From 30017854ddecd0cd0a1046fcadcbf0acc4f97337 Mon Sep 17 00:00:00 2001
From: Jonathan Piacenti <kelketek@gmail.com>
Date: Thu, 1 Jan 2015 16:17:05 +0000
Subject: [PATCH] Refactored JS and Python classes for better code reuse.

---
 poll/poll.py                 | 61 +++++++++++++++++++++++++++++++++++++------------------------
 poll/public/html/survey.html |  1 +
 poll/public/js/poll.js       | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
 3 files changed, 89 insertions(+), 56 deletions(-)

diff --git a/poll/poll.py b/poll/poll.py
index 48e6071..a68dd97 100644
--- a/poll/poll.py
+++ b/poll/poll.py
@@ -35,7 +35,35 @@ class ResourceMixin(object):
         return frag
 
 
-class PollBlock(XBlock, ResourceMixin, PublishEventMixin):
+class PollBase(XBlock, ResourceMixin, PublishEventMixin):
+    """
+    Base class for Poll-like XBlocks.
+    """
+    event_namespace = 'xblock.pollbase'
+
+    @XBlock.json_handler
+    def load_answers(self, data, suffix=''):
+        return {
+            'answers': [
+                {
+                    'key': key, 'text': value['label'], 'img': value['img']
+                }
+                for key, value in self.answers
+            ]
+        }
+
+    @XBlock.json_handler
+    def get_results(self, data, suffix=''):
+        self.publish_event_from_dict(self.event_namespace + '.view_results', {})
+        detail, total = self.tally_detail()
+        return {
+            'question': markdown(self.question), 'tally': detail,
+            'total': total, 'feedback': markdown(self.feedback),
+            'plural': total > 1,
+        }
+
+
+class PollBlock(PollBase):
     """
     Poll XBlock. Allows a teacher to poll users, and presents the results so
     far of the poll to the user when finished.
@@ -54,16 +82,7 @@ class PollBlock(XBlock, ResourceMixin, PublishEventMixin):
                  scope=Scope.user_state_summary,
                  help="Total tally of answers from students.")
     choice = String(scope=Scope.user_state, help="The student's answer")
-
-    @XBlock.json_handler
-    def get_results(self, data, suffix=''):
-        self.publish_event_from_dict('xblock.poll.view_results', {})
-        detail, total = self.tally_detail()
-        return {
-            'question': markdown(self.question), 'tally': detail,
-            'total': total, 'feedback': markdown(self.feedback),
-            'plural': total > 1,
-        }
+    event_namespace = 'xblock.poll'
 
     def clean_tally(self):
         """
@@ -173,17 +192,6 @@ class PollBlock(XBlock, ResourceMixin, PublishEventMixin):
             context, "public/html/poll.html", "public/css/poll.css",
             "public/js/poll.js", "PollBlock")
 
-    @XBlock.json_handler
-    def load_answers(self, data, suffix=''):
-        return {
-            'answers': [
-                {
-                    'key': key, 'text': value['label'], 'img': value['img']
-                }
-                for key, value in self.answers
-            ]
-        }
-
     def studio_view(self, context=None):
         if not context:
             context = {}
@@ -321,7 +329,7 @@ class PollBlock(XBlock, ResourceMixin, PublishEventMixin):
         ]
 
 
