Commit 9e6e0011 by Tim Krones

Address review comments.

parent 602d0212
...@@ -105,20 +105,33 @@ class TestVectorDraw(StudioEditableBaseTest): ...@@ -105,20 +105,33 @@ class TestVectorDraw(StudioEditableBaseTest):
def check_vector_properties( def check_vector_properties(
self, menu, is_present=False, expected_label="Vector Properties", self, menu, is_present=False, expected_label="Vector Properties",
expected_name=None, expected_tail=None, expected_length=None, expected_angle=None expected_name=None, expected_tail=None, expected_length=None, expected_angle=None,
input_fields_disabled=True
): ):
if is_present: if is_present:
vector_properties = menu.find_element_by_css_selector(".vector-properties") vector_properties = menu.find_element_by_css_selector(".vector-properties")
vector_properties_label = vector_properties.find_element_by_css_selector("h3") vector_properties_label = vector_properties.find_element_by_css_selector("h3")
self.assertEquals(vector_properties_label.text, expected_label) self.assertEquals(vector_properties_label.text, expected_label)
# Name # Name
self.check_vector_property(vector_properties, "name", "select", "name:", expected_name or "-") self.check_vector_property(
vector_properties, "name", "select", "name:", expected_name or "-",
field_disabled=input_fields_disabled
)
# Tail # Tail
self.check_vector_property(vector_properties, "tail", "input", "tail position:", expected_tail or "-") self.check_vector_property(
vector_properties, "tail", "input", "tail position:", expected_tail or "",
field_disabled=input_fields_disabled
)
# Length # Length
self.check_vector_property(vector_properties, "length", "input", "length:", expected_length or "-") self.check_vector_property(
vector_properties, "length", "input", "length:", expected_length or "",
field_disabled=input_fields_disabled
)
# Angle # Angle
self.check_vector_property(vector_properties, "angle", "input", "angle:", expected_angle or "-") self.check_vector_property(
vector_properties, "angle", "input", "angle:", expected_angle or "",
field_disabled=input_fields_disabled
)
# Slope # Slope
vector_slope = vector_properties.find_element_by_css_selector(".vector-prop-slope") vector_slope = vector_properties.find_element_by_css_selector(".vector-prop-slope")
self.assertFalse(vector_slope.is_displayed()) self.assertFalse(vector_slope.is_displayed())
...@@ -130,7 +143,8 @@ class TestVectorDraw(StudioEditableBaseTest): ...@@ -130,7 +143,8 @@ class TestVectorDraw(StudioEditableBaseTest):
) )
def check_vector_property( def check_vector_property(
self, vector_properties, property_name, input_type, expected_label, expected_value=None self, vector_properties, property_name, input_type, expected_label, expected_value=None,
field_disabled=False
): ):
vector_property = vector_properties.find_element_by_css_selector( vector_property = vector_properties.find_element_by_css_selector(
".vector-prop-{}".format(property_name) ".vector-prop-{}".format(property_name)
...@@ -145,6 +159,8 @@ class TestVectorDraw(StudioEditableBaseTest): ...@@ -145,6 +159,8 @@ class TestVectorDraw(StudioEditableBaseTest):
) )
if input_type == "input": if input_type == "input":
self.assertEquals(vector_property_input.get_attribute("value"), expected_value) self.assertEquals(vector_property_input.get_attribute("value"), expected_value)
disabled = vector_property_input.get_attribute("disabled")
self.assertEquals(bool(disabled), field_disabled)
else: else:
selected_option = vector_property_input.find_element_by_css_selector('option[selected="selected"]') selected_option = vector_property_input.find_element_by_css_selector('option[selected="selected"]')
self.assertEquals(selected_option.text, expected_value) self.assertEquals(selected_option.text, expected_value)
...@@ -297,7 +313,8 @@ class TestVectorDraw(StudioEditableBaseTest): ...@@ -297,7 +313,8 @@ class TestVectorDraw(StudioEditableBaseTest):
# "Vector Properties" should display correct info # "Vector Properties" should display correct info
self.check_vector_properties( self.check_vector_properties(
menu, is_present=True, expected_label="Custom properties label", menu, is_present=True, expected_label="Custom properties label",
expected_name="N", expected_tail="2.00, 2.00", expected_length="4.00", expected_angle="45.00" expected_name="N", expected_tail="2.00, 2.00", expected_length="4.00", expected_angle="45.00",
input_fields_disabled=False
) )
self.check_edit_dropdown(menu, vectors) self.check_edit_dropdown(menu, vectors)
...@@ -330,7 +347,8 @@ class TestVectorDraw(StudioEditableBaseTest): ...@@ -330,7 +347,8 @@ class TestVectorDraw(StudioEditableBaseTest):
# "Vector Properties" should display correct info # "Vector Properties" should display correct info
self.check_vector_properties( self.check_vector_properties(
menu, is_present=True, expected_label="Custom properties label", menu, is_present=True, expected_label="Custom properties label",
expected_name="N", expected_tail="2.00, 2.00", expected_length="4.00", expected_angle="45.00" expected_name="N", expected_tail="2.00, 2.00", expected_length="4.00", expected_angle="45.00",
input_fields_disabled=False
) )
def reset(self, board, vectors, points): def reset(self, board, vectors, points):
...@@ -552,7 +570,8 @@ class TestVectorDraw(StudioEditableBaseTest): ...@@ -552,7 +570,8 @@ class TestVectorDraw(StudioEditableBaseTest):
menu = self.exercise.find_element_by_css_selector(".menu") menu = self.exercise.find_element_by_css_selector(".menu")
self.check_vector_properties( self.check_vector_properties(
menu, is_present=True, expected_label="Custom properties label", menu, is_present=True, expected_label="Custom properties label",
expected_name="N", expected_tail="2.00, 2.00", expected_length="4.00", expected_angle="45.00" expected_name="N", expected_tail="2.00, 2.00", expected_length="4.00", expected_angle="45.00",
input_fields_disabled=False
) )
@data( @data(
......
...@@ -123,7 +123,7 @@ ...@@ -123,7 +123,7 @@
} }
.vectordraw_block .menu .vector-properties .vector-prop-list .row .vector-prop-update .update-error { .vectordraw_block .menu .vector-properties .vector-prop-list .row .vector-prop-update .update-error {
visibility: hidden; display: none;
color: #ff0000; color: #ff0000;
} }
......
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
margin-bottom: 1em; margin-bottom: 1em;
} }
.vectordraw_edit_block #wysiwyg-description {
display: none;
}
.vectordraw_edit_block p { .vectordraw_edit_block p {
margin-bottom: 1em; margin-bottom: 1em;
font-size: 0.9em; font-size: 0.9em;
...@@ -59,6 +63,11 @@ ...@@ -59,6 +63,11 @@
float: right; float: right;
} }
.vectordraw_block .menu .vector-properties .vector-prop-list .row .vector-prop-update .update-pending {
display: none;
color: #ffa500;
}
.vectordraw_edit_block h3 { .vectordraw_edit_block h3 {
margin-top: 5px; margin-top: 5px;
margin-bottom: 5px; margin-bottom: 5px;
...@@ -83,11 +92,16 @@ ...@@ -83,11 +92,16 @@
} }
.vectordraw_edit_block .checks .check span, .vectordraw_edit_block .checks .check span,
.vectordraw_edit_block .checks .check input[type="text"] { .vectordraw_edit_block .checks .check input[type="number"] {
height: 1.5em; height: 1.5em;
min-width: 0px;
margin-right: 12px; margin-right: 12px;
} }
.vectordraw_edit_block .checks .check input[type="number"] {
padding: 0 0 0 5px;
}
.vectordraw_edit_block .checks .check input[type="checkbox"] { .vectordraw_edit_block .checks .check input[type="checkbox"] {
height: 1.2em; height: 1.2em;
width: 20%; width: 20%;
......
...@@ -367,6 +367,10 @@ function VectorDrawXBlock(runtime, element, init_args) { ...@@ -367,6 +367,10 @@ function VectorDrawXBlock(runtime, element, init_args) {
$('.vector-prop-slope input', this.element).val(slope.toFixed(2)); $('.vector-prop-slope input', this.element).val(slope.toFixed(2));
} }
} }
// Enable input fields
$('.vector-properties input').prop('disabled', false);
// Hide error message
$('.vector-prop-update .update-error', element).hide();
}; };
VectorDraw.prototype.resetVectorProperties = function(vector) { VectorDraw.prototype.resetVectorProperties = function(vector) {
...@@ -374,8 +378,8 @@ function VectorDrawXBlock(runtime, element, init_args) { ...@@ -374,8 +378,8 @@ function VectorDrawXBlock(runtime, element, init_args) {
this.element.find('.menu .element-list-edit option').attr('selected', false); this.element.find('.menu .element-list-edit option').attr('selected', false);
// Select default value // Select default value
$('.menu .element-list-edit option[value="-"]', element).attr('selected', true); $('.menu .element-list-edit option[value="-"]', element).attr('selected', true);
// Reset input fields to default values // Reset input fields to default values and disable them
$('.menu .vector-prop-list input', element).val('-'); $('.menu .vector-prop-list input', element).prop('disabled', true).val('');
}; };
VectorDraw.prototype.isVectorTailDraggable = function(vector) { VectorDraw.prototype.isVectorTailDraggable = function(vector) {
...@@ -478,7 +482,7 @@ function VectorDrawXBlock(runtime, element, init_args) { ...@@ -478,7 +482,7 @@ function VectorDrawXBlock(runtime, element, init_args) {
var values = [newTail[0], newTail[1], newLength, newAngle]; var values = [newTail[0], newTail[1], newLength, newAngle];
// Validate values // Validate values
if (!_.some(values, Number.isNaN)) { if (!_.some(values, Number.isNaN)) {
$('.vector-prop-update .update-error', element).css('visibility', 'hidden'); $('.vector-prop-update .update-error', element).hide();
// Use coordinates of new tail, new length, new angle to calculate new position of tip // Use coordinates of new tail, new length, new angle to calculate new position of tip
var radians = newAngle * Math.PI / 180; var radians = newAngle * Math.PI / 180;
var newTip = [ var newTip = [
...@@ -491,7 +495,7 @@ function VectorDrawXBlock(runtime, element, init_args) { ...@@ -491,7 +495,7 @@ function VectorDrawXBlock(runtime, element, init_args) {
board_object.point2.setPosition(JXG.COORDS_BY_USER, newTip); board_object.point2.setPosition(JXG.COORDS_BY_USER, newTip);
this.board.update(); this.board.update();
} else { } else {
$('.vector-prop-update .update-error', element).css('visibility', 'visible'); $('.vector-prop-update .update-error', element).show();
} }
}; };
......
...@@ -4,11 +4,15 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -4,11 +4,15 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
var VectorDraw = function(element_id, settings) { var VectorDraw = function(element_id, settings) {
this.board = null; this.board = null;
this.dragged_vector = null; this.dragged_vector = null;
this.selectedVector = null;
this.drawMode = false; this.drawMode = false;
this.wasUsed = false; this.wasUsed = false;
this.resultMode = false; this.resultMode = false;
this.settings = settings; this.settings = settings;
this.numberOfVectors = this.settings.vectors.length; this.numberOfVectors = this.settings.vectors.length;
this.checks = [
'tail', 'tail_x', 'tail_y', 'tip', 'tip_x', 'tip_y', 'coords', 'length', 'angle'
];
this.element = $('#' + element_id, element); this.element = $('#' + element_id, element);
this.element.on('click', '.controls .add-vector', this.onAddVector.bind(this)); this.element.on('click', '.controls .add-vector', this.onAddVector.bind(this));
...@@ -28,17 +32,10 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -28,17 +32,10 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
// (without making necessary adjustments in "Expected results" field) // (without making necessary adjustments in "Expected results" field)
// discard stale information about expected positions and checks // discard stale information about expected positions and checks
var vectorData = JSON.parse(fieldEditor.getContents('vectors')), var vectorData = JSON.parse(fieldEditor.getContents('vectors')),
vectorNames = _.pluck(vectorData, 'name'); vectorNames = this.getVectorNames(vectorData);
_.each(_.keys(this.settings.expected_result_positions), function(key) { var isStale = function(key) { return !_.contains(vectorNames, key); };
if (!_.contains(vectorNames, key)) { this.settings.expected_result_positions = _.omit(this.settings.expected_result_positions, isStale);
delete this.settings.expected_result_positions[key]; this.settings.expected_result = _.omit(this.settings.expected_result, isStale);
}
}, this);
_.each(_.keys(this.settings.expected_result), function(key) {
if (!_.contains(vectorNames, key)) {
delete this.settings.expected_result[key];
}
}, this);
}; };
VectorDraw.prototype.render = function() { VectorDraw.prototype.render = function() {
...@@ -112,6 +109,13 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -112,6 +109,13 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
this.board.create('point', coords, point.style); this.board.create('point', coords, point.style);
}; };
VectorDraw.prototype.getVectorNames = function(vectorData) {
if (vectorData) {
return _.pluck(vectorData, 'name');
}
return _.pluck(this.settings.vectors, 'name');
};
VectorDraw.prototype.getVectorCoordinates = function(vec) { VectorDraw.prototype.getVectorCoordinates = function(vec) {
var coords = vec.coords; var coords = vec.coords;
if (!coords) { if (!coords) {
...@@ -232,26 +236,22 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -232,26 +236,22 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
var boardObject = this.board.elementsByName[vectorName]; var boardObject = this.board.elementsByName[vectorName];
this.board.removeAncestors(boardObject); this.board.removeAncestors(boardObject);
// 2. Mark vector as "deleted" so it will be removed from "vectors" field on save // 2. Mark vector as "deleted" so it will be removed from "vectors" field on save
var vectorSettings = this.getVectorSettingsByName("" + vectorName); var vectorSettings = this.getVectorSettingsByName(String(vectorName));
vectorSettings.deleted = true; vectorSettings.deleted = true;
// 3. Remove entry that corresponds to selected vector from menu for selecting vector to edit // 3. Remove entry that corresponds to selected vector from menu for selecting vector to edit
var idx = _.indexOf(this.settings.vectors, vectorSettings), var idx = _.indexOf(this.settings.vectors, vectorSettings),
editOption = this.getEditMenuOption("vector", idx); editOption = this.getEditMenuOption("vector", idx);
editOption.remove(); editOption.remove();
// 4. Discard information about expected position // 4. Discard information about expected position (if any)
var expectedPositions = this.settings.expected_result_positions; delete this.settings.expected_result_positions[vectorName];
if (expectedPositions[vectorName]) { // 5. Discard information about expected result (if any)
delete expectedPositions[vectorName]; delete this.settings.expected_result[vectorName];
this.settings.expected_result_positions = expectedPositions;
}
// 5. Discard information about expected result
var expectedResults = this.settings.expected_result;
if (expectedResults[vectorName]) {
delete expectedResults[vectorName];
this.settings.expected_result = expectedResults;
}
// 6. Reset input fields for vector properties to default values // 6. Reset input fields for vector properties to default values
this.resetVectorProperties(); this.resetVectorProperties();
// 7. Reset selected vector
this.selectedVector = null;
// 8. Hide message about pending changes
$('.vector-prop-update .update-pending', element).hide();
}; };
VectorDraw.prototype.onEditResult = function(evt) { VectorDraw.prototype.onEditResult = function(evt) {
...@@ -259,6 +259,9 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -259,6 +259,9 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
this.resultMode = true; this.resultMode = true;
// Save vector positions // Save vector positions
this.settings.vectors = this.getState(); // Discards vectors that were removed from board this.settings.vectors = this.getState(); // Discards vectors that were removed from board
// Vector positions saved, so hide message about pending changes
this.selectedVector = null;
$('.vector-prop-update .update-pending', element).hide();
// Update vector positions using positions from expected result // Update vector positions using positions from expected result
var expectedResultPositions = this.settings.expected_result_positions; var expectedResultPositions = this.settings.expected_result_positions;
if (!_.isEmpty(expectedResultPositions)) { if (!_.isEmpty(expectedResultPositions)) {
...@@ -286,13 +289,17 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -286,13 +289,17 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
this.resetVectorProperties(); this.resetVectorProperties();
// Show controls for opting in and out of checks // Show controls for opting in and out of checks
$('.checks', element).show(); $('.checks', element).show();
// Disable input fields that users should not be able to interact with unless a vector is selected
_.each(['tail', 'length', 'angle'], function(propName) {
$('.vector-prop-' + propName + ' input', element).prop('disabled', true);
});
}; };
VectorDraw.prototype.resetVectorProperties = function(vector) { VectorDraw.prototype.resetVectorProperties = function(vector) {
// Select default value // Select default value
$('.menu .element-list-edit option[value="-"]', element).attr('selected', true); $('.menu .element-list-edit option[value="-"]', element).attr('selected', true);
// Reset input fields to default values // Reset input fields to default values
$('.menu .vector-prop-list input', element).val('-'); $('.menu .vector-prop-list input', element).val('');
}; };
VectorDraw.prototype.getMouseCoords = function(evt) { VectorDraw.prototype.getMouseCoords = function(evt) {
...@@ -335,6 +342,12 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -335,6 +342,12 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
if (angle < 0) { if (angle < 0) {
angle += 360; angle += 360;
} }
// If user selected different vector, hide message about pending changes
if (this.selectedVector && vector.name !== this.selectedVector.name) {
$('.vector-prop-update .update-pending', element).hide();
}
// Update selected vector
this.selectedVector = vector;
// Update menu for selecting vector to edit // Update menu for selecting vector to edit
this.element.find('.menu .element-list-edit option').attr('selected', false); this.element.find('.menu .element-list-edit option').attr('selected', false);
var idx = _.indexOf(this.settings.vectors, vec_settings), var idx = _.indexOf(this.settings.vectors, vec_settings),
...@@ -342,7 +355,7 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -342,7 +355,7 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
editOption.attr('selected', true); editOption.attr('selected', true);
// Update properties // Update properties
$('.vector-prop-name input', this.element).val(vector.name); $('.vector-prop-name input', this.element).val(vector.name);
$('.vector-prop-label input', this.element).val(vec_settings.style.label || '-'); $('.vector-prop-label input', this.element).val(vec_settings.style.label || '');
$('.vector-prop-angle input', this.element).val(angle.toFixed(2)); $('.vector-prop-angle input', this.element).val(angle.toFixed(2));
if (vector.elType !== "line") { if (vector.elType !== "line") {
var tailInput = x1.toFixed(2) + ", " + y1.toFixed(2); var tailInput = x1.toFixed(2) + ", " + y1.toFixed(2);
...@@ -357,14 +370,13 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -357,14 +370,13 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
else { else {
$('.vector-prop-length', this.element).hide(); $('.vector-prop-length', this.element).hide();
} }
// Enable input fields
$('.vector-properties input').prop('disabled', false);
}; };
VectorDraw.prototype.updateChecks = function(vector) { VectorDraw.prototype.updateChecks = function(vector) {
var expectedResult = this.settings.expected_result[vector.name] || {}; var expectedResult = this.settings.expected_result[vector.name] || {};
var checks = [ _.each(this.checks, function(check) {
'tail', 'tail_x', 'tail_y', 'tip', 'tip_x', 'tip_y', 'coords', 'length', 'angle'
];
_.each(checks, function(check) {
var checkElement = $('#check-' + check, element); var checkElement = $('#check-' + check, element);
// Update checkbox // Update checkbox
if (expectedResult[check]) { if (expectedResult[check]) {
...@@ -375,10 +387,10 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -375,10 +387,10 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
// Update tolerance // Update tolerance
var tolerance = expectedResult[check + '_tolerance']; var tolerance = expectedResult[check + '_tolerance'];
if (tolerance) { if (tolerance) {
checkElement.find('input[type="text"]').val(tolerance.toFixed(1)); checkElement.find('input[type="number"]').val(tolerance.toFixed(1));
} else { } else {
var defaultTolerance = check === 'angle' ? 2.0 : 1.0; var defaultTolerance = check === 'angle' ? 2.0 : 1.0;
checkElement.find('input[type="text"]').val(defaultTolerance.toFixed(1)); checkElement.find('input[type="number"]').val(defaultTolerance.toFixed(1));
} }
}); });
}; };
...@@ -400,16 +412,13 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -400,16 +412,13 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
VectorDraw.prototype.saveChecks = function(vectorName) { VectorDraw.prototype.saveChecks = function(vectorName) {
var expectedResult = {}; var expectedResult = {};
var checks = [ _.each(this.checks, function(check) {
'tail', 'tail_x', 'tail_y', 'tip', 'tip_x', 'tip_y', 'coords', 'length', 'angle'
];
_.each(checks, function(check) {
var checkElement = $('#check-' + check, element); var checkElement = $('#check-' + check, element);
if (checkElement.find('input[type="checkbox"]').prop('checked')) { if (checkElement.find('input[type="checkbox"]').prop('checked')) {
// Insert (or update) check: Need current position of selected vector // Insert (or update) check: Need current position of selected vector
expectedResult[check] = this.settings.expected_result_positions[vectorName][check]; expectedResult[check] = this.settings.expected_result_positions[vectorName][check];
// Insert (or update) tolerance // Insert (or update) tolerance
var tolerance = checkElement.find('input[type="text"]').val(); var tolerance = checkElement.find('input[type="number"]').val();
expectedResult[check + '_tolerance'] = parseFloat(tolerance); expectedResult[check + '_tolerance'] = parseFloat(tolerance);
} }
}, this); }, this);
...@@ -457,7 +466,7 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -457,7 +466,7 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
VectorDraw.prototype.getDefaultVector = function(coords) { VectorDraw.prototype.getDefaultVector = function(coords) {
this.numberOfVectors += 1; this.numberOfVectors += 1;
var name = "" + this.numberOfVectors, var name = String(this.numberOfVectors),
description = "Vector " + name; description = "Vector " + name;
return { return {
name: name, name: name,
...@@ -504,7 +513,11 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -504,7 +513,11 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
this.dragged_vector.point1.setProperty({fixed: false}); this.dragged_vector.point1.setProperty({fixed: false});
this.updateVectorProperties(this.dragged_vector); this.updateVectorProperties(this.dragged_vector);
if (this.resultMode) { if (this.resultMode) {
_.each(['name', 'label'], function(propName) {
$('.vector-prop-' + propName + ' input', element).prop('disabled', true);
});
this.updateChecks(this.dragged_vector); this.updateChecks(this.dragged_vector);
$('.checks input', element).prop('disabled', false);
} }
} }
} }
...@@ -536,7 +549,11 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -536,7 +549,11 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
var vectorObject = this.board.elementsByName[vectorName]; var vectorObject = this.board.elementsByName[vectorName];
this.updateVectorProperties(vectorObject); this.updateVectorProperties(vectorObject);
if (this.resultMode) { if (this.resultMode) {
_.each(['name', 'label'], function(propName) {
$('.vector-prop-' + propName + ' input', element).prop('disabled', true);
});
this.updateChecks(vectorObject); this.updateChecks(vectorObject);
$('.checks input', element).prop('disabled', false);
} }
}; };
...@@ -544,30 +561,32 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -544,30 +561,32 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
if (!this.wasUsed) { if (!this.wasUsed) {
this.wasUsed = true; this.wasUsed = true;
} }
// About to save changes, so hide message about pending changes
$('.vector-prop-update .update-pending', element).hide();
// Get name of vector that is currently "selected" // Get name of vector that is currently "selected"
var vectorName = "" + $('.element-list-edit', element).find('option:selected').data('vector-name'); var vectorName = String($('.element-list-edit', element).find('option:selected').data('vector-name')),
editableProperties = ['name', 'label', 'tail', 'length', 'angle'],
newValues = {};
// Get values from input fields // Get values from input fields
var newName = $('.vector-prop-name input', element).val(), _.each(editableProperties, function(prop) {
newLabel = $('.vector-prop-label input', element).val(), newValues[prop] = $.trim($('.vector-prop-' + prop + ' input', element).val());
newTail = $('.vector-prop-tail input', element).val(),
newLength = $('.vector-prop-length input', element).val(),
newAngle = $('.vector-prop-angle input', element).val();
// Process values
newName = $.trim(newName);
newLabel = $.trim(newLabel);
newTail = _.map(newTail.split(/ *, */), function(coord) {
return parseFloat(coord);
}); });
newLength = parseFloat(newLength); // Process values
newAngle = parseFloat(newAngle); var newName = newValues.name,
newLabel = newValues.label,
newTail = _.map(newValues.tail.split(/ *, */), function(coord) { return parseFloat(coord); }),
newLength = parseFloat(newValues.length),
newAngle = parseFloat(newValues.angle);
// Validate and update values // Validate and update values
var vectorSettings = this.getVectorSettingsByName(vectorName), var vectorNames = this.getVectorNames(),
editOption = $('.menu .element-list-edit option[data-vector-name="' + vectorName + '"]', element), vectorSettings = this.getVectorSettingsByName(vectorName),
boardObject = this.board.elementsByName[vectorName]; boardObject = this.board.elementsByName[vectorName];
if (newName && newName !== vectorName) { // 1. Update name
if (newName && newName !== vectorName && !_.contains(vectorNames, newName)) {
// Update vector settings // Update vector settings
vectorSettings.name = newName; vectorSettings.name = newName;
// Update dropdown for selecting vector to edit // Update dropdown for selecting vector to edit
var editOption = $('.menu .element-list-edit option[data-vector-name="' + vectorName + '"]', element);
editOption.data('vector-name', newName); editOption.data('vector-name', newName);
editOption.text(newName); editOption.text(newName);
// Update board // Update board
...@@ -589,14 +608,21 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -589,14 +608,21 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
expectedResults[newName] = expectedResult; expectedResults[newName] = expectedResult;
delete expectedResults[vectorName]; delete expectedResults[vectorName];
} }
} else {
$('.vector-prop-name input', element).val(vectorName);
} }
if (newLabel && newLabel !== '-') { // 2. Update label
if (newLabel) {
vectorSettings.style.label = newLabel; vectorSettings.style.label = newLabel;
boardObject.point2.name = newLabel; // Always prefer label for labeling vector on board boardObject.point2.name = newLabel; // Always prefer label for labeling vector on board
} else {
vectorSettings.style.label = null;
boardObject.point2.name = newName || vectorName; // ... but fall back on name if label was removed
} }
// 3. Update tail, length, angle
var values = [newTail[0], newTail[1], newLength, newAngle]; var values = [newTail[0], newTail[1], newLength, newAngle];
if (!_.some(values, Number.isNaN)) { if (!_.some(values, Number.isNaN)) {
$('.vector-prop-update .update-error', element).css('visibility', 'hidden'); $('.vector-prop-update .update-error', element).hide();
// Use coordinates of new tail, new length, new angle to calculate new position of tip // Use coordinates of new tail, new length, new angle to calculate new position of tip
var radians = newAngle * Math.PI / 180; var radians = newAngle * Math.PI / 180;
var newTip = [ var newTip = [
...@@ -616,7 +642,7 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -616,7 +642,7 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
this.saveChecks(vectorName); this.saveChecks(vectorName);
} }
} else { } else {
$('.vector-prop-update .update-error', element).css('visibility', 'visible'); $('.vector-prop-update .update-error', element).show();
} }
}; };
...@@ -665,29 +691,30 @@ function VectorDrawXBlockEdit(runtime, element, init_args) { ...@@ -665,29 +691,30 @@ function VectorDrawXBlockEdit(runtime, element, init_args) {
// Set up click handlers // Set up click handlers
$('.save-button', element).on('click', function(e) { $('.save-button', element).on('click', function(e) {
e.preventDefault(); e.preventDefault();
var data; var data = {};
if (vectordraw.resultMode) { // Author edited both initial state and result if (vectordraw.wasUsed) {
data = { // If author edited both initial state and result,
vectors: vectordraw.settings.vectors, // Corresponds to state vectors were in // vectordraw.settings.vectors corresponds to state vectors were in
// when author switched to result mode // when author switched to result mode
expected_result_positions: vectordraw.settings.expected_result_positions, data.vectors = vectordraw.resultMode ? vectordraw.settings.vectors : vectordraw.getState();
expected_result: vectordraw.settings.expected_result data.expected_result_positions = vectordraw.settings.expected_result_positions;
}; data.expected_result = vectordraw.settings.expected_result;
} else if (vectordraw.wasUsed) { // Author edited initial state
var state = vectordraw.getState();
data = {
vectors: state,
expected_result_positions: vectordraw.settings.expected_result_positions,
expected_result: vectordraw.settings.expected_result
};
} else { // Author did not use WYSIWYG editor
data = {};
} }
fieldEditor.save(data); fieldEditor.save(data);
}); });
$('.cancel-button', element).on('click', function(e) { $('.cancel-button', element).on('click', function(e) {
e.preventDefault(); e.preventDefault();
fieldEditor.cancel(); fieldEditor.cancel();
}); });
$('.info-button', element).on('click', function(e) {
e.preventDefault();
$('#wysiwyg-description', element).toggle();
});
$('input', element).on('change', function(e) {
$('.update-error').hide();
$('.update-pending').show();
});
} }
...@@ -74,13 +74,13 @@ ...@@ -74,13 +74,13 @@
<span id="vector-prop-tail-label"> <span id="vector-prop-tail-label">
{% trans "tail position" %}: {% trans "tail position" %}:
</span> </span>
<input type="text" value="-" aria-labelledby="vector-prop-tail-label"> <input type="text" disabled="disabled" placeholder="-" aria-labelledby="vector-prop-tail-label">
</div> </div>
<div class="vector-prop vector-prop-length"> <div class="vector-prop vector-prop-length">
<span id="vector-prop-length-label"> <span id="vector-prop-length-label">
{% trans "length" %}: {% trans "length" %}:
</span> </span>
<input type="text" value="-" aria-labelledby="vector-prop-length-label"> <input type="text" disabled="disabled" placeholder="-" aria-labelledby="vector-prop-length-label">
</div> </div>
</div> </div>
<div class="row"> <div class="row">
...@@ -88,13 +88,13 @@ ...@@ -88,13 +88,13 @@
<span id="vector-prop-angle-label"> <span id="vector-prop-angle-label">
{% trans "angle" %}: {% trans "angle" %}:
</span> </span>
<input type="text" value="-" aria-labelledby="vector-prop-angle-label"> <input type="text" disabled="disabled" placeholder="-" aria-labelledby="vector-prop-angle-label">
</div> </div>
<div class="vector-prop vector-prop-slope"> <div class="vector-prop vector-prop-slope">
<span id="vector-prop-slope-label"> <span id="vector-prop-slope-label">
{% trans "slope" %}: {% trans "slope" %}:
</span> </span>
<input type="text" value="-" aria-labelledby="vector-prop-slope-label" disabled="disabled"> <input type="text" disabled="disabled" placeholder="-" aria-labelledby="vector-prop-slope-label">
</div> </div>
</div> </div>
<div class="row"> <div class="row">
......
...@@ -64,48 +64,81 @@ ...@@ -64,48 +64,81 @@
<li> <li>
<!-- WYSIWYG editor --> <!-- WYSIWYG editor -->
<div class="vectordraw_block vectordraw_edit_block"> <div class="vectordraw_block vectordraw_edit_block">
<h2 aria-describedby="wysiwyg-description">WYSIWYG Editor</h2> <h2 aria-describedby="wysiwyg-description">
WYSIWYG Editor
<button class="info-button" title="Info">
<span class="info-label fa fa-question" aria-hidden="true"></span>
<span class="sr">{% trans "Toggle information about how to use WYSIWYG editor" %}</span>
</button>
</h2>
<p id="wysiwyg-description"> <div id="wysiwyg-description">
{% blocktrans %} <p>
Instead of using the "Vectors" and "Expected result" fields above {% blocktrans %}
to define or modify the set of working vectors and expected result for this exercise, Instead of using the "Vectors" and "Expected result" fields above
you can also use the board below. to define or modify the set of working vectors and expected result for this exercise,
you can also use the board below.
{% endblocktrans %}
</p>
To add a vector, left-click the board where you want the vector to originate. <p>
Keep holding down the left mouse button and drag your mouse pointer across the board {% blocktrans %}
to achieve the desired length and angle for the vector. To add a vector, left-click the board where you want the vector to originate.
Alternatively, you can click "Create vector", which will add a new vector Keep holding down the left mouse button and drag your mouse pointer across the board
that starts at the center of the board and has a predefined length (3) and angle (90). to achieve the desired length and angle for the vector.
Alternatively, you can click "Create vector", which will add a new vector
that starts at the center of the board and has a predefined length (3) and angle (90).
{% endblocktrans %}
</p>
To modify the position of an existing vector, left-click it, hold down the left mouse button, <p>
and move your mouse pointer across the board. To modify length and/or angle, {% blocktrans %}
left-click the tip of the vector and drag your mouse pointer across the board. To modify the position of an existing vector, left-click it, hold down the left mouse button,
Alternatively, you can select an existing vector from the dropdown menu, and move your mouse pointer across the board. To modify length and/or angle,
modify its tail position, length, and angle by changing the values left-click the tip of the vector and drag your mouse pointer across the board.
in the corresponding input fields, and click "Update" to update its position on the board. Alternatively, you can select an existing vector from the dropdown menu,
You can also modify the name and label of a vector using this technique. modify its tail position, length, and angle by changing the values
in the corresponding input fields, and click "Update" to update its position on the board.
You can also modify the name and label of a vector using this technique.
{% endblocktrans %}
</p>
To remove an existing vector, left-click it or select it from the dropdown menu, <p>
then click "Remove". {% blocktrans %}
To remove an existing vector, left-click it or select it from the dropdown menu,
then click "Remove".
{% endblocktrans %}
</p>
When you are done defining the set of working vectors, click "Edit result" <p>
to switch the editor to a mode that will allow you to define the expected result for this exercise. {% blocktrans %}
In this mode you can operate on vectors as described above but you can not add or remove vectors, When you are done defining the set of working vectors, click "Edit result"
and you may not change the name and label of a selected vector. to switch the editor to a mode that will allow you to define the expected result for this exercise.
In this mode you can operate on vectors as described above but you can not add or remove vectors,
and you may not change the name and label of a selected vector.
{% endblocktrans %}
</p>
To define the expected result for the exercise, place each vector where it would be located <p>
in a correct solution. When a vector is selected, use the menu to the right of the board {% blocktrans %}
to select the checks that you would like the grader to perform for this vector, To define the expected result for the exercise, place each vector where it would be located
and click "Update". Note that if you do not select any checks for a given vector, in a correct solution. When a vector is selected and positioned correctly,
no checks at all will be performed for it during grading (i.e., the grader will skip a presence check). use the menu to the right of the board to select the checks that you would like the grader
to perform for this vector, then click "Update" to save expected position and associated checks
for the vector. Note that if you do not select any checks for a given vector,
no checks at all will be performed for it during grading (i.e., the grader will skip a presence check).
{% endblocktrans %}
</p>
Finally, note that if you make changes using the board below, any changes you made <p>
via the "Vectors" and "Expected results" fields above will be overwritten {% blocktrans %}
when you save the settings for this exercise by clicking the "Save" button Finally, note that if you make changes using the board below, any changes you made
at the bottom of this dialog. via the "Vectors" and "Expected results" fields above will be overwritten
{% endblocktrans %} when you save the settings for this exercise by clicking the "Save" button
</p> at the bottom of this dialog.
{% endblocktrans %}
</p>
</div>
<div id="vectordraw"> <div id="vectordraw">
<div class="menu" style="width: {{ self.width }}px;"> <div class="menu" style="width: {{ self.width }}px;">
...@@ -134,7 +167,7 @@ ...@@ -134,7 +167,7 @@
<span id="vector-prop-name-label"> <span id="vector-prop-name-label">
{% trans "name" %}: {% trans "name" %}:
</span> </span>
<input type="text" value="-" aria-labelledby="vector-prop-name-label"> <input type="text" disabled="disabled" placeholder="-" aria-labelledby="vector-prop-name-label">
</div> </div>
</div> </div>
<div class="row"> <div class="row">
...@@ -142,13 +175,13 @@ ...@@ -142,13 +175,13 @@
<span id="vector-prop-label-label"> <span id="vector-prop-label-label">
{% trans "label" %}: {% trans "label" %}:
</span> </span>
<input type="text" value="-" aria-labelledby="vector-prop-label-label"> <input type="text" disabled="disabled" placeholder="-" aria-labelledby="vector-prop-label-label">
</div> </div>
<div class="vector-prop vector-prop-tail"> <div class="vector-prop vector-prop-tail">
<span id="vector-prop-tail-label"> <span id="vector-prop-tail-label">
{% trans "tail position" %}: {% trans "tail position" %}:
</span> </span>
<input type="text" value="-" aria-labelledby="vector-prop-tail-label"> <input type="text" disabled="disabled" placeholder="-" aria-labelledby="vector-prop-tail-label">
</div> </div>
</div> </div>
<div class="row"> <div class="row">
...@@ -156,13 +189,13 @@ ...@@ -156,13 +189,13 @@
<span id="vector-prop-length-label"> <span id="vector-prop-length-label">
{% trans "length" %}: {% trans "length" %}:
</span> </span>
<input type="text" value="-" aria-labelledby="vector-prop-length-label"> <input type="text" disabled="disabled" placeholder="-" aria-labelledby="vector-prop-length-label">
</div> </div>
<div class="vector-prop vector-prop-angle"> <div class="vector-prop vector-prop-angle">
<span id="vector-prop-angle-label"> <span id="vector-prop-angle-label">
{% trans "angle" %}: {% trans "angle" %}:
</span> </span>
<input type="text" value="-" aria-labelledby="vector-prop-angle-label"> <input type="text" disabled="disabled" placeholder="-" aria-labelledby="vector-prop-angle-label">
</div> </div>
</div> </div>
<div class="row"> <div class="row">
...@@ -171,6 +204,9 @@ ...@@ -171,6 +204,9 @@
<span class="update-label" aria-hidden="true">{% trans "Update" %}</span> <span class="update-label" aria-hidden="true">{% trans "Update" %}</span>
<span class="sr">{% trans "Update properties of selected element" %}</span> <span class="sr">{% trans "Update properties of selected element" %}</span>
</button> </button>
<span class="update-pending">
{% trans "Pending changes." %}
</span>
<span class="update-error">{% trans "Invalid input." %}</span> <span class="update-error">{% trans "Invalid input." %}</span>
</div> </div>
<div class="vector-prop vector-remove"> <div class="vector-prop vector-remove">
...@@ -194,13 +230,13 @@ ...@@ -194,13 +230,13 @@
<span id="tail-check-label"> <span id="tail-check-label">
{% trans "check tail" %}: {% trans "check tail" %}:
</span> </span>
<input type="checkbox" aria-labelledby="tail-check-label"> <input type="checkbox" disabled="disabled" aria-labelledby="tail-check-label">
</div> </div>
<div class="row"> <div class="row">
<span id="tail-tolerance-label"> <span id="tail-tolerance-label">
{% trans "tolerance" %}: {% trans "tolerance" %}:
</span> </span>
<input type="text" value="1.0" aria-labelledby="tail-tolerance-label"> <input type="number" disabled="disabled" min="0" step="0.1" placeholder="-" aria-labelledby="tail-tolerance-label">
</div> </div>
</div> </div>
<div class="check" id="check-tip"> <div class="check" id="check-tip">
...@@ -208,13 +244,13 @@ ...@@ -208,13 +244,13 @@
<span id="tip-check-label"> <span id="tip-check-label">
{% trans "check tip" %}: {% trans "check tip" %}:
</span> </span>
<input type="checkbox" aria-labelledby="tip-check-label"> <input type="checkbox" disabled="disabled" aria-labelledby="tip-check-label">
</div> </div>
<div class="row"> <div class="row">
<span id="tip-tolerance-label"> <span id="tip-tolerance-label">
{% trans "tolerance" %}: {% trans "tolerance" %}:
</span> </span>
<input type="text" value="1.0" aria-labelledby="tip-tolerance-label"> <input type="number" disabled="disabled" min="0" step="0.1" placeholder="-" aria-labelledby="tip-tolerance-label">
</div> </div>
</div> </div>
<div class="check" id="check-tail_x"> <div class="check" id="check-tail_x">
...@@ -222,13 +258,13 @@ ...@@ -222,13 +258,13 @@
<span id="tail-x-check-label"> <span id="tail-x-check-label">
{% trans "check tail(x)" %}: {% trans "check tail(x)" %}:
</span> </span>
<input type="checkbox" aria-labelledby="tail-x-check-label"> <input type="checkbox" disabled="disabled" aria-labelledby="tail-x-check-label">
</div> </div>
<div class="row"> <div class="row">
<span id="tail-x-tolerance-label"> <span id="tail-x-tolerance-label">
{% trans "tolerance" %}: {% trans "tolerance" %}:
</span> </span>
<input type="text" value="1.0" aria-labelledby="tail-x-tolerance-label"> <input type="number" disabled="disabled" min="0" step="0.1" placeholder="-" aria-labelledby="tail-x-tolerance-label">
</div> </div>
</div> </div>
<div class="check" id="check-tail_y"> <div class="check" id="check-tail_y">
...@@ -236,13 +272,13 @@ ...@@ -236,13 +272,13 @@
<span id="tail-y-check-label"> <span id="tail-y-check-label">
{% trans "check tail(y)" %}: {% trans "check tail(y)" %}:
</span> </span>
<input type="checkbox" aria-labelledby="tail-y-check-label"> <input type="checkbox" disabled="disabled" aria-labelledby="tail-y-check-label">
</div> </div>
<div class="row"> <div class="row">
<span id="tail-y-tolerance-label"> <span id="tail-y-tolerance-label">
{% trans "tolerance" %}: {% trans "tolerance" %}:
</span> </span>
<input type="text" value="1.0" aria-labelledby="tail-y-tolerance-label"> <input type="number" disabled="disabled" min="0" step="0.1" placeholder="-" aria-labelledby="tail-y-tolerance-label">
</div> </div>
</div> </div>
<div class="check" id="check-tip_x"> <div class="check" id="check-tip_x">
...@@ -250,13 +286,13 @@ ...@@ -250,13 +286,13 @@
<span id="tip-x-check-label"> <span id="tip-x-check-label">
{% trans "check tip(x)" %}: {% trans "check tip(x)" %}:
</span> </span>
<input type="checkbox" aria-labelledby="tip-x-check-label"> <input type="checkbox" disabled="disabled" aria-labelledby="tip-x-check-label">
</div> </div>
<div class="row"> <div class="row">
<span id="tip-x-tolerance-label"> <span id="tip-x-tolerance-label">
{% trans "tolerance" %}: {% trans "tolerance" %}:
</span> </span>
<input type="text" value="1.0" aria-labelledby="tip-x-tolerance-label"> <input type="number" disabled="disabled" min="0" step="0.1" placeholder="-" aria-labelledby="tip-x-tolerance-label">
</div> </div>
</div> </div>
<div class="check" id="check-tip_y"> <div class="check" id="check-tip_y">
...@@ -264,13 +300,13 @@ ...@@ -264,13 +300,13 @@
<span id="tip-y-check-label"> <span id="tip-y-check-label">
{% trans "check tip(y)" %}: {% trans "check tip(y)" %}:
</span> </span>
<input type="checkbox" aria-labelledby="tip-y-check-label"> <input type="checkbox" disabled="disabled" aria-labelledby="tip-y-check-label">
</div> </div>
<div class="row"> <div class="row">
<span id="tip-y-tolerance-label"> <span id="tip-y-tolerance-label">
{% trans "tolerance" %}: {% trans "tolerance" %}:
</span> </span>
<input type="text" value="1.0" aria-labelledby="tip-y-tolerance-label"> <input type="number" disabled="disabled" min="0" step="0.1" placeholder="-" aria-labelledby="tip-y-tolerance-label">
</div> </div>
</div> </div>
<div class="check" id="check-coords"> <div class="check" id="check-coords">
...@@ -278,13 +314,13 @@ ...@@ -278,13 +314,13 @@
<span id="coords-check-label"> <span id="coords-check-label">
{% trans "check coords" %}: {% trans "check coords" %}:
</span> </span>
<input type="checkbox" aria-labelledby="coords-check-label"> <input type="checkbox" disabled="disabled" aria-labelledby="coords-check-label">
</div> </div>
<div class="row"> <div class="row">
<span id="coords-tolerance-label"> <span id="coords-tolerance-label">
{% trans "tolerance" %}: {% trans "tolerance" %}:
</span> </span>
<input type="text" value="1.0" aria-labelledby="coords-tolerance-label"> <input type="number" disabled="disabled" min="0" step="0.1" placeholder="-" aria-labelledby="coords-tolerance-label">
</div> </div>
</div> </div>
<div class="check" id="check-length"> <div class="check" id="check-length">
...@@ -292,13 +328,13 @@ ...@@ -292,13 +328,13 @@
<span id="length-check-label"> <span id="length-check-label">
{% trans "check length" %}: {% trans "check length" %}:
</span> </span>
<input type="checkbox" aria-labelledby="length-check-label"> <input type="checkbox" disabled="disabled" aria-labelledby="length-check-label">
</div> </div>
<div class="row"> <div class="row">
<span id="length-tolerance-label"> <span id="length-tolerance-label">
{% trans "tolerance" %}: {% trans "tolerance" %}:
</span> </span>
<input type="text" value="1.0" aria-labelledby="length-tolerance-label"> <input type="number" disabled="disabled" min="0" step="0.1" placeholder="-" aria-labelledby="length-tolerance-label">
</div> </div>
</div> </div>
<div class="check" id="check-angle"> <div class="check" id="check-angle">
...@@ -306,13 +342,13 @@ ...@@ -306,13 +342,13 @@
<span id="angle-check-label"> <span id="angle-check-label">
{% trans "check angle" %}: {% trans "check angle" %}:
</span> </span>
<input type="checkbox" aria-labelledby="angle-check-label"> <input type="checkbox" disabled="disabled" aria-labelledby="angle-check-label">
</div> </div>
<div class="row"> <div class="row">
<span id="angle-tolerance-label"> <span id="angle-tolerance-label">
{% trans "tolerance" %}: {% trans "tolerance" %}:
</span> </span>
<input type="text" value="2.0" aria-labelledby="angle-tolerance-label"> <input type="number" disabled="disabled" min="0" step="0.1" placeholder="-" aria-labelledby="angle-tolerance-label">
</div> </div>
</div> </div>
</div> </div>
......
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