Commit 5f8d9c03 by Xavier Antoviaque

Factor out part of MCQBlock into QuestionnaireAbstractBlock

parent b5632bef
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 Harvard
......@@ -25,11 +26,9 @@
import logging
from xblock.fragment import Fragment
from .choice import ChoiceBlock
from .tip import TipBlock
from .light_children import LightChild, Scope, String
from .light_children import Scope, String
from .questionnaire import QuestionnaireAbstractBlock
from .utils import render_template
......@@ -40,59 +39,16 @@ log = logging.getLogger(__name__)
# Classes ###########################################################
class MCQBlock(LightChild):
class MCQBlock(QuestionnaireAbstractBlock):
"""
An XBlock used to ask multiple-choice questions
Must be a child of a MentoringBlock. Allow to display a tip/advice depending on the
values entered by the student, and supports multiple types of multiple-choice
set, with preset choices and author-defined values.
"""
question = String(help="Question to ask the student", scope=Scope.content, default="")
type = String(help="Type of MCQ", scope=Scope.content, default="choices")
student_choice = String(help="Last input submitted by the student", default="", scope=Scope.user_state)
low = String(help="Label for low ratings", scope=Scope.content, default="Less")
high = String(help="Label for high ratings", scope=Scope.content, default="More")
@classmethod
def init_block_from_node(cls, block, node, attr):
block.light_children = []
for child_id, xml_child in enumerate(node):
if xml_child.tag == "question":
block.question = xml_child.text
else:
cls.add_node_as_child(block, xml_child, child_id)
for name, value in attr:
setattr(block, name, value)
return block
def mentoring_view(self, context=None):
if str(self.type) not in ('rating', 'choices'):
raise ValueError, u'Invalid value for MCQBlock.type: `{}`'.format(self.type)
template_path = 'templates/html/mcq_{}.html'.format(self.type)
html = render_template(template_path, {
'self': self,
'custom_choices': self.custom_choices,
})
fragment = Fragment(html)
fragment.add_css_url(self.runtime.local_resource_url(self.xblock_container,
'public/css/mcq.css'))
fragment.add_javascript_url(self.runtime.local_resource_url(self.xblock_container,
'public/js/mcq.js'))
fragment.initialize_js('MCQBlock')
return fragment
@property
def custom_choices(self):
custom_choices = []
for child in self.get_children_objects():
if isinstance(child, ChoiceBlock):
custom_choices.append(child)
return custom_choices
valid_types = ('rating', 'choices')
def submit(self, submission):
log.debug(u'Received MCQ submission: "%s"', submission)
......@@ -100,7 +56,6 @@ class MCQBlock(LightChild):
completed = True
tips_fragments = []
for tip in self.get_tips():
log.warn(tip)
completed = completed and tip.is_completed(submission)
if tip.is_tip_displayed(submission):
tips_fragments.append(tip.render(submission))
......@@ -130,12 +85,3 @@ class MCQBlock(LightChild):
return choice.content
return submission
def get_tips(self):
"""
Returns the tips contained in this block
"""
tips = []
for child in self.get_children_objects():
if isinstance(child, TipBlock):
tips.append(child)
return tips
function MCQBlock(runtime, element) {
function QuestionnaireBlock(runtime, element) {
return {
submit: function() {
var checkedRadio = $('input[type=radio]:checked', element);
if(checkedRadio.length) {
return checkedRadio.val();
} else {
return null;
}
},
handleSubmit: function(result) {
var tipsDom = $(element).parent().find('.messages'),
tipHtml = (result || {}).tips || '';
......@@ -19,3 +10,19 @@ function MCQBlock(runtime, element) {
}
}
}
function MCQBlock(runtime, element) {
var init = QuestionnaireBlock(runtime, element);
init.submit = function() {
var checkedRadio = $('input[type=radio]:checked', element);
if(checkedRadio.length) {
return checkedRadio.val();
} else {
return null;
}
};
return init;
}
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 Harvard
#
# Authors:
# Xavier Antoviaque <xavier@antoviaque.org>
#
# This software's license gives you freedom; you can copy, convey,
# propagate, redistribute and/or modify this program under the terms of
# the GNU Affero General Public License (AGPL) as published by the Free
# Software Foundation (FSF), either version 3 of the License, or (at your
# option) any later version of the AGPL published by the FSF.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
# General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program in a file in the toplevel directory called
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
#
# Imports ###########################################################
import logging
from xblock.fragment import Fragment
from .choice import ChoiceBlock
from .light_children import LightChild, Scope, String
from .tip import TipBlock
from .utils import render_template
# Globals ###########################################################
log = logging.getLogger(__name__)
# Classes ###########################################################
class QuestionnaireAbstractBlock(LightChild):
"""
An abstract class used for MCQ/MRQ blocks
Must be a child of a MentoringBlock. Allow to display a tip/advice depending on the
values entered by the student, and supports multiple types of multiple-choice
set, with preset choices and author-defined values.
"""
question = String(help="Question to ask the student", scope=Scope.content, default="")
@classmethod
def init_block_from_node(cls, block, node, attr):
block.light_children = []
for child_id, xml_child in enumerate(node):
if xml_child.tag == "question":
block.question = xml_child.text
else:
cls.add_node_as_child(block, xml_child, child_id)
for name, value in attr:
setattr(block, name, value)
return block
def mentoring_view(self, context=None):
name = self.__class__.__name__
if str(self.type) not in self.valid_types:
raise ValueError, u'Invalid value for {}.type: `{}`'.format(name, self.type)
template_path = 'templates/html/{}_{}.html'.format(name.lower(), self.type)
html = render_template(template_path, {
'self': self,
'custom_choices': self.custom_choices,
})
fragment = Fragment(html)
fragment.add_css_url(self.runtime.local_resource_url(self.xblock_container,
'public/css/questionnaire.css'))
fragment.add_javascript_url(self.runtime.local_resource_url(self.xblock_container,
'public/js/questionnaire.js'))
fragment.initialize_js('QuestionnaireBlock')
return fragment
@property
def custom_choices(self):
custom_choices = []
for child in self.get_children_objects():
if isinstance(child, ChoiceBlock):
custom_choices.append(child)
return custom_choices
def get_tips(self):
"""
Returns the tips contained in this block
"""
tips = []
for child in self.get_children_objects():
if isinstance(child, TipBlock):
tips.append(child)
return tips
<fieldset class="yes-maybenot-understand">
<legend>{{ self.question }}</legend>
<div class="choices">
<span class="choice">
<label><input type="radio" name="{{ self.name }}" value="yes"{% if self.student_choice == 'yes' %} checked{% endif %}> Yes</label>
</span>
<span class="choice">
<label><input type="radio" name="{{ self.name }}" value="maybenot"{% if self.student_choice == 'maybenot' %} checked{% endif %}> Maybe not</label>
</span>
<span class="choice">
<label><input type="radio" name="{{ self.name }}" value="understand"{% if self.student_choice == 'understand' %} checked{% endif %}> I don't understand</label>
</span>
</div>
</fieldset>
......@@ -89,5 +89,4 @@ class TipBlock(LightChild):
@property
def reject_with_defaults(self):
reject = commas_to_list(self.reject)
log.debug(reject)
return reject or []
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