-class SurveyBlock(XBlock, ResourceMixin, PublishEventMixin):
+class SurveyBlock(PollBase):
     display_name = String(default='Survey')
     answers = List(
         default=(
@@ -345,6 +353,7 @@ class SurveyBlock(XBlock, ResourceMixin, PublishEventMixin):
         help="Total tally of answers from students."
     )
     choices = Dict(help="The user's answers")
+    event_namespace = 'xblock.survey'
 
     def student_view(self, context=None):
         """
@@ -354,10 +363,14 @@ class SurveyBlock(XBlock, ResourceMixin, PublishEventMixin):
         if not context:
             context = {}
 
+        js_template = self.resource_string(
+            '/public/handlebars/poll_results.handlebars')
+
         context.update({
             'choices': self.choices,
             # Offset so choices will always be True.
             'answers': self.answers,
+            'js_template': js_template,
             'questions': self.questions,
             # Mustache is treating an empty string as true.
             'feedback': markdown(self.feedback) or False,
@@ -367,7 +380,7 @@ class SurveyBlock(XBlock, ResourceMixin, PublishEventMixin):
 
         return self.create_fragment(
             context, "public/html/survey.html", "public/css/poll.css",
-            "public/js/poll.js", "PollBlock")
+            "public/js/poll.js", "SurveyBlock")
 
     @staticmethod
     def workbench_scenarios():
diff --git a/poll/public/html/survey.html b/poll/public/html/survey.html
index c84768c..972246c 100644
--- a/poll/public/html/survey.html
+++ b/poll/public/html/survey.html
@@ -1,3 +1,4 @@
+{{ js_template|safe }}
 <div class="survey-block">
     {# If no form is present, the Javascript will load the results instead. #}
     {% if not choices %}
diff --git a/poll/public/js/poll.js b/poll/public/js/poll.js
index a17f846..10c9fb1 100644
--- a/poll/public/js/poll.js
+++ b/poll/public/js/poll.js
@@ -1,70 +1,89 @@
 /* Javascript for PollBlock. */
 
-var PollUtil = {
+function PollUtil (runtime, element) {
 
-    init: function(runtime, element) {
+    this.init = function(runtime, element) {
         this.voteUrl = runtime.handlerUrl(element, 'vote');
         this.tallyURL = runtime.handlerUrl(element, 'get_results');
         this.element = element;
         this.runtime = runtime;
         this.submit = $('input[type=button]', element);
+        this.answers = $('input[type=radio]', element);
         this.resultsTemplate = Handlebars.compile($("#poll-results-template", element).html());
-    },
+    };
 
-    poll_init: function(){
+    this.pollInit = function(){
         // If the submit button doesn't exist, the user has already
         // selected a choice.
         var self = this;
+        var enableSubmit = self.enableSubmit();
+        var getResults = self.getResults();
         if (self.submit.length) {
             var radio = $('input[name=choice]:checked', self.element);
-            self.submit.click(function (event) {
+            self.submit.click(function () {
                 // Refresh.
-                radio = $(radio.selector, element);
+                radio = $(radio.selector, self.element);
                 var choice = radio.val();
                 $.ajax({
                     type: "POST",
                     url: self.voteUrl,
                     data: JSON.stringify({"choice": choice}),
-                    success: self.getResults
+                    success: getResults
                 });
             });
             // If the user has refreshed the page, they may still have an answer
             // selected and the submit button should be enabled.
             var answers = $('input[type=radio]', self.element);
             if (! radio.val()) {
-                answers.bind("change.EnableSubmit", self.enableSubmit);
+                answers.bind("change.EnableSubmit", enableSubmit);
             } else {
-                self.enableSubmit();
+                enableSubmit();
             }
         } else {
-            self.getResults({'success': true});
+            getResults({'success': true});
         }
-    },
+    };
 
-    getResults: function(data) {
+    this.surveyInit = function () {
+
+    };
+
+    this.getResults = function () {
         var self = this;
-        if (! data['success']) {
-            alert(data['errors'].join('\n'));
-        }
-        $.ajax({
-            // Semantically, this would be better as GET, but we can use helper
-            // functions with POST.
-            type: "POST",
-            url: self.tallyURL,
-            data: JSON.stringify({}),
-            success: function (data) {
-                $('div.poll-block', self.element).html(self.resultsTemplate(data));
+        return function(data) {
+            if (!data['success']) {
+                alert(data['errors'].join('\n'));
             }
-        })
-    },
+            $.ajax({
+                // Semantically, this would be better as GET, but we can use helper
+                // functions with POST.
+                type: "POST",
+                url: self.tallyURL,
+                data: JSON.stringify({}),
+                success: function (data) {
+                    console.log(self);
+                    $('div.poll-block', self.element).html(self.resultsTemplate(data));
+                }
+            })
+        }
+    };
 
-    enableSubmit: function () {
-        this.submit.removeAttr("disabled");
-        this.answers.unbind("change.EnableSubmit");
-    }
-};
+    this.enableSubmit = function () {
+        var self = this;
+        return function () {
+            self.submit.removeAttr("disabled");
+            self.answers.unbind("change.EnableSubmit");
+        }
+    };
+    this.init(runtime, element);
+}
 
 function PollBlock(runtime, element) {
-    PollUtil.init(runtime, element);
-    PollUtil.poll_init();
+    var util = new PollUtil(runtime, element);
+    util.pollInit();
+}
+
+function SurveyBlock(runtime, element) {
+    var util = new PollUtil(runtime, element);
+    util.surveyInit();
 }
--
libgit2 0.26.0