Commit 30017854 by Jonathan Piacenti

Refactored JS and Python classes for better code reuse.

parent 7fc0f64f
......@@ -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():
......
{{ js_template|safe }}
<div class="survey-block">
{# If no form is present, the Javascript will load the results instead. #}
{% if not choices %}
......
/* 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();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment