Keyword on note page
authorCharles Connell <charles@connells.org>
Tue, 8 Apr 2014 22:29:23 +0000 (18:29 -0400)
committerCharles Connell <charles@connells.org>
Tue, 8 Apr 2014 22:29:23 +0000 (18:29 -0400)
karmaworld/apps/notes/views.py
karmaworld/assets/css/note_course_pages.css
karmaworld/assets/js/note-detail.js
karmaworld/settings/dev.py
karmaworld/templates/notes/note_detail.html

index b9be9b55818df930ad38342662d12b7bc40359b8..8c62087dd7e7e445312336b3d8b241d1f4471d2a 100644 (file)
@@ -2,21 +2,19 @@
 # -*- coding:utf8 -*-
 # Copyright (C) 2012  FinalsClub Foundation
 
-import json
 import traceback
 import logging
 
 from django.core import serializers
-from django.core.exceptions import ObjectDoesNotExist
+from django.forms.formsets import formset_factory
 from karmaworld.apps.courses.models import Course
 from karmaworld.apps.notes.search import SearchIndex
+from karmaworld.apps.quizzes.forms import KeywordForm
+from karmaworld.apps.quizzes.models import Keyword
 from karmaworld.apps.users.models import NoteKarmaEvent
 from karmaworld.utils.ajax_utils import *
 
-import os
-
-from django.conf import settings
-from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound
+from django.http import HttpResponse, HttpResponseBadRequest
 from django.views.generic import DetailView, ListView
 from django.views.generic import FormView
 from django.views.generic import View
@@ -38,11 +36,30 @@ class NoteDetailView(DetailView):
     """ Class-based view for the note html page """
     model = Note
     context_object_name = u"note" # name passed to template
+    keyword_form_class = formset_factory(KeywordForm)
+
+    def post(self, requests, *args, **kwargs):
+        formset = self.keyword_form_class(requests)
+        if formset.is_valid():
+            self.keyword_form_valid(formset)
+            self.keyword_formset = self.keyword_form_class(initial=self.get_initial_keywords())
+            return super(NoteDetailView, self).post(requests, *args, **kwargs)
+        else:
+            self.keyword_formset = formset
+            return super(NoteDetailView, self).post(requests, *args, **kwargs)
+
+    def get(self, request, *args, **kwargs):
+        self.keyword_formset = self.keyword_form_class(initial=self.get_initial_keywords())
+        return super(NoteDetailView, self).get(request, *args, **kwargs)
 
     def get_context_data(self, **kwargs):
         """ Generate custom context for the page rendering a Note
             + if pdf, set the `pdf` flag
         """
+
+        kwargs['keyword_prototype_form'] = KeywordForm
+        kwargs['keyword_formset'] = self.keyword_formset
+
         if self.object.is_pdf():
             kwargs['pdf_controls'] = True
 
@@ -61,6 +78,29 @@ class NoteDetailView(DetailView):
 
         return super(NoteDetailView, self).get_context_data(**kwargs)
 
+    def get_initial_keywords(self):
+        existing_keywords = self.get_object().keyword_set.order_by('id')
+        initial_data = [{'keyword': keyword.word, 'definition': keyword.definition, 'id': keyword.pk}
+                        for keyword in existing_keywords]
+        return initial_data
+
+    def keyword_form_valid(self, formset):
+        for form in formset:
+            word = form['keyword'].data
+            definition = form['definition'].data
+            id = form['id'].data
+            if word == '':
+                continue
+            try:
+                keyword_object = Keyword.objects.get(id=id)
+            except (ValueError, ObjectDoesNotExist):
+                keyword_object = Keyword()
+
+            keyword_object.note = self.note
+            keyword_object.word = word
+            keyword_object.definition = definition
+            keyword_object.save()
+
 
 class NoteSaveView(FormView, SingleObjectMixin):
     """ Save a Note and then view the page, 
index 83328423b03dbc73898e09b9fa50f1d79773318d..1b0ab22f3fa719eb01fda3d3a285757b39a9f8f7 100644 (file)
@@ -101,4 +101,8 @@ div.header-title-row {
 #minus-btn,
 #plus-btn {
   cursor: pointer;
+}
+
+.keyword-form-row textarea.definition {
+  max-height: 75px;
 }
\ No newline at end of file
index 16ec9118b7a05afa55e5d09242d76feaef003775..b150f56b243f918166c4d9a4de3d5fbbdcc4d76f 100644 (file)
@@ -91,6 +91,48 @@ function injectRemoteCSS(url, noteframe) {
   noteframe.document.head.appendChild(injectCSS);
 }
 
+function tabHandler(event) {
+  // check for:
+  // key pressed was TAB
+  // key was pressed in last row
+  if (event.which == 9) {
+    var totalForms = parseInt($('#id_form-TOTAL_FORMS').attr('value'));
+    var formIndex = parseInt($(this).closest('div.keyword-form-row').data('index'));
+    if (formIndex === totalForms-1) {
+      addForm(event);
+      event.preventDefault();
+    }
+  }
+}
+
+function addForm(event) {
+  var prototypeForm = $('#keyword-form-prototype div.keyword-form-row').clone().appendTo('#keyword-form-rows');
+  var newForm = $('.keyword-form-row:last');
+  var totalForms = $('#id_form-TOTAL_FORMS').attr('value');
+  var newIdRoot = 'id_form-' + totalForms + '-';
+  var newNameRoot = 'form-' + totalForms + '-';
+
+  newForm.data('index', totalForms);
+
+  var keywordInput = newForm.find('.keyword');
+  keywordInput.attr('id', newIdRoot + 'keyword');
+  keywordInput.attr('name', newNameRoot + 'keyword');
+  keywordInput.focus();
+
+  var definitionInput = newForm.find('.definition');
+  definitionInput.attr('id', newIdRoot + 'definition');
+  definitionInput.attr('name', newNameRoot + 'definition');
+  definitionInput.keydown(tabHandler);
+
+  var objectIdInput = newForm.find('.object-id');
+  objectIdInput.attr('id', newIdRoot + 'id');
+  objectIdInput.attr('name', newNameRoot + 'id');
+
+  $('#id_form-TOTAL_FORMS').attr('value', parseInt(totalForms)+1);
+
+  keywordInput.focus();
+}
+
 $(function() {
 
   $("#thank-button").click(function(event) {
@@ -224,6 +266,9 @@ $(function() {
     });
   }
 
-
+  $('.definition').keydown(tabHandler);
+  $('#add-row-btn').click(addForm);
 
 });
+
+
index 70dccca7da91a86766ab8e7683ff5d46d968136a..646caccf77bbbede9555238ebc3fceb6aae64745 100644 (file)
@@ -73,6 +73,7 @@ AWS_HEADERS = {
 ########## TOOLBAR CONFIGURATION
 # See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation
 INSTALLED_APPS += (
+    'debug_toolbar',
     'django_extensions',
     'django_nose',
 )
@@ -82,6 +83,7 @@ INTERNAL_IPS = ('127.0.0.1',)
 
 # See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation
 MIDDLEWARE_CLASSES += (
+    'debug_toolbar.middleware.DebugToolbarMiddleware',
 )
 
 
index 1e8db7d7957170731d87472b540ed020f0bb034f..785d5359e6c7139b63afc0e2c9e1f6e95061a890 100644 (file)
       <div id="tabs" class="small-12 columns">
         <dl class="tabs show-for-large-up" data-tab>
           <dd class="active"><a href="#note_container">Note</a></dd>
+          <dd><a href="#keywords">Keywords</a></dd>
         </dl>
         <div class="tabs-content">
           <div id="note_container" class="content active">
                 {% endif %} {# note.static_html #}
               </div><!-- /body_copy -->
             </div>
+          </div><!-- /note_container -->
+
+          <div id="keywords" class="content">
+            <div class="row">
+              <div class="small-12 columns">
+                <form id="keyword-form" action="{% url 'keyword_edit' note.slug %}" method="post">
+                  {% csrf_token %}
+                  {{ keyword_formset.management_form }}
+                  <div class="hide" id="keyword-form-prototype">
+                    <div class="row keyword-form-row">
+                      <div class="small-12 large-4 columns">
+                        {{ keyword_prototype_form.keyword }}
+                      </div>
+                      <div class="small-12 large-8 columns">
+                        {{ keyword_prototype_form.definition }}
+                        {{ keyword_prototype_form.id }}
+                      </div>
+                    </div>
+                    <hr class="hide-for-large-up" />
+                  </div>
+                  <div id="keyword-form-rows">
+                    {% for form_row in keyword_formset %}
+                      <div class="row keyword-form-row" data-index="{{ forloop.counter0 }}">
+                        <div class="small-12 large-4 columns">
+                          {{ form_row.keyword }}
+                        </div>
+                        <div class="small-12 large-8 columns">
+                          {{ form_row.definition }}
+                          {{ form_row.id }}
+                        </div>
+                      </div>
+                      <hr class="hide-for-large-up" />
+                    {% endfor %}
+                  </div>
+                  <div id="row">
+                    <div class="small-1 columns">
+                      <i id="add-row-btn" class="fa fa-plus fa-2x"></i>
+                    </div>
+                    <div class="small-10 large-11 columns center">
+                      <button type="submit" name="action">Save</button>
+                    </div>
+                  </div>
+                </form>
+              </div>
+            </div>
           </div>
-        </div><!-- /note_container -->
+        </div>
       </div>
     </div>