Drag and Drop: refactoring + preparing for reuse of draggables.
This commit is contained in:
committed by
Alexander Kryklia
parent
e47f0e45f2
commit
79f5e98dfc
@@ -26,7 +26,7 @@ define(['logme'], function (logme) {
|
||||
|
||||
state.baseImageEl.attr(
|
||||
'src',
|
||||
state.config.base_image
|
||||
state.config.baseImage
|
||||
);
|
||||
state.baseImageEl.load(function () {
|
||||
baseImageElContainer.css('width', this.width);
|
||||
@@ -43,11 +43,11 @@ define(['logme'], function (logme) {
|
||||
});
|
||||
state.baseImageEl.error(function () {
|
||||
logme(
|
||||
'ERROR: Image "' + state.config.base_image + '" was not found!'
|
||||
'ERROR: Image "' + state.config.baseImage + '" was not found!'
|
||||
);
|
||||
baseImageElContainer.html(
|
||||
'<span style="color: red;">' +
|
||||
'ERROR: Image "' + state.config.base_image + '" was not found!' +
|
||||
'ERROR: Image "' + state.config.baseImage + '" was not found!' +
|
||||
'</span>'
|
||||
);
|
||||
baseImageElContainer.appendTo(state.containerEl);
|
||||
|
||||
@@ -8,154 +8,218 @@ define(['logme'], function (logme) {
|
||||
return configParser;
|
||||
|
||||
function configParser(config, state) {
|
||||
var returnStatus;
|
||||
|
||||
returnStatus = true;
|
||||
|
||||
state.config = {
|
||||
'draggables': [],
|
||||
'baseImage': '',
|
||||
'targets': [],
|
||||
'base_image': ''
|
||||
'onePerTarget': null,
|
||||
'targetOutline': true,
|
||||
'labelBgColor': '#d6d6d6',
|
||||
|
||||
'individualTargets': null,
|
||||
|
||||
'errors': 0 // Number of errors found while parsing config.
|
||||
};
|
||||
|
||||
if ($.isArray(config.draggables) === true) {
|
||||
getDraggables(state, config);
|
||||
getBaseImage(state, config);
|
||||
getTargets(state, config);
|
||||
getOnePerTarget(state, config);
|
||||
getTargetOutline(state, config);
|
||||
getLabelBgColor(state, config);
|
||||
|
||||
setIndividualTargets(state);
|
||||
|
||||
if (state.config.errors !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getDraggables(state, config) {
|
||||
if (config.hasOwnProperty('draggables') === false) {
|
||||
logme('ERROR: "config" does not have a property "draggables".');
|
||||
state.config.errors += 1;
|
||||
} else if ($.isArray(config.draggables) === true) {
|
||||
(function (i) {
|
||||
while (i < config.draggables.length) {
|
||||
if (processDraggable(config.draggables[i]) !== true) {
|
||||
returnStatus = false;
|
||||
if (processDraggable(state, config.draggables[i]) !== true) {
|
||||
state.config.errors += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}(0));
|
||||
} else if ($.isPlainObject(config.draggables) === true) {
|
||||
if (processDraggable(config.draggables) !== true) {
|
||||
returnStatus = false;
|
||||
if (processDraggable(state, config.draggables) !== true) {
|
||||
state.config.errors += 1;
|
||||
}
|
||||
} else {
|
||||
logme('ERROR: The type of config.draggables is no supported.');
|
||||
returnStatus = false;
|
||||
state.config.errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof config.base_image === 'string') {
|
||||
state.config.base_image = config.base_image;
|
||||
function getBaseImage(state, config) {
|
||||
if (config.hasOwnProperty('base_image') === false) {
|
||||
logme('ERROR: "config" does not have a property "base_image".');
|
||||
state.config.errors += 1;
|
||||
} else if (typeof config.base_image === 'string') {
|
||||
state.config.baseImage = config.base_image;
|
||||
} else {
|
||||
logme('ERROR: Property config.base_image is not of type "string".');
|
||||
returnStatus = false;
|
||||
state.config.errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($.isArray(config.targets) === true) {
|
||||
function getTargets(state, config) {
|
||||
if (config.hasOwnProperty('targets') === false) {
|
||||
// It is possible that no "targets" were specified. This is not an error.
|
||||
// In this case the default value of "[]" (empty array) will be used.
|
||||
// Draggables can be positioned anywhere on the image, and the server will
|
||||
// get an answer in the form of (x, y) coordinates for each draggable.
|
||||
} else if ($.isArray(config.targets) === true) {
|
||||
(function (i) {
|
||||
while (i < config.targets.length) {
|
||||
if (processTarget(config.targets[i]) !== true) {
|
||||
returnStatus = false;
|
||||
if (processTarget(state, config.targets[i]) !== true) {
|
||||
state.config.errors += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}(0));
|
||||
} else if ($.isPlainObject(config.targets) === true) {
|
||||
if (processTarget(config.targets) !== true) {
|
||||
returnStatus = false;
|
||||
if (processTarget(state, config.targets) !== true) {
|
||||
state.config.errors += 1;
|
||||
}
|
||||
} else if (typeof config.targets !== 'undefined') {
|
||||
} else {
|
||||
logme('ERROR: Property config.targets is not of a supported type.');
|
||||
returnStatus = false;
|
||||
state.config.errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof config.one_per_target === 'string') {
|
||||
function getOnePerTarget(state, config) {
|
||||
if (config.hasOwnProperty('one_per_target') === false) {
|
||||
logme('ERROR: "config" does not have a property "one_per_target".');
|
||||
state.config.errors += 1;
|
||||
} else if (typeof config.one_per_target === 'string') {
|
||||
if (config.one_per_target.toLowerCase() === 'true') {
|
||||
state.config.one_per_target = true;
|
||||
state.config.onePerTarget = true;
|
||||
} else if (config.one_per_target.toLowerCase() === 'false') {
|
||||
state.config.one_per_target = false;
|
||||
state.config.onePerTarget = false;
|
||||
} else {
|
||||
logme('ERROR: Property config.one_per_target can either be "true", or "false".');
|
||||
returnStatus = false;
|
||||
state.config.errors += 1;
|
||||
}
|
||||
} else if (typeof config.one_per_target !== 'undefined') {
|
||||
} else {
|
||||
logme('ERROR: Property config.one_per_target is not of a supported type.');
|
||||
returnStatus = false;
|
||||
state.config.errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof config.target_outline === 'string') {
|
||||
function getTargetOutline(state, config) {
|
||||
if (config.hasOwnProperty('target_outline') === false) {
|
||||
// It is possible that no "target_outline" was specified. This is not an error.
|
||||
// In this case the default value of 'true' (boolean) will be used.
|
||||
} else if (typeof config.target_outline === 'string') {
|
||||
if (config.target_outline.toLowerCase() === 'true') {
|
||||
state.config.targetOutline = true;
|
||||
} else if (config.target_outline.toLowerCase() === 'false') {
|
||||
state.config.targetOutline = false;
|
||||
} else {
|
||||
logme('ERROR: Property config.target_outline can either be "true", or "false".');
|
||||
returnStatus = false;
|
||||
state.config.errors += 1;
|
||||
}
|
||||
} else if (typeof config.target_outline !== 'undefined') {
|
||||
} else {
|
||||
logme('ERROR: Property config.target_outline is not of a supported type.');
|
||||
returnStatus = false;
|
||||
state.config.errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
state.config.labelBgColor = '#d6d6d6';
|
||||
if (typeof config.label_bg_color === 'string') {
|
||||
function getLabelBgColor(state, config) {
|
||||
if (config.hasOwnProperty('label_bg_color') === false) {
|
||||
// It is possible that no "label_bg_color" was specified. This is not an error.
|
||||
// In this case the default value of '#d6d6d6' (string) will be used.
|
||||
} else if (typeof config.label_bg_color === 'string') {
|
||||
state.config.labelBgColor = config.label_bg_color;
|
||||
} else if (typeof config.label_bg_color !== 'undefined') {
|
||||
} else {
|
||||
logme('ERROR: Property config.label_bg_color is not of a supported type.');
|
||||
returnStatus = false;
|
||||
}
|
||||
}
|
||||
|
||||
function setIndividualTargets(state) {
|
||||
if (state.config.targets.length === 0) {
|
||||
state.individualTargets = false;
|
||||
state.config.individualTargets = false;
|
||||
} else {
|
||||
state.individualTargets = true;
|
||||
state.config.individualTargets = true;
|
||||
}
|
||||
}
|
||||
|
||||
function processDraggable(state, obj) {
|
||||
if (!attrIsString(obj, 'id')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!attrIsString(obj, 'icon')) {
|
||||
return false;
|
||||
}
|
||||
if (!attrIsString(obj, 'label')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state.config.draggables.push(obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function processTarget(state, obj) {
|
||||
if (!attrIsString(obj, 'id')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!attrIsInteger(obj, 'w')) {
|
||||
return false;
|
||||
}
|
||||
if (!attrIsInteger(obj, 'h')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!attrIsInteger(obj, 'x')) {
|
||||
return false;
|
||||
}
|
||||
if (!attrIsInteger(obj, 'y')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state.config.targets.push(obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function attrIsString(obj, attr) {
|
||||
if (typeof obj[attr] !== 'string') {
|
||||
logme('ERROR: Attribute "obj.' + attr + '" is not a string.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function processDraggable(obj) {
|
||||
if (!attrIsString(obj, 'id')) { return false; }
|
||||
function attrIsInteger(obj, attr) {
|
||||
var tempInt;
|
||||
|
||||
if (!attrIsString(obj, 'icon')) { return false; }
|
||||
if (!attrIsString(obj, 'label')) { return false; }
|
||||
tempInt = parseInt(obj[attr], 10);
|
||||
|
||||
state.config.draggables.push(obj);
|
||||
if (isFinite(tempInt) === false) {
|
||||
logme('ERROR: Attribute "obj.' + attr + '" is not an integer.');
|
||||
|
||||
true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function processTarget(obj) {
|
||||
if (!attrIsString(obj, 'id')) { return false; }
|
||||
obj[attr] = tempInt;
|
||||
|
||||
if (!attrIsInteger(obj, 'w')) { return false; }
|
||||
if (!attrIsInteger(obj, 'h')) { return false; }
|
||||
|
||||
if (!attrIsInteger(obj, 'x')) { return false; }
|
||||
if (!attrIsInteger(obj, 'y')) { return false; }
|
||||
|
||||
state.config.targets.push(obj);
|
||||
|
||||
true;
|
||||
|
||||
}
|
||||
|
||||
function attrIsString(obj, attr) {
|
||||
if (typeof obj[attr] !== 'string') {
|
||||
logme('ERROR: Attribute "obj.' + attr + '" is not a string.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function attrIsInteger(obj, attr) {
|
||||
var tempInt;
|
||||
|
||||
tempInt = parseInt(obj[attr], 10);
|
||||
|
||||
if (isFinite(tempInt) === false) {
|
||||
logme('ERROR: Attribute "obj.' + attr + '" is not an integer.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
obj[attr] = tempInt;
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
};
|
||||
|
||||
function init(state) {
|
||||
logme('Draggables.init; state = ', state);
|
||||
|
||||
state.draggables = [];
|
||||
state.numDraggablesInSlider = 0;
|
||||
state.currentMovingDraggable = null;
|
||||
@@ -65,13 +63,137 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
}
|
||||
}
|
||||
|
||||
function moveDraggableToXY(newPosition) {
|
||||
var self, offset;
|
||||
|
||||
if (this.hasLoaded === false) {
|
||||
self = this;
|
||||
|
||||
setTimeout(function () {
|
||||
self.moveDraggableToXY(newPosition);
|
||||
}, 50);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
if (this.state.config.targetOutline === true) {
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
this.inContainer = false;
|
||||
this.containerEl.hide();
|
||||
|
||||
this.iconEl.detach();
|
||||
this.iconEl.css('background-color', this.iconElBGColor);
|
||||
this.iconEl.css('padding-left', this.iconElPadding);
|
||||
this.iconEl.css('padding-right', this.iconElPadding);
|
||||
this.iconEl.css('border', this.iconElBorder);
|
||||
this.iconEl.css('width', this.iconWidth);
|
||||
this.iconEl.css('height', this.iconHeight);
|
||||
this.iconEl.css(
|
||||
'left',
|
||||
newPosition.x - this.iconWidth * 0.5 + offset - this.iconElLeftOffset
|
||||
);
|
||||
this.iconEl.css(
|
||||
'top',
|
||||
newPosition.y - this.iconHeight * 0.5 + offset
|
||||
);
|
||||
this.iconEl.appendTo(this.state.baseImageEl.parent());
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.detach();
|
||||
this.labelEl.css('background-color', this.state.config.labelBgColor);
|
||||
this.labelEl.css('padding-left', 8);
|
||||
this.labelEl.css('padding-right', 8);
|
||||
this.labelEl.css('border', '1px solid black');
|
||||
this.labelEl.css(
|
||||
'left',
|
||||
newPosition.x - this.labelWidth * 0.5 + offset - 9 // Account for padding, border.
|
||||
);
|
||||
this.labelEl.css(
|
||||
'top',
|
||||
newPosition.y - this.iconHeight * 0.5 + this.iconHeight + 5 + offset
|
||||
);
|
||||
this.labelEl.appendTo(this.state.baseImageEl.parent());
|
||||
}
|
||||
|
||||
this.x = newPosition.x;
|
||||
this.y = newPosition.y;
|
||||
|
||||
this.state.numDraggablesInSlider -= 1;
|
||||
this.state.updateArrowOpacity();
|
||||
}
|
||||
|
||||
function moveDraggableToTarget(target) {
|
||||
var self, offset;
|
||||
|
||||
if (this.hasLoaded === false) {
|
||||
self = this;
|
||||
|
||||
setTimeout(function () {
|
||||
self.moveDraggableToTarget(target);
|
||||
}, 50);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
if (this.state.config.targetOutline === true) {
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
this.inContainer = false;
|
||||
this.containerEl.hide();
|
||||
|
||||
this.iconEl.detach();
|
||||
this.iconEl.css('background-color', this.iconElBGColor);
|
||||
this.iconEl.css('padding-left', this.iconElPadding);
|
||||
this.iconEl.css('padding-right', this.iconElPadding);
|
||||
this.iconEl.css('border', this.iconElBorder);
|
||||
this.iconEl.css('width', this.iconWidth);
|
||||
this.iconEl.css('height', this.iconHeight);
|
||||
this.iconEl.css(
|
||||
'left',
|
||||
target.offset.left + 0.5 * target.w - this.iconWidth * 0.5 + offset - this.iconElLeftOffset
|
||||
);
|
||||
this.iconEl.css(
|
||||
'top',
|
||||
target.offset.top + 0.5 * target.h - this.iconHeight * 0.5 + offset
|
||||
);
|
||||
this.iconEl.appendTo(this.state.baseImageEl.parent());
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.detach();
|
||||
this.labelEl.css('background-color', this.state.config.labelBgColor);
|
||||
this.labelEl.css('padding-left', 8);
|
||||
this.labelEl.css('padding-right', 8);
|
||||
this.labelEl.css('border', '1px solid black');
|
||||
this.labelEl.css(
|
||||
'left',
|
||||
target.offset.left + 0.5 * target.w - this.labelWidth * 0.5 + offset - 9 // Account for padding, border.
|
||||
);
|
||||
this.labelEl.css(
|
||||
'top',
|
||||
target.offset.top + 0.5 * target.h + this.iconHeight * 0.5 + 5 + offset
|
||||
);
|
||||
this.labelEl.appendTo(this.state.baseImageEl.parent());
|
||||
}
|
||||
|
||||
this.onTarget = target;
|
||||
target.draggable.push(this.id);
|
||||
|
||||
if (target.numTextEl !== null) {
|
||||
target.updateNumTextEl();
|
||||
}
|
||||
|
||||
this.state.numDraggablesInSlider -= 1;
|
||||
this.state.updateArrowOpacity();
|
||||
}
|
||||
|
||||
function processDraggable(state, obj, objIndex) {
|
||||
var draggableObj;
|
||||
|
||||
logme('processDraggable; state = ', state);
|
||||
|
||||
logme('Processing draggable #' + objIndex);
|
||||
|
||||
draggableObj = {
|
||||
'zIndex': objIndex,
|
||||
'oldZIndex': objIndex,
|
||||
@@ -91,7 +213,10 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
'checkIfOnTarget': checkIfOnTarget,
|
||||
'snapToTarget': snapToTarget,
|
||||
'correctZIndexes': correctZIndexes,
|
||||
'moveBackToSlider': moveBackToSlider
|
||||
'moveBackToSlider': moveBackToSlider,
|
||||
|
||||
'moveDraggableToTarget': moveDraggableToTarget,
|
||||
'moveDraggableToXY': moveDraggableToXY
|
||||
};
|
||||
|
||||
draggableObj.containerEl = $(
|
||||
@@ -334,7 +459,7 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
this.iconHeight * 0.5
|
||||
);
|
||||
this.iconEl.appendTo(
|
||||
state.baseImageEl.parent()
|
||||
this.state.baseImageEl.parent()
|
||||
);
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
@@ -447,7 +572,7 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
this.mousePressed = false;
|
||||
positionIE = this.iconEl.position();
|
||||
|
||||
if (this.state.individualTargets === true) {
|
||||
if (this.state.config.individualTargets === true) {
|
||||
if (this.checkIfOnTarget(positionIE) === true) {
|
||||
this.correctZIndexes();
|
||||
} else {
|
||||
@@ -486,7 +611,7 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
}
|
||||
|
||||
this.state.updateArrowOpacity();
|
||||
updateInput(this.state);
|
||||
updateInput.update(this.state);
|
||||
}
|
||||
|
||||
function removeObjIdFromTarget() {
|
||||
@@ -532,7 +657,7 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
// (with an ID different from the one we are checking
|
||||
// against), then go to next target.
|
||||
if (
|
||||
(this.state.config.one_per_target === true) &&
|
||||
(this.state.config.onePerTarget === true) &&
|
||||
(target.draggable.length === 1) &&
|
||||
(target.draggable[0] !== this.id)
|
||||
) {
|
||||
@@ -652,7 +777,7 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
function correctZIndexes() {
|
||||
var draggablesInMe, c1, c2, highestZIndex;
|
||||
|
||||
if (this.state.individualTargets === true) {
|
||||
if (this.state.config.individualTargets === true) {
|
||||
if (this.onTarget.draggable.length > 0) {
|
||||
draggablesInMe = [];
|
||||
|
||||
|
||||
@@ -65,11 +65,11 @@ define(
|
||||
Scroller(state);
|
||||
Draggables.init(state);
|
||||
|
||||
logme('After Draggables.init(state); state = ', state);
|
||||
|
||||
// Update the input element, checking first that it is not filled with
|
||||
// an answer from the server.
|
||||
updateInput(state, true);
|
||||
if (updateInput.check(state) === false) {
|
||||
updateInput.update(state);
|
||||
}
|
||||
}());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ define(['logme'], function (logme) {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
if (state.config.one_per_target === false) {
|
||||
if (state.config.onePerTarget === false) {
|
||||
numTextEl = $(
|
||||
'<div ' +
|
||||
'style=" ' +
|
||||
@@ -86,7 +86,7 @@ define(['logme'], function (logme) {
|
||||
'updateNumTextEl': updateNumTextEl
|
||||
};
|
||||
|
||||
if (state.config.one_per_target === false) {
|
||||
if (state.config.onePerTarget === false) {
|
||||
numTextEl.appendTo(state.baseImageEl.parent());
|
||||
numTextEl.mousedown(function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -5,363 +5,209 @@
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(['logme'], function (logme) {
|
||||
return updateInput;
|
||||
return {
|
||||
'check': check,
|
||||
'update': update
|
||||
};
|
||||
|
||||
function updateInput(state, checkFirst) {
|
||||
var inputEl, stateStr, targets, draggables, c1, c2, tempObj;
|
||||
function update(state) {
|
||||
var draggables, tempObj;
|
||||
|
||||
logme('updateInput; state = ', state);
|
||||
|
||||
if (checkFirst === true) {
|
||||
if (checkIfHasAnswer() === true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
logme('state.problemId = ' + state.problemId);
|
||||
|
||||
draggables = [];
|
||||
|
||||
if (state.individualTargets === false) {
|
||||
for (c1 = 0; c1 < state.draggables.length; c1++) {
|
||||
if (state.draggables[c1].x !== -1) {
|
||||
tempObj = {};
|
||||
tempObj[state.draggables[c1].id] = [
|
||||
state.draggables[c1].x,
|
||||
state.draggables[c1].y
|
||||
];
|
||||
if (state.config.individualTargets === false) {
|
||||
(function (c1) {
|
||||
while (c1 < state.draggables.length) {
|
||||
if (state.draggables[c1].x !== -1) {
|
||||
tempObj = {};
|
||||
tempObj[state.draggables[c1].id] = [
|
||||
state.draggables[c1].x,
|
||||
state.draggables[c1].y
|
||||
];
|
||||
draggables.push(tempObj);
|
||||
tempObj = null;
|
||||
}
|
||||
|
||||
draggables.push(tempObj);
|
||||
c1 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
stateStr = JSON.stringify({
|
||||
'use_targets': false,
|
||||
'draggables': draggables
|
||||
});
|
||||
}(0));
|
||||
} else {
|
||||
for (c1 = 0; c1 < state.targets.length; c1++) {
|
||||
for (c2 = 0; c2 < state.targets[c1].draggable.length; c2++) {
|
||||
tempObj = {};
|
||||
tempObj[state.targets[c1].draggable[c2]] =
|
||||
state.targets[c1].id;
|
||||
(function (c1) {
|
||||
while (c1 < state.targets.length) {
|
||||
(function (c2) {
|
||||
while (c2 < state.targets[c1].draggable.length) {
|
||||
tempObj = {};
|
||||
tempObj[state.targets[c1].draggable[c2]] = state.targets[c1].id;
|
||||
draggables.push(tempObj);
|
||||
tempObj = null;
|
||||
|
||||
draggables.push(tempObj);
|
||||
c2 += 1;
|
||||
}
|
||||
}(0));
|
||||
|
||||
c1 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
stateStr = JSON.stringify({
|
||||
'use_targets': true,
|
||||
'draggables': draggables
|
||||
});
|
||||
}(0));
|
||||
}
|
||||
|
||||
inputEl = $('#input_' + state.problemId);
|
||||
inputEl.val(stateStr);
|
||||
$('#input_' + state.problemId).val(JSON.stringify({'draggables': draggables}));
|
||||
}
|
||||
|
||||
return;
|
||||
// Check if input has an answer from server. If yes, then position
|
||||
// all draggables according to answer.
|
||||
function check(state) {
|
||||
var inputElVal;
|
||||
|
||||
// Check if input has an answer from server. If yes, then position
|
||||
// all draggables according to answer.
|
||||
function checkIfHasAnswer() {
|
||||
var inputElVal;
|
||||
|
||||
inputElVal = $('#input_' + state.problemId).val();
|
||||
if (inputElVal.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
repositionDraggables(JSON.parse(inputElVal));
|
||||
|
||||
return true;
|
||||
inputElVal = $('#input_' + state.problemId).val();
|
||||
if (inputElVal.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function repositionDraggables(answer) {
|
||||
var draggableId, draggable, targetId, target, c1, offset;
|
||||
repositionDraggables(state, JSON.parse(inputElVal));
|
||||
|
||||
offset = 0;
|
||||
if (state.config.targetOutline === true) {
|
||||
offset = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
function getUseTargets(answer) {
|
||||
if ($.isArray(answer.draggables) === false) {
|
||||
logme('ERROR: answer.draggables is not an array.');
|
||||
|
||||
return;
|
||||
} else if (answer.draggables.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($.isPlainObject(answer.draggables[0]) === false) {
|
||||
logme('ERROR: answer.draggables array does not contain objects.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (c1 in answer.draggables[0]) {
|
||||
if (answer.draggables[0].hasOwnProperty(c1) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
(
|
||||
(typeof answer.use_targets === 'boolean') &&
|
||||
(answer.use_targets === true)
|
||||
) ||
|
||||
(
|
||||
(typeof answer.use_targets === 'string') &&
|
||||
(answer.use_targets === 'true')
|
||||
)
|
||||
) {
|
||||
for (c1 = 0; c1 < answer.draggables.length; c1++) {
|
||||
for (draggableId in answer.draggables[c1]) {
|
||||
if (
|
||||
(draggable = getDraggableById(draggableId)) ===
|
||||
null
|
||||
) {
|
||||
logme(
|
||||
'ERROR: In answer there exists a ' +
|
||||
'draggable ID "' + draggableId + '". No ' +
|
||||
'draggable with this ID could be found.'
|
||||
);
|
||||
if (typeof answer.draggables[0][c1] === 'string') {
|
||||
// use_targets = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
targetId = answer.draggables[c1][draggableId];
|
||||
if ((target = getTargetById(targetId)) === null) {
|
||||
logme(
|
||||
'ERROR: In answer there exists a target ' +
|
||||
'ID "' + targetId + '". No target with this ' +
|
||||
'ID could be found.'
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
(function (draggableId, draggable, targetId, target) {
|
||||
moveDraggableToBaseImage();
|
||||
return;
|
||||
|
||||
function moveDraggableToBaseImage() {
|
||||
if (draggable.hasLoaded === false) {
|
||||
setTimeout(moveDraggableToBaseImage, 50);
|
||||
return;
|
||||
}
|
||||
|
||||
draggable.inContainer = false;
|
||||
draggable.containerEl.hide();
|
||||
|
||||
draggable.iconEl.detach();
|
||||
draggable.iconEl.css(
|
||||
'background-color', draggable.iconElBGColor
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'padding-left', draggable.iconElPadding
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'padding-right', draggable.iconElPadding
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'border', draggable.iconElBorder
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'width',
|
||||
draggable.iconWidth
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'height',
|
||||
draggable.iconHeight
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'left',
|
||||
target.offset.left + 0.5 * target.w -
|
||||
draggable.iconWidth * 0.5 + offset
|
||||
- draggable.iconElLeftOffset
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'top',
|
||||
target.offset.top + 0.5 * target.h -
|
||||
draggable.iconHeight * 0.5 + offset
|
||||
);
|
||||
draggable.iconEl.appendTo(
|
||||
state.baseImageEl.parent()
|
||||
);
|
||||
|
||||
if (draggable.labelEl !== null) {
|
||||
draggable.labelEl.detach();
|
||||
draggable.labelEl.css(
|
||||
'background-color', state.config.labelBgColor
|
||||
);
|
||||
draggable.labelEl.css(
|
||||
'padding-left', 8
|
||||
);
|
||||
draggable.labelEl.css(
|
||||
'padding-right', 8
|
||||
);
|
||||
draggable.labelEl.css(
|
||||
'border', '1px solid black'
|
||||
);
|
||||
draggable.labelEl.css(
|
||||
'left',
|
||||
target.offset.left + 0.5 * target.w -
|
||||
draggable.labelWidth * 0.5 + offset
|
||||
- 9 // Account for padding, border.
|
||||
);
|
||||
draggable.labelEl.css(
|
||||
'top',
|
||||
target.offset.top + 0.5 * target.h +
|
||||
draggable.iconHeight * 0.5 + 5 +
|
||||
offset
|
||||
);
|
||||
draggable.labelEl.appendTo(
|
||||
state.baseImageEl.parent()
|
||||
);
|
||||
}
|
||||
|
||||
draggable.onTarget = target;
|
||||
target.draggable.push(draggableId);
|
||||
|
||||
if (target.numTextEl !== null) {
|
||||
target.updateNumTextEl();
|
||||
}
|
||||
|
||||
state.numDraggablesInSlider -= 1;
|
||||
state.updateArrowOpacity();
|
||||
}
|
||||
}(draggableId, draggable, targetId, target));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (
|
||||
(
|
||||
(typeof answer.use_targets === 'boolean') &&
|
||||
(answer.use_targets === false)
|
||||
) ||
|
||||
(
|
||||
(typeof answer.use_targets === 'string') &&
|
||||
(answer.use_targets === 'false')
|
||||
)
|
||||
($.isArray(answer.draggables[0][c1]) === true) &&
|
||||
(answer.draggables[0][c1].length === 2)
|
||||
) {
|
||||
for (c1 = 0; c1 < answer.draggables.length; c1++) {
|
||||
for (draggableId in answer.draggables[c1]) {
|
||||
if (
|
||||
(draggable = getDraggableById(draggableId)) ===
|
||||
null
|
||||
) {
|
||||
logme(
|
||||
'ERROR: In answer there exists a ' +
|
||||
'draggable ID "' + draggableId + '". No ' +
|
||||
'draggable with this ID could be found.'
|
||||
);
|
||||
// use_targets = false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
(function (c1, draggableId, draggable) {
|
||||
moveDraggableToBaseImage();
|
||||
return;
|
||||
|
||||
function moveDraggableToBaseImage() {
|
||||
if (draggable.hasLoaded === false) {
|
||||
setTimeout(moveDraggableToBaseImage, 50);
|
||||
return;
|
||||
}
|
||||
|
||||
draggable.inContainer = false;
|
||||
draggable.containerEl.hide();
|
||||
|
||||
draggable.iconEl.detach();
|
||||
draggable.iconEl.css(
|
||||
'background-color', draggable.iconElBGColor
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'padding-left', draggable.iconElPadding
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'padding-right', draggable.iconElPadding
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'border', draggable.iconElBorder
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'width',
|
||||
draggable.iconWidth
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'height',
|
||||
draggable.iconHeight
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'left',
|
||||
answer.draggables[c1][draggableId][0] -
|
||||
draggable.iconWidth * 0.5 + offset
|
||||
- draggable.iconElLeftOffset
|
||||
);
|
||||
draggable.iconEl.css(
|
||||
'top',
|
||||
answer.draggables[c1][draggableId][1] -
|
||||
draggable.iconHeight * 0.5 + offset
|
||||
);
|
||||
draggable.iconEl.appendTo(
|
||||
state.baseImageEl.parent()
|
||||
);
|
||||
|
||||
if (draggable.labelEl !== null) {
|
||||
draggable.labelEl.detach();
|
||||
draggable.labelEl.css(
|
||||
'background-color', state.config.labelBgColor
|
||||
);
|
||||
draggable.labelEl.css(
|
||||
'padding-left', 8
|
||||
);
|
||||
draggable.labelEl.css(
|
||||
'padding-right', 8
|
||||
);
|
||||
draggable.labelEl.css(
|
||||
'border', '1px solid black'
|
||||
);
|
||||
draggable.labelEl.css(
|
||||
'left',
|
||||
answer.draggables[c1][draggableId][0] -
|
||||
draggable.labelWidth * 0.5 + offset
|
||||
- 9 // Account for padding, border.
|
||||
);
|
||||
draggable.labelEl.css(
|
||||
'top',
|
||||
answer.draggables[c1][draggableId][1] -
|
||||
draggable.iconHeight * 0.5 +
|
||||
draggable.iconHeight + 5 + offset
|
||||
);
|
||||
draggable.labelEl.appendTo(
|
||||
state.baseImageEl.parent()
|
||||
);
|
||||
}
|
||||
|
||||
draggable.x =
|
||||
answer.draggables[c1][draggableId][0];
|
||||
draggable.y =
|
||||
answer.draggables[c1][draggableId][1];
|
||||
|
||||
state.numDraggablesInSlider -= 1;
|
||||
state.updateArrowOpacity();
|
||||
}
|
||||
}(c1, draggableId, draggable));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
logme(
|
||||
'ERROR: The type of answer.targets is not supported. ' +
|
||||
'answer.targets = ', answer.targets
|
||||
);
|
||||
logme('ERROR: answer.draggables[0] is inconsidtent.');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logme('ERROR: answer.draggables[0] is an empty object.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
function getDraggableById(id) {
|
||||
var c1;
|
||||
function processAnswerTargets(state, answer) {
|
||||
var draggableId, draggable, targetId, target;
|
||||
|
||||
for (c1 = 0; c1 < state.draggables.length; c1 += 1) {
|
||||
if (state.draggables[c1].id === id) {
|
||||
return state.draggables[c1];
|
||||
(function (c1) {
|
||||
while (c1 < answer.draggables.length) {
|
||||
for (draggableId in answer.draggables[c1]) {
|
||||
if (answer.draggables[c1].hasOwnProperty(draggableId) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((draggable = getById(state, 'draggables', draggableId)) === null) {
|
||||
logme(
|
||||
'ERROR: In answer there exists a ' +
|
||||
'draggable ID "' + draggableId + '". No ' +
|
||||
'draggable with this ID could be found.'
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
targetId = answer.draggables[c1][draggableId];
|
||||
if ((target = getById(state, 'targets', targetId)) === null) {
|
||||
logme(
|
||||
'ERROR: In answer there exists a target ' +
|
||||
'ID "' + targetId + '". No target with this ' +
|
||||
'ID could be found.'
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
draggable.moveDraggableToTarget(target);
|
||||
}
|
||||
|
||||
c1 += 1;
|
||||
}
|
||||
}(0));
|
||||
}
|
||||
|
||||
function processAnswerPositions(state, answer) {
|
||||
var draggableId, draggable;
|
||||
|
||||
(function (c1) {
|
||||
while (c1 < answer.draggables.length) {
|
||||
for (draggableId in answer.draggables[c1]) {
|
||||
if (answer.draggables[c1].hasOwnProperty(draggableId) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((draggable = getById(state, 'draggables', draggableId)) === null) {
|
||||
logme(
|
||||
'ERROR: In answer there exists a ' +
|
||||
'draggable ID "' + draggableId + '". No ' +
|
||||
'draggable with this ID could be found.'
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
draggable.moveDraggableToXY({
|
||||
'x': answer.draggables[c1][draggableId][0],
|
||||
'y': answer.draggables[c1][draggableId][1]
|
||||
});
|
||||
}
|
||||
|
||||
c1 += 1;
|
||||
}
|
||||
}(0));
|
||||
}
|
||||
|
||||
function repositionDraggables(state, answer) {
|
||||
if (state.config.individualTargets !== getUseTargets(answer)) {
|
||||
logme('ERROR: JSON config is not consistent with server response.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.config.individualTargets === true) {
|
||||
processAnswerTargets(state, answer);
|
||||
} else if (state.config.individualTargets === false) {
|
||||
processAnswerPositions(state, answer);
|
||||
}
|
||||
}
|
||||
|
||||
function getById(state, type, id) {
|
||||
return (function (c1) {
|
||||
while (c1 < state[type].length) {
|
||||
if (state[type][c1].id === id) {
|
||||
return state[type][c1];
|
||||
}
|
||||
c1 += 1;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getTargetById(id) {
|
||||
var c1;
|
||||
|
||||
for (c1 = 0; c1 < state.targets.length; c1 += 1) {
|
||||
if (state.targets[c1].id === id) {
|
||||
return state.targets[c1];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}(0));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user