Autocomplete instructor names, take users to existing courses, be stricter about...
authorCharles Connell <charles@connells.org>
Sun, 15 Dec 2013 22:03:07 +0000 (17:03 -0500)
committerCharles Connell <charles@connells.org>
Sun, 15 Dec 2013 22:03:07 +0000 (17:03 -0500)
karmaworld/apps/courses/views.py
karmaworld/assets/css/global.css
karmaworld/assets/js/add-course.js
karmaworld/templates/partial/add_course.html
karmaworld/urls.py

index ab2c57e0e9e4b0a5f704867751e478921e8a54b3..18f27fee60368147ac430e3f0b10eae85c05fa75 100644 (file)
@@ -117,19 +117,66 @@ def school_course_list(request):
         try:
           _school_id = int(request.POST['school_id'])
         except:
-          return HttpResponseNotFound(json.dumps({'status': 'fail', 'message':'could not convert school id to integer'}), mimetype="application/json")
+          return HttpResponseNotFound(json.dumps({'status': 'fail',
+                                                  'message': 'could not convert school id to integer'}),
+                                      mimetype="application/json")
 
         # Look up the school
         try:
             school = School.objects.get(id__exact=_school_id)
         except (MultipleObjectsReturned, ObjectDoesNotExist):
-            return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': 'school id did not match exactly one school'}), mimetype="application/json")
+            return HttpResponseNotFound(json.dumps({'status': 'fail',
+                                                    'message': 'school id did not match exactly one school'}),
+                                        mimetype="application/json")
 
+        # Look up matching courses
         _courses = Course.objects.filter(school__exact=school.id, name__icontains=_query)
         courses = [{'name': c.name} for c in _courses]
 
         # return as json
-        return HttpResponse(json.dumps({'status':'success', 'courses': courses}), mimetype="application/json")
+        return HttpResponse(json.dumps({'status':'success', 'courses': courses}),
+                            mimetype="application/json")
     else:
         # else return that the api call failed
-        return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': 'query parameters missing'}), mimetype="application/json")
+        return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': 'query parameters missing'}),
+                                    mimetype="application/json")
+
+def school_course_instructor_list(request):
+    """Return JSON describing instructors we know of at the given school
+       teaching the given course
+       that match the query """
+    if request.method == 'POST' and request.is_ajax() \
+                        and request.POST.has_key('q')\
+                        and request.POST.has_key('course_name')\
+                        and request.POST.has_key('school_id'):
+
+        _query = request.POST['q']
+        _course_name = request.POST['course_name']
+        try:
+          _school_id = int(request.POST['school_id'])
+        except:
+          return HttpResponseNotFound(json.dumps({'status': 'fail',
+                                                  'message':'could not convert school id to integer'}),
+                                      mimetype="application/json")
+
+        # Look up the school
+        try:
+            school = School.objects.get(id__exact=_school_id)
+        except (MultipleObjectsReturned, ObjectDoesNotExist):
+            return HttpResponseNotFound(json.dumps({'status': 'fail',
+                                                    'message': 'school id did not match exactly one school'}),
+                                        mimetype="application/json")
+
+        # Look up matching courses
+        _courses = Course.objects.filter(school__exact=school.id,
+                                         name__exact=_course_name,
+                                         instructor_name__icontains=_query)
+        instructors = [{'name': c.instructor_name, 'url': c.get_absolute_url()} for c in _courses]
+
+        # return as json
+        return HttpResponse(json.dumps({'status':'success', 'instructors': instructors}),
+                            mimetype="application/json")
+    else:
+        # else return that the api call failed
+        return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': 'query parameters missing'}),
+                                    mimetype="application/json")
index b5d5dceb4f1c6352244017589fbc0e616c58d8dc..355ab0167b578856f8327fa0cd1d64364f08c272 100644 (file)
@@ -532,6 +532,7 @@ a.activity_target:hover
 .add-note-btn,
 #add-note-btn,
 #add-course-btn,
+#existing-course-btn,
 #save-btn
 {
   border: none;
@@ -545,10 +546,12 @@ a.activity_target:hover
   /* transition: ease-out ? ? ? */
 }
 
+#existing-course-btn,
 #save-btn {
   margin-top: 13px;
 }
 
