Commit 0d4a06ac by Tim Krones

Address upstream review comments.

parent d2a9f6e2
pyyaml git+https://github.com/edx/XBlock.git@xblock-0.4.2#egg=XBlock
-e git+https://github.com/edx/XBlock.git@tag-master-2015-05-22#egg=XBlock git+https://github.com/edx/xblock-utils.git@b4f9b51146c7fafa12f41d54af752b8f1516dffd#egg=xblock-utils
-e git+https://github.com/edx/xblock-utils.git@b4f9b51146c7fafa12f41d54af752b8f1516dffd#egg=xblock-utils
-e . -e .
django>=1.4, <1.5 Django>=1.8, <1.9
-r requirements.txt -r requirements.txt
-e git+https://github.com/edx/xblock-sdk.git@629650ed6fc1b77d1a5287debeace0b29db7c0fd#egg=xblock-sdk -e git+https://github.com/edx/xblock-sdk.git@8eb5f174dc59c0f4e40e10eaab56753958651d17#egg=xblock-sdk
ddt ddt
selenium==2.47.3 # 2.48 is not working atm selenium==2.47.3 # 2.48 is not working atm
...@@ -77,7 +77,7 @@ def check_presence(check, vectors): ...@@ -77,7 +77,7 @@ def check_presence(check, vectors):
""" """
if check['vector'] not in vectors: if check['vector'] not in vectors:
errmsg = check.get('errmsg', 'You need to use the {name} vector.') errmsg = check.get('errmsg', 'You need to use the {name} vector.')
return errmsg.format(name=check['vector']) raise ValueError(errmsg.format(name=check['vector']))
def _check_vector_endpoint(check, vectors, endpoint): def _check_vector_endpoint(check, vectors, endpoint):
...@@ -91,11 +91,11 @@ def _check_vector_endpoint(check, vectors, endpoint): ...@@ -91,11 +91,11 @@ def _check_vector_endpoint(check, vectors, endpoint):
endpoint = getattr(vec, endpoint) endpoint = getattr(vec, endpoint)
dist = math.hypot(expected[0] - endpoint.x, expected[1] - endpoint.y) dist = math.hypot(expected[0] - endpoint.x, expected[1] - endpoint.y)
if dist > tolerance: if dist > tolerance:
return _errmsg( raise ValueError(_errmsg(
'Vector {name} does not {verb} at correct point.'.format(name='{name}', verb=verb), 'Vector {name} does not {verb} at correct point.'.format(name='{name}', verb=verb),
check, check,
vectors vectors
) ))
def check_tail(check, vectors): def check_tail(check, vectors):
...@@ -127,7 +127,7 @@ def check_tail_x(check, vectors): ...@@ -127,7 +127,7 @@ def check_tail_x(check, vectors):
""" """
vec = vectors[check['vector']] vec = vectors[check['vector']]
if _check_coordinate(check, vec.tail.x): if _check_coordinate(check, vec.tail.x):
return _errmsg('Vector {name} does not start at correct point.', check, vectors) raise ValueError(_errmsg('Vector {name} does not start at correct point.', check, vectors))
def check_tail_y(check, vectors): def check_tail_y(check, vectors):
...@@ -136,7 +136,7 @@ def check_tail_y(check, vectors): ...@@ -136,7 +136,7 @@ def check_tail_y(check, vectors):
""" """
vec = vectors[check['vector']] vec = vectors[check['vector']]
if _check_coordinate(check, vec.tail.y): if _check_coordinate(check, vec.tail.y):
return _errmsg('Vector {name} does not start at correct point.', check, vectors) raise ValueError(_errmsg('Vector {name} does not start at correct point.', check, vectors))
def check_tip_x(check, vectors): def check_tip_x(check, vectors):
...@@ -145,7 +145,7 @@ def check_tip_x(check, vectors): ...@@ -145,7 +145,7 @@ def check_tip_x(check, vectors):
""" """
vec = vectors[check['vector']] vec = vectors[check['vector']]
if _check_coordinate(check, vec.tip.x): if _check_coordinate(check, vec.tip.x):
return _errmsg('Vector {name} does not end at correct point.', check, vectors) raise ValueError(_errmsg('Vector {name} does not end at correct point.', check, vectors))
def check_tip_y(check, vectors): def check_tip_y(check, vectors):
...@@ -154,7 +154,7 @@ def check_tip_y(check, vectors): ...@@ -154,7 +154,7 @@ def check_tip_y(check, vectors):
""" """
vec = vectors[check['vector']] vec = vectors[check['vector']]
if _check_coordinate(check, vec.tip.y): if _check_coordinate(check, vec.tip.y):
return _errmsg('Vector {name} does not end at correct point.', check, vectors) raise ValueError(_errmsg('Vector {name} does not end at correct point.', check, vectors))
def _coord_delta(expected, actual): def _coord_delta(expected, actual):
...@@ -187,7 +187,7 @@ def check_coords(check, vectors): ...@@ -187,7 +187,7 @@ def check_coords(check, vectors):
expected = check['expected'] expected = check['expected']
tolerance = check.get('tolerance', 1.0) tolerance = check.get('tolerance', 1.0)
if not _coords_within_tolerance(vec, expected, tolerance): if not _coords_within_tolerance(vec, expected, tolerance):
return _errmsg('Vector {name} coordinates are not correct.', check, vectors) raise ValueError(_errmsg('Vector {name} coordinates are not correct.', check, vectors))
def check_segment_coords(check, vectors): def check_segment_coords(check, vectors):
...@@ -199,7 +199,7 @@ def check_segment_coords(check, vectors): ...@@ -199,7 +199,7 @@ def check_segment_coords(check, vectors):
tolerance = check.get('tolerance', 1.0) tolerance = check.get('tolerance', 1.0)
if not (_coords_within_tolerance(vec, expected, tolerance) or if not (_coords_within_tolerance(vec, expected, tolerance) or
_coords_within_tolerance(vec.opposite(), expected, tolerance)): _coords_within_tolerance(vec.opposite(), expected, tolerance)):
return _errmsg('Segment {name} coordinates are not correct.', check, vectors) raise ValueError(_errmsg('Segment {name} coordinates are not correct.', check, vectors))
def check_length(check, vectors): def check_length(check, vectors):
...@@ -209,9 +209,9 @@ def check_length(check, vectors): ...@@ -209,9 +209,9 @@ def check_length(check, vectors):
vec = vectors[check['vector']] vec = vectors[check['vector']]
tolerance = check.get('tolerance', 1.0) tolerance = check.get('tolerance', 1.0)
if abs(vec.length - check['expected']) > tolerance: if abs(vec.length - check['expected']) > tolerance:
return _errmsg( raise ValueError(_errmsg(
'The length of {name} is incorrect. Your length: {length:.1f}', check, vectors 'The length of {name} is incorrect. Your length: {length:.1f}', check, vectors
) ))
def _angle_within_tolerance(vec, expected, tolerance): def _angle_within_tolerance(vec, expected, tolerance):
...@@ -236,7 +236,9 @@ def check_angle(check, vectors): ...@@ -236,7 +236,9 @@ def check_angle(check, vectors):
tolerance = check.get('tolerance', 2.0) tolerance = check.get('tolerance', 2.0)
expected = math.radians(check['expected']) expected = math.radians(check['expected'])
if not _angle_within_tolerance(vec, expected, tolerance): if not _angle_within_tolerance(vec, expected, tolerance):
return _errmsg('The angle of {name} is incorrect. Your angle: {angle:.1f}', check, vectors) raise ValueError(
_errmsg('The angle of {name} is incorrect. Your angle: {angle:.1f}', check, vectors)
)
def check_segment_angle(check, vectors): def check_segment_angle(check, vectors):
...@@ -250,7 +252,9 @@ def check_segment_angle(check, vectors): ...@@ -250,7 +252,9 @@ def check_segment_angle(check, vectors):
expected = math.radians(check['expected']) expected = math.radians(check['expected'])
if not (_angle_within_tolerance(vec, expected, tolerance) or if not (_angle_within_tolerance(vec, expected, tolerance) or
_angle_within_tolerance(vec.opposite(), expected, tolerance)): _angle_within_tolerance(vec.opposite(), expected, tolerance)):
return _errmsg('The angle of {name} is incorrect. Your angle: {angle:.1f}', check, vectors) raise ValueError(
_errmsg('The angle of {name} is incorrect. Your angle: {angle:.1f}', check, vectors)
)
def _dist_line_point(line, point): def _dist_line_point(line, point):
...@@ -275,9 +279,9 @@ def check_points_on_line(check, vectors): ...@@ -275,9 +279,9 @@ def check_points_on_line(check, vectors):
for point in points: for point in points:
point = Point(point[0], point[1]) point = Point(point[0], point[1])
if _dist_line_point(line, point) > tolerance: if _dist_line_point(line, point) > tolerance:
return _errmsg( raise ValueError(_errmsg(
'The line {name} does not pass through the correct points.', check, vectors 'The line {name} does not pass through the correct points.', check, vectors
) ))
def check_point_coords(check, points): def check_point_coords(check, points):
...@@ -358,10 +362,11 @@ class Grader(object): ...@@ -358,10 +362,11 @@ class Grader(object):
check_data['check'] = check check_data['check'] = check
check_fn = self.check_registry[check['check']] check_fn = self.check_registry[check['check']]
args = [check_data[arg] for arg in inspect.getargspec(check_fn).args] args = [check_data[arg] for arg in inspect.getargspec(check_fn).args]
result = check_fn(*args) try:
if result: check_fn(*args)
return {'ok': False, 'msg': result} except ValueError as e:
return {'ok': True, 'msg': self.success_message} return {'correct': False, 'msg': e.message}
return {'correct': True, 'msg': self.success_message}
def _get_vectors(self, answer): # pylint: disable=no-self-use def _get_vectors(self, answer): # pylint: disable=no-self-use
""" """
......
...@@ -4,7 +4,7 @@ function StudioEditableXBlockMixin(runtime, element) { ...@@ -4,7 +4,7 @@ function StudioEditableXBlockMixin(runtime, element) {
var fields = []; var fields = [];
var tinyMceAvailable = (typeof $.fn.tinymce !== 'undefined'); // Studio includes a copy of tinyMCE and its jQuery plugin var tinyMceAvailable = (typeof $.fn.tinymce !== 'undefined'); // Studio includes a copy of tinyMCE and its jQuery plugin
var errorMessage = gettext("This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online."); var errorMessage = gettext("This may be happening because of an error with our server or your internet connection. Make sure you are online, and try refreshing the page.");
$(element).find('.field-data-control').each(function() { $(element).find('.field-data-control').each(function() {
var $field = $(this); var $field = $(this);
...@@ -18,11 +18,11 @@ function StudioEditableXBlockMixin(runtime, element) { ...@@ -18,11 +18,11 @@ function StudioEditableXBlockMixin(runtime, element) {
val: function() { val: function() {
var val = $field.val(); var val = $field.val();
// Cast values to the appropriate type so that we send nice clean JSON over the wire: // Cast values to the appropriate type so that we send nice clean JSON over the wire:
if (type == 'boolean') if (type === 'boolean')
return (val == 'true' || val == '1'); return (val === 'true' || val === '1');
if (type == "integer") if (type === "integer")
return parseInt(val, 10); return parseInt(val, 10);
if (type == "float") if (type === "float")
return parseFloat(val); return parseFloat(val);
return val; return val;
}, },
...@@ -41,7 +41,7 @@ function StudioEditableXBlockMixin(runtime, element) { ...@@ -41,7 +41,7 @@ function StudioEditableXBlockMixin(runtime, element) {
$wrapper.removeClass('is-set'); $wrapper.removeClass('is-set');
$resetButton.removeClass('active').addClass('inactive'); $resetButton.removeClass('active').addClass('inactive');
}); });
if (type == 'html' && tinyMceAvailable) { if (type === 'html' && tinyMceAvailable) {
tinyMCE.baseURL = baseUrl + "/js/vendor/tinymce/js/tinymce"; tinyMCE.baseURL = baseUrl + "/js/vendor/tinymce/js/tinymce";
$field.tinymce({ $field.tinymce({
theme: 'modern', theme: 'modern',
...@@ -72,16 +72,17 @@ function StudioEditableXBlockMixin(runtime, element) { ...@@ -72,16 +72,17 @@ function StudioEditableXBlockMixin(runtime, element) {
url: handlerUrl, url: handlerUrl,
data: JSON.stringify(data), data: JSON.stringify(data),
dataType: "json", dataType: "json",
global: false // Disable Studio's error handling that conflicts with studio's notify('save') and notify('cancel') :-/ notifyOnError: false
}).done(function(response) { }).done(function(response) {
runtime.notify('save', {state: 'end'}); runtime.notify('save', {state: 'end'});
}).fail(function(jqXHR) { }).fail(function(jqXHR) {
if (jqXHR.responseText) { // Is there a more specific error message we can show? if (jqXHR.responseText) { // Is there a more specific error message we can show?
try { try {
errorMessage = JSON.parse(jqXHR.responseText).error; errorMessage = JSON.parse(jqXHR.responseText).error;
if (typeof errorMessage === "object" && errorMessage.messages) { if (_.isObject(errorMessage) && errorMessage.messages) {
// e.g. {"error": {"messages": [{"text": "Unknown user 'bob'!", "type": "error"}, ...]}} etc. // e.g. {"error": {"messages": [{"text": "Unknown user 'bob'!", "type": "error"}, ...]}} etc.
errorMessage = $.map(errorMessage.messages, function(msg) { return msg.text; }).join(", "); var errorMessages = _.pluck(errorMessage.messages, "text");
errorMessage = errorMessages.join(", ");
} }
} catch (error) { errorMessage = jqXHR.responseText.substr(0, 300); } } catch (error) { errorMessage = jqXHR.responseText.substr(0, 300); }
} }
...@@ -98,8 +99,7 @@ function StudioEditableXBlockMixin(runtime, element) { ...@@ -98,8 +99,7 @@ function StudioEditableXBlockMixin(runtime, element) {
save: function(data) { save: function(data) {
var values = {}; var values = {};
var notSet = []; // List of field names that should be set to default values var notSet = []; // List of field names that should be set to default values
for (var i in fields) { _.each(fields, function(field) {
var field = fields[i];
if (field.isSet()) { if (field.isSet()) {
values[field.name] = field.val(); values[field.name] = field.val();
} else { } else {
...@@ -110,7 +110,7 @@ function StudioEditableXBlockMixin(runtime, element) { ...@@ -110,7 +110,7 @@ function StudioEditableXBlockMixin(runtime, element) {
if (field.hasEditor()) { if (field.hasEditor()) {
field.removeEditor(); field.removeEditor();
} }
} });
// If WYSIWYG editor was used, // If WYSIWYG editor was used,
// prefer its data over values of "Vectors" and "Expected result" fields: // prefer its data over values of "Vectors" and "Expected result" fields:
if (!_.isEmpty(data)) { if (!_.isEmpty(data)) {
...@@ -125,12 +125,11 @@ function StudioEditableXBlockMixin(runtime, element) { ...@@ -125,12 +125,11 @@ function StudioEditableXBlockMixin(runtime, element) {
cancel: function() { cancel: function() {
// Remove TinyMCE instances to make sure jQuery does not try to access stale instances // Remove TinyMCE instances to make sure jQuery does not try to access stale instances
// when loading editor for another block: // when loading editor for another block:
for (var i in fields) { _.each(fields, function(field) {
var field = fields[i];
if (field.hasEditor()) { if (field.hasEditor()) {
field.removeEditor(); field.removeEditor();
} }
} });
runtime.notify('cancel', {}); runtime.notify('cancel', {});
} }
......
...@@ -593,7 +593,7 @@ function VectorDrawXBlock(runtime, element, init_args) { ...@@ -593,7 +593,7 @@ function VectorDrawXBlock(runtime, element, init_args) {
var correctness = $('.correctness', element), var correctness = $('.correctness', element),
correctClass = 'checkmark-correct fa fa-check', correctClass = 'checkmark-correct fa fa-check',
incorrectClass = 'checkmark-incorrect fa fa-times'; incorrectClass = 'checkmark-incorrect fa fa-times';
if (data.result.ok) { if (data.result.correct) {
correctness.removeClass(incorrectClass); correctness.removeClass(incorrectClass);
correctness.addClass(correctClass); correctness.addClass(correctClass);
} else { } else {
......
...@@ -530,7 +530,7 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock): ...@@ -530,7 +530,7 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
# Save result # Save result
self.result = result self.result = result
# Publish grade data # Publish grade data
score = 1 if result["ok"] else 0 score = 1 if result["correct"] else 0
self.runtime.publish(self, 'grade', dict(value=score, max_value=1)) self.runtime.publish(self, 'grade', dict(value=score, max_value=1))
return { return {
"result": result, "result": result,
......
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