Commit 664c851a by Xavier Antoviaque

Merge pull request #9 from aboudreault/answer-min-characters

Answer min characters
parents 4a635709 7f3186cd
......@@ -29,7 +29,7 @@ from lazy import lazy
from xblock.fragment import Fragment
from .light_children import LightChild, Boolean, Scope, String
from .light_children import LightChild, Boolean, Scope, String, Integer
from .models import Answer
from .utils import render_template
......@@ -51,6 +51,8 @@ class AnswerBlock(LightChild):
read_only = Boolean(help="Display as a read-only field", default=False, scope=Scope.content)
default_from = String(help="If specified, the name of the answer to get the default value from",
default=None, scope=Scope.content)
min_characters = Integer(help="Minimum number of characters allowed for the answer",
default=0, scope=Scope.content)
@lazy
def student_input(self):
......@@ -106,7 +108,11 @@ class AnswerBlock(LightChild):
@property
def completed(self):
return bool(self.read_only or self.student_input)
answer_length_ok = self.student_input
if self.min_characters > 0:
answer_length_ok = len(self.student_input.strip()) >= self.min_characters
return bool(self.read_only or answer_length_ok)
def save(self):
"""
......
......@@ -43,8 +43,10 @@ class MRQBlock(QuestionnaireAbstractBlock):
An XBlock used to ask multiple-response questions
"""
student_choices = List(help="Last submissions by the student", default=[], scope=Scope.user_state)
max_attempts = Integer(help="Number of max attempts for this questions", scope=Scope.content)
num_attempts = Integer(help="Number of attempts a user has answered for this questions", scope=Scope.user_state)
max_attempts = Integer(help="Number of max attempts for this questions", default=0,
scope=Scope.content)
num_attempts = Integer(help="Number of attempts a user has answered for this questions",
default=0, scope=Scope.user_state)
# TODO REMOVE THIS, ONLY NEEDED FOR LIGHTCHILDREN
@classmethod
......
function AnswerBlock(runtime, element) {
return {
init: function(options) {
// register the child validator
$(':input', element).on('keyup', options.blockValidator);
},
submit: function() {
return $(element).find(':input').serializeArray();
return $(':input', element).serializeArray();
},
handleSubmit: function(result) {
$(element).find('.message').text((result || {}).error || '');
},
// Returns `true` if the child is valid, else `false`
validate: function() {
var input = $(':input', element),
input_value = input.val().replace(/^\s+|\s+$/gm,''),
answer_length = input_value.length,
data = input.data();
// an answer cannot be empty event if min_characters is 0
if (_.isNumber(data.min_characters)) {
var min_characters = _.max([data.min_characters, 1]);
if (answer_length < min_characters) {
return false;
}
}
return true;
}
}
}
......@@ -77,6 +77,7 @@ function MentoringBlock(runtime, element) {
var submit_dom = $(element).find('.submit .input-main');
submit_dom.bind('click', function() {
var success = true;
var data = {};
var children = getChildren(element);
for (var i = 0; i < children.length; i++) {
......@@ -91,10 +92,15 @@ function MentoringBlock(runtime, element) {
// init children (especially mrq blocks)
var children = getChildren(element);
var options = {
blockValidator: validateXBlock
};
_.each(children, function(child) {
callIfExists(child, 'init');
callIfExists(child, 'init', options);
});
validateXBlock();
if (submit_dom.length) {
renderProgress();
}
......@@ -112,6 +118,31 @@ function MentoringBlock(runtime, element) {
$.post(handlerUrl, '{}').success(handleRefreshResults);
}
// validate all children
function validateXBlock() {
var submit_dom = $(element).find('.submit .input-main');
var children_are_valid = true;
var data = {};
var children = getChildren(element);
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.name !== undefined) {
var child_validation = callIfExists(child, 'validate');
if (_.isBoolean(child_validation)) {
children_are_valid = children_are_valid && child_validation
}
}
}
if (!children_are_valid) {
submit_dom.attr('disabled','disabled');
}
else {
submit_dom.removeAttr("disabled");
}
}
// We need to manually refresh, XBlocks are currently loaded together with the section
refreshXBlock(element);
}
<textarea class="answer editable" cols="50" rows="10" name="input">{{ self.student_input }}</textarea>
<textarea
class="answer editable" cols="50" rows="10" name="input"
data-min_characters="{{ self.min_characters }}"
>{{ self.student_input }}</textarea>
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