+#existing-course-btn.disabled,
 #save-btn.disabled
 {
   color: #afafaf;
index f9f0e07c6b34c2cf9c91cbaae84e4802cba525cd..d46e1f6e216e05bf6cd96dc01c901fc473fc0445 100644 (file)
@@ -1,7 +1,22 @@
 // Setup all the javascript stuff we need for the various
 // incarnations of the Add Course form
+
 $(function() {
 
+  var schoolSelected = false;
+  var courseNameSelected = false;
+  var instructorSelected = false;
+
+  function fieldEdited() {
+    if (schoolSelected && courseNameSelected && instructorSelected) {
+      $('#save-btn').hide();
+      $('#existing-course-msg').show();
+    } else {
+      $('#save-btn').show();
+      $('#existing-course-msg').hide();
+    }
+  }
+
   // Set up the "Add Course" button at bottom
   // of page
   $('#add-course-btn').click(function() {
@@ -52,7 +67,6 @@ $(function() {
         url: json_school_list,
         data: {q: request.term},
         success: function(data) {
-          console.log(data);
           if (data['status'] === 'success') {
             response($.map(data['schools'], function(item) {
               return {
@@ -70,31 +84,33 @@ $(function() {
         type: 'POST'
       });
     },
-    select: function(event, ui) { 
-      console.log("select func");
-      console.log("id");
-      console.log(ui.item.value);
-      console.log("name");
-      console.log(ui.item.label);
-      // don't let the user edit the field anymore
-      //$('#str_school').attr('readonly', true);
-
+    select: function(event, ui) {
       // set the school id as the value of the hidden field
       $('#id_school').val(ui.item.real_value);
-      // set the School name as the textbox field
-      //$('#str_school').val(ui.item.label);
+      schoolSelected = true;
+      $('#str_school').removeClass('error');
+      $('#save-btn').removeClass('disabled');
+      fieldEdited();
+    },
+    change: function(event, ui) {
+      if (ui.item == null) {
+        $('#id_school').val('');
+        schoolSelected = false;
+        $('#str_school').addClass('error');
+        $('#save-btn').addClass('disabled');
+        fieldEdited();
+      }
     },
     minLength: 3
   });
 
   $("#id_name").autocomplete({
     source: function(request, response){
-      var school_id = $('#id_school').val()
+      var school_id = $('#id_school').val();
       $.ajax({
         url: json_school_course_list,
         data: {q: request.term, school_id: school_id},
         success: function(data) {
-          console.log(data);
           if (data['status'] === 'success') {
             response($.map(data['courses'], function(item) {
               return {
@@ -102,14 +118,60 @@ $(function() {
                   label: item.name,
               };
             }));
-          } else {
-            // FIXME: do something?
           }
         },
         dataType: "json",
         type: 'POST'
       });
     },
+    select: function(event, ui) {
+      courseNameSelected = true;
+      fieldEdited();
+    },
+    change: function(event, ui) {
+      if (ui.item == null) {
+        courseNameSelected = false;
+        fieldEdited();
+      }
+    },
+    minLength: 3
+  });
+
+  $("#id_instructor_name").autocomplete({
+    source: function(request, response) {
+      var school_id = $('#id_school').val();
+      var course_name = $('#id_name').val();
+      $.ajax({
+        url: json_school_course_instructor_list,
+        data: {q: request.term, school_id: school_id, course_name: course_name},
+        success: function(data) {
+          if (data['status'] === 'success') {
+            // Fill in the autocomplete entries
+            response($.map(data['instructors'], function(item) {
+              return {
+                  value: item.name,
+                  label: item.name,
+                  url:   item.url
+              };
+            }));
+          }
+        },
+        dataType: "json",
+        type: 'POST'
+      });
+    },
+    select: function(event, ui) {
+      instructorSelected = true;
+      $('#existing-course-btn').attr('href', ui.item.url);
+      fieldEdited();
+    },
+    change: function(event, ui) {
+      if (ui.item == null) {
+        instructorSelected = false;
+        $('#existing-course-btn').attr('href', '');
+        fieldEdited();
+      }
+    },
     minLength: 3
   });
 
index ea0c366499630b8d9a69f26330dc80729ae29f1b..efa6d9826ec7746bda305f99c3feb10d23c08e99 100644 (file)
@@ -2,6 +2,7 @@
 <script>
   var json_school_list = "{% url 'json_school_list' %}"
   var json_school_course_list = "{% url 'json_school_course_list' %}"
+  var json_school_course_instructor_list = "{% url 'json_school_course_instructor_list' %}"
   var csrf_token = "{{ csrf_token }}";
 </script>
 <script src="{{ STATIC_URL }}js/add-course.js"></script>
     </div> <!-- .row -->
 
     <div class="row">
-      <div class="small-4 columns small-centered">
-        <button id="save-btn">
-          <i class=icon-save></i> Save
-        </div>
+      <div class="small-4 large-8 columns small-centered text-center">
+        <button id="save-btn" class="disabled">
+          <i class="icon-save"></i> Save
+        </button>
+        <span id="existing-course-msg" class="hide">
+          Looks like this course already exists on KarmaNotes!
+          <a id="existing-course-btn" class="button">Go To Existing Course <i class="icon-arrow-right"></i></a></span>
       </div>
     </div>
 
index f69edd0c5641eff95faf3f0715d5862511e16f62..fe9ba61aa6493a0e8c9e63cb933a7a2ad1bfffdb 100644 (file)
@@ -15,6 +15,7 @@ from karmaworld.apps.courses.views import CourseDetailView
 from karmaworld.apps.courses.views import CourseListView
 from karmaworld.apps.courses.views import school_list
 from karmaworld.apps.courses.views import school_course_list
+from karmaworld.apps.courses.views import school_course_instructor_list
 from karmaworld.apps.notes.views import NoteView
 from karmaworld.apps.notes.views import RawNoteDetailView
 from karmaworld.apps.notes.views import PDFView
@@ -91,6 +92,8 @@ urlpatterns = patterns('',
     url(r'^school/list/$', school_list, name='json_school_list'),
     # return json list of courses for a given school
     url(r'^school/course/list/$', school_course_list, name='json_school_course_list'),
+    # return json list of instructors for a given school and course
+    url(r'^school/course/instructors/list/$', school_course_instructor_list, name='json_school_course_instructor_list'),
     # ---- end JSON views ----#
 
     url(r'^$', CourseListView.as_view(model=Course), name='home'),