Refactoring and code documentation.
This commit is contained in:
committed by
Alexander Kryklia
parent
f2e930a395
commit
108b0fc384
@@ -8,53 +8,25 @@ define(['logme'], function (logme) {
|
||||
return BaseImage;
|
||||
|
||||
function BaseImage(state) {
|
||||
var targetImgSrc, baseImageElContainer, mouseMoveDiv;
|
||||
|
||||
targetImgSrc = state.config.imageDir + '/' + state.config.base_image;
|
||||
var baseImageElContainer;
|
||||
|
||||
baseImageElContainer = $(
|
||||
'<div ' +
|
||||
'class="base_image_container" ' +
|
||||
'style=" ' +
|
||||
'position: relative; ' +
|
||||
'margin-bottom: 25px; ' +
|
||||
'" ' +
|
||||
'></div>'
|
||||
);
|
||||
|
||||
state.baseImageEl = $(
|
||||
'<img ' +
|
||||
'src="' + targetImgSrc + '" ' +
|
||||
'src="' + state.config.imageDir + '/' + state.config.base_image + '" ' +
|
||||
'/>'
|
||||
);
|
||||
state.baseImageEl.appendTo(baseImageElContainer);
|
||||
|
||||
state.baseImageElWidth = null;
|
||||
$('<img/>') // Make in memory copy of image to avoid css issues.
|
||||
.attr('src', state.baseImageEl.attr('src'))
|
||||
.load(function () {
|
||||
state.baseImageElWidth = this.width;
|
||||
});
|
||||
|
||||
// state.baseImageEl.mousemove(
|
||||
// function (event) {
|
||||
// mouseMoveDiv.html(
|
||||
// '[' + event.offsetX + ', ' + event.offsetY + ']'
|
||||
// );
|
||||
// }
|
||||
// );
|
||||
|
||||
mouseMoveDiv = $(
|
||||
'<div ' +
|
||||
'style=" ' +
|
||||
'clear: both; ' +
|
||||
'width: auto; ' +
|
||||
'height: 25px; ' +
|
||||
'text-align: center; ' +
|
||||
'" ' +
|
||||
'></div>'
|
||||
);
|
||||
mouseMoveDiv.appendTo(baseImageElContainer);
|
||||
|
||||
baseImageElContainer.appendTo(state.containerEl);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -78,9 +78,9 @@ define(['logme'], function (logme) {
|
||||
|
||||
if (typeof config.target_outline === 'string') {
|
||||
if (config.target_outline.toLowerCase() === 'true') {
|
||||
state.config.target_outline = true;
|
||||
state.config.targetOutline = true;
|
||||
} else if (config.target_outline.toLowerCase() === 'false') {
|
||||
state.config.target_outline = false;
|
||||
state.config.targetOutline = false;
|
||||
} else {
|
||||
logme('ERROR: Property config.target_outline can either be "true", or "false".');
|
||||
returnStatus = false;
|
||||
|
||||
@@ -8,22 +8,13 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
return Draggables;
|
||||
|
||||
function Draggables(state) {
|
||||
var _draggables, numDraggables;
|
||||
var c1;
|
||||
|
||||
numDraggables = state.config.draggables.length;
|
||||
_draggables = [];
|
||||
state.draggables = [];
|
||||
|
||||
(function (i) {
|
||||
while (i < numDraggables) {
|
||||
processDraggable(state.config.draggables[i], i + 1);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (state.individualTargets === false) {
|
||||
updateInput(state, true);
|
||||
}
|
||||
}(0));
|
||||
for (c1 = 0; c1 < state.config.draggables.length; c1 += 1) {
|
||||
processDraggable(state.config.draggables[c1], c1 + 1);
|
||||
}
|
||||
|
||||
state.currentMovingDraggable = null;
|
||||
|
||||
@@ -39,8 +30,8 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
return;
|
||||
|
||||
function processDraggable(obj, objIndex) {
|
||||
var draggableContainerEl, imgEl, inContainer, ousePressed,
|
||||
onTarget, draggableObj, marginCss;
|
||||
var draggableContainerEl, inContainer, mousePressed, onTarget,
|
||||
draggableObj, marginCss;
|
||||
|
||||
draggableContainerEl = $(
|
||||
'<div ' +
|
||||
@@ -51,20 +42,16 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
'float: left; ' +
|
||||
'overflow: hidden; ' +
|
||||
'z-index: ' + objIndex + '; ' +
|
||||
'border: 1px solid gray; ' +
|
||||
'border: 1px solid #CCC; ' +
|
||||
'" ' +
|
||||
'data-draggable-position-index="' + objIndex + '" ' +
|
||||
'></div>'
|
||||
);
|
||||
|
||||
if (obj.icon.length > 0) {
|
||||
imgEl = $(
|
||||
'<img ' +
|
||||
'src="' + state.config.imageDir + '/' + obj.icon + '" ' +
|
||||
'/>'
|
||||
draggableContainerEl.append(
|
||||
$('<img src="' + state.config.imageDir + '/' + obj.icon + '" />')
|
||||
);
|
||||
|
||||
draggableContainerEl.append(imgEl);
|
||||
}
|
||||
|
||||
if (obj.label.length > 0) {
|
||||
@@ -80,7 +67,6 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
}
|
||||
|
||||
draggableContainerEl.appendTo(state.sliderEl);
|
||||
_draggables.push(draggableContainerEl);
|
||||
|
||||
inContainer = true;
|
||||
mousePressed = false;
|
||||
@@ -102,12 +88,6 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
draggableContainerEl.mouseup(mouseUp);
|
||||
draggableContainerEl.mousemove(mouseMove);
|
||||
|
||||
if (objIndex + 1 === numDraggables) {
|
||||
state.draggablesLoaded = true;
|
||||
|
||||
state.updateArrowOpacity();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
function mouseDown(event) {
|
||||
@@ -134,10 +114,9 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
}
|
||||
}
|
||||
|
||||
function mouseUp(event) {
|
||||
function mouseUp() {
|
||||
if (mousePressed === true) {
|
||||
state.currentMovingDraggable = null;
|
||||
normalizeEvent(event);
|
||||
|
||||
checkLandingElement(event);
|
||||
}
|
||||
@@ -150,14 +129,30 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
}
|
||||
}
|
||||
|
||||
function checkLandingElement(event) {
|
||||
// At this point the mouse was realeased, and we need to check
|
||||
// where the draggable eneded up. Based on several things, we
|
||||
// will either move the draggable back to the slider, or update
|
||||
// the input with the user's answer (X-Y position of the draggable,
|
||||
// or the ID of the target where it landed.
|
||||
function checkLandingElement() {
|
||||
var offsetDE, indexes, DEindex, targetFound;
|
||||
|
||||
mousePressed = false;
|
||||
|
||||
offsetDE = draggableContainerEl.position();
|
||||
|
||||
if (state.individualTargets === false) {
|
||||
if (state.individualTargets === true) {
|
||||
targetFound = false;
|
||||
|
||||
checkIfOnTarget();
|
||||
|
||||
if (targetFound === true) {
|
||||
correctZIndexes();
|
||||
} else {
|
||||
moveBackToSlider();
|
||||
removeObjIdFromTarget();
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
(offsetDE.left < 0) ||
|
||||
(offsetDE.left + 100 > state.baseImageEl.width()) ||
|
||||
@@ -174,21 +169,9 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
draggableObj.x = offsetDE.left + 50;
|
||||
draggableObj.y = offsetDE.top + 50;
|
||||
}
|
||||
} else if (state.individualTargets === true) {
|
||||
targetFound = false;
|
||||
|
||||
checkIfOnTarget();
|
||||
|
||||
if (targetFound === true) {
|
||||
correctZIndexes();
|
||||
} else {
|
||||
moveBackToSlider();
|
||||
removeObjIdFromTarget();
|
||||
}
|
||||
}
|
||||
|
||||
state.updateArrowOpacity();
|
||||
|
||||
updateInput(state);
|
||||
|
||||
return;
|
||||
@@ -197,25 +180,26 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
var c1;
|
||||
|
||||
if (onTarget !== null) {
|
||||
c1 = 0;
|
||||
|
||||
while (c1 < onTarget.draggable.length) {
|
||||
for (c1 = 0; c1 < onTarget.draggable.length; c1 += 1) {
|
||||
if (onTarget.draggable[c1] === obj.id) {
|
||||
onTarget.draggable.splice(c1, 1);
|
||||
|
||||
break;
|
||||
}
|
||||
c1 += 1;
|
||||
}
|
||||
|
||||
onTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if a draggable, after it was relased, ends up on a
|
||||
// target. We do this by iterating over all of the targets, and
|
||||
// for each one we check whether the draggable's center is
|
||||
// within the target's dimensions.
|
||||
function checkIfOnTarget() {
|
||||
var c1, target;
|
||||
|
||||
for (c1 = 0; c1 < state.targets.length; c1++) {
|
||||
for (c1 = 0; c1 < state.targets.length; c1 += 1) {
|
||||
target = state.targets[c1];
|
||||
|
||||
if (offsetDE.top + 50 < target.offset.top) {
|
||||
@@ -241,10 +225,21 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
|
||||
targetFound = true;
|
||||
|
||||
removeObjIdFromTarget();
|
||||
onTarget = target;
|
||||
// If the draggable was moved from one target to
|
||||
// another, then we need to remove it's ID from the
|
||||
// previous target's draggables list, and add it to the
|
||||
// new target's draggables list.
|
||||
if ((onTarget !== null) && (onTarget.id !== target.id)) {
|
||||
removeObjIdFromTarget();
|
||||
onTarget = target;
|
||||
target.draggable.push(obj.id);
|
||||
} else if (onTarget === null) {
|
||||
onTarget = target;
|
||||
target.draggable.push(obj.id);
|
||||
}
|
||||
|
||||
target.draggable.push(obj.id);
|
||||
// Reposition the draggable so that it's center
|
||||
// coincides with the center of the target.
|
||||
snapToTarget(target);
|
||||
|
||||
break;
|
||||
@@ -256,30 +251,47 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
draggableContainerEl.css('top', target.offset.top + 0.5 * target.h - 50);
|
||||
}
|
||||
|
||||
// Go through all of the draggables subtract 1 from the z-index
|
||||
// of all whose z-index is higher than the old z-index of the
|
||||
// current element. After, set the z-index of the current
|
||||
// element to 1 + N (where N is the number of draggables - i.e.
|
||||
// the highest z-index possible).
|
||||
//
|
||||
// This will make sure that after releasing a draggable, it
|
||||
// will be on top of all of the other draggables. Also, the
|
||||
// ordering of the visibility (z-index) of the other draggables
|
||||
// will not change.
|
||||
function correctZIndexes() {
|
||||
var c1;
|
||||
|
||||
c1 = 0;
|
||||
|
||||
while (c1 < _draggables.length) {
|
||||
if (parseInt(draggableContainerEl.attr('data-old-z-index'), 10) < parseInt(_draggables[c1].css('z-index'), 10)) {
|
||||
_draggables[c1].css('z-index', parseInt(_draggables[c1].css('z-index'), 10) - 1);
|
||||
for (c1 = 0; c1 < state.draggables.length; c1++) {
|
||||
if (
|
||||
parseInt(draggableContainerEl.attr('data-old-z-index'), 10) <
|
||||
parseInt(state.draggables[c1].el.css('z-index'), 10)
|
||||
) {
|
||||
state.draggables[c1].el.css(
|
||||
'z-index',
|
||||
parseInt(state.draggables[c1].el.css('z-index'), 10) - 1
|
||||
);
|
||||
}
|
||||
c1 += 1;
|
||||
}
|
||||
|
||||
draggableContainerEl.css('z-index', c1);
|
||||
}
|
||||
|
||||
// If a draggable was released in a wrong positione, we will
|
||||
// move it back to the slider, placing it in the same position
|
||||
// that it was dragged out of.
|
||||
function moveBackToSlider() {
|
||||
var c1;
|
||||
|
||||
draggableContainerEl.detach();
|
||||
draggableContainerEl.css('position', 'static');
|
||||
|
||||
// Get the position indexes of all draggables that are
|
||||
// currently in the slider, along with the corresponding
|
||||
// jQuery element.
|
||||
indexes = [];
|
||||
DEindex = parseInt(draggableContainerEl.attr('data-draggable-position-index'), 10);
|
||||
|
||||
state.sliderEl.children().each(function (index, value) {
|
||||
indexes.push({
|
||||
'index': parseInt($(value).attr('data-draggable-position-index'), 10),
|
||||
@@ -287,27 +299,39 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
});
|
||||
});
|
||||
|
||||
c1 = 0;
|
||||
// Get the position index of the element that we are
|
||||
// inserting back into the slider.
|
||||
DEindex = parseInt(draggableContainerEl.attr('data-draggable-position-index'), 10);
|
||||
|
||||
while (c1 < indexes.length) {
|
||||
// Starting from the first position index that we
|
||||
// retrieved, and going up, if we find a position index
|
||||
// that is more than 'DEindex', we know that we must insert
|
||||
// the current element before the element with the greater
|
||||
// position index.
|
||||
for (c1 = 0; c1 < indexes.length; c1 += 1) {
|
||||
if ((inContainer === false) && (indexes[c1].index > DEindex)) {
|
||||
indexes[c1].el.before(draggableContainerEl);
|
||||
inContainer = true;
|
||||
}
|
||||
|
||||
c1 += 1;
|
||||
}
|
||||
|
||||
// If we did not find a greater postion index, then either
|
||||
// there are no elements in the slider, or all of them
|
||||
// have a lesser position index. In both cases we add the
|
||||
// current draggable to the end.
|
||||
if (inContainer === false) {
|
||||
draggableContainerEl.appendTo(state.sliderEl);
|
||||
inContainer = true;
|
||||
}
|
||||
|
||||
inContainer = true;
|
||||
|
||||
draggableContainerEl.css('border', '1px solid gray');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In firefox the event does not have a proper pageX and pageY
|
||||
// coordinates.
|
||||
function normalizeEvent(event) {
|
||||
if(!event.offsetX) {
|
||||
event.offsetX = (event.pageX - $(event.target).offset().left);
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(
|
||||
['logme', 'state', 'config_parser', 'container', 'base_image', 'scroller', 'draggables', 'targets'],
|
||||
function (logme, State, configParser, Container, BaseImage, Scroller, Draggables, Targets) {
|
||||
['logme', 'state', 'config_parser', 'container', 'base_image', 'scroller',
|
||||
'draggables', 'targets', 'update_input'],
|
||||
function (logme, State, configParser, Container, BaseImage, Scroller,
|
||||
Draggables, Targets, updateInput) {
|
||||
return Main;
|
||||
|
||||
function Main() {
|
||||
@@ -58,12 +60,13 @@ define(
|
||||
|
||||
Container(state);
|
||||
BaseImage(state);
|
||||
Targets(state);
|
||||
Scroller(state);
|
||||
Draggables(state);
|
||||
Targets(state);
|
||||
|
||||
logme('config', config);
|
||||
logme('state', state);
|
||||
// Update the input element, checking first that it is not filled with
|
||||
// an answer from the server.
|
||||
updateInput(state, true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -61,14 +61,20 @@ define(['logme'], function (logme) {
|
||||
moveLeftEl.mousemove(function (event) { event.preventDefault(); });
|
||||
moveLeftEl.mousedown(function (event) { event.preventDefault(); });
|
||||
|
||||
// This event will be responsible for moving the scroller left.
|
||||
// Hidden draggables will be shown.
|
||||
moveLeftEl.mouseup(function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
// When there are no more hidden draggables, prevent from
|
||||
// scrolling infinitely.
|
||||
if (showElLeftMargin > -102) {
|
||||
return;
|
||||
}
|
||||
|
||||
showElLeftMargin += 102;
|
||||
|
||||
// We scroll by changing the 'margin-left' CSS property smoothly.
|
||||
state.sliderEl.animate({
|
||||
'margin-left': showElLeftMargin + 'px'
|
||||
}, 100, function () {
|
||||
@@ -91,6 +97,10 @@ define(['logme'], function (logme) {
|
||||
|
||||
showElLeftMargin = 0;
|
||||
|
||||
// Element where the draggables will be contained. It is very long
|
||||
// so that any SANE number of draggables will fit in a single row. It
|
||||
// will be contained in a parent element whose 'overflow' CSS value
|
||||
// will be hidden, preventing the long row from fully being visible.
|
||||
state.sliderEl = $(
|
||||
'<div ' +
|
||||
'style=" ' +
|
||||
@@ -141,15 +151,20 @@ define(['logme'], function (logme) {
|
||||
moveRightEl.mousemove(function (event) { event.preventDefault(); });
|
||||
moveRightEl.mousedown(function (event) { event.preventDefault(); });
|
||||
|
||||
// This event will be responsible for moving the scroller right.
|
||||
// Hidden draggables will be shown.
|
||||
moveRightEl.mouseup(function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
// When there are no more hidden draggables, prevent from
|
||||
// scrolling infinitely.
|
||||
if (showElLeftMargin < -102 * (state.sliderEl.children().length - 6)) {
|
||||
return;
|
||||
}
|
||||
|
||||
showElLeftMargin -= 102;
|
||||
|
||||
// We scroll by changing the 'margin-left' CSS property smoothly.
|
||||
state.sliderEl.animate({
|
||||
'margin-left': showElLeftMargin + 'px'
|
||||
}, 100, function () {
|
||||
@@ -159,6 +174,16 @@ define(['logme'], function (logme) {
|
||||
|
||||
parentEl.appendTo(state.containerEl);
|
||||
|
||||
// Make the function available throughout the application. We need to
|
||||
// call it in several places:
|
||||
//
|
||||
// 1.) When initially reading answer from server, if draggables will be
|
||||
// positioned on the base image, the scroller's right and left arrows
|
||||
// opacity must be updated.
|
||||
//
|
||||
// 2.) When creating draggable elements, the scroller's right and left
|
||||
// arrows opacity must be updated according to the number of
|
||||
// draggables.
|
||||
state.updateArrowOpacity = updateArrowOpacity;
|
||||
|
||||
return;
|
||||
|
||||
@@ -11,6 +11,8 @@ define([], function () {
|
||||
return {
|
||||
'problemId': problemId,
|
||||
|
||||
// Will indicate when all targetsand draggables have been loaded,
|
||||
// processed, and postioned intially.
|
||||
'targetsLoaded': false,
|
||||
'draggablesLoaded': false
|
||||
};
|
||||
|
||||
@@ -4,48 +4,29 @@
|
||||
// See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
define(['logme'], function (logme) {
|
||||
return Targets;
|
||||
|
||||
function Targets(state) {
|
||||
var numTargets;
|
||||
var c1;
|
||||
|
||||
numTargets = state.config.targets.length;
|
||||
state.targets = [];
|
||||
|
||||
(function (c1) {
|
||||
while (c1 < numTargets) {
|
||||
processTarget(state.config.targets[c1], c1);
|
||||
c1 += 1;
|
||||
}
|
||||
|
||||
if (state.individualTargets === true) {
|
||||
updateInput(state, true);
|
||||
}
|
||||
}(0));
|
||||
for (c1 = 0; c1 < state.config.targets.length; c1++) {
|
||||
processTarget(state.config.targets[c1]);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
function processTarget(obj, objIndex) {
|
||||
var baseImageElOffset, tEl, left, borderCss;
|
||||
|
||||
// if (state.baseImageElWidth === null) {
|
||||
// window.setTimeout(function () {
|
||||
// processTarget(obj);
|
||||
// }, 50);
|
||||
//
|
||||
// return;
|
||||
// }
|
||||
|
||||
// left = obj.x + 0.5 * (state.baseImageEl.parent().width() - state.baseImageElWidth);
|
||||
left = obj.x;
|
||||
function processTarget(obj) {
|
||||
var targetEl, borderCss;
|
||||
|
||||
borderCss = '';
|
||||
if (state.config.target_outline === true) {
|
||||
if (state.config.targetOutline === true) {
|
||||
borderCss = 'border: 1px dashed gray; ';
|
||||
}
|
||||
|
||||
tEl = $(
|
||||
targetEl = $(
|
||||
'<div ' +
|
||||
'style=" ' +
|
||||
'display: block; ' +
|
||||
@@ -53,27 +34,26 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
'width: ' + obj.w + 'px; ' +
|
||||
'height: ' + obj.h + 'px; ' +
|
||||
'top: ' + obj.y + 'px; ' +
|
||||
'left: ' + left + 'px; ' +
|
||||
'left: ' + obj.x + 'px; ' +
|
||||
borderCss +
|
||||
'" ' +
|
||||
'data-target-id="' + obj.id + '" ' +
|
||||
'></div>'
|
||||
);
|
||||
|
||||
tEl.appendTo(state.baseImageEl.parent());
|
||||
targetEl.appendTo(state.baseImageEl.parent());
|
||||
|
||||
state.targets.push({
|
||||
'id': obj.id,
|
||||
'offset': tEl.position(),
|
||||
|
||||
'w': obj.w,
|
||||
'h': obj.h,
|
||||
'el': tEl,
|
||||
|
||||
'el': targetEl,
|
||||
'offset': targetEl.position(),
|
||||
|
||||
'draggable': []
|
||||
});
|
||||
|
||||
if (objIndex + 1 === numTargets) {
|
||||
state.targetsLoaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -54,6 +54,8 @@ define(['logme'], function (logme) {
|
||||
inputEl = $('#input_' + state.problemId);
|
||||
inputEl.val(stateStr);
|
||||
|
||||
logme(inputEl.val());
|
||||
|
||||
return;
|
||||
|
||||
// Check if input has an answer from server. If yes, then position
|
||||
@@ -75,16 +77,7 @@ define(['logme'], function (logme) {
|
||||
var draggableId, draggable, targetId, target, draggablePosition,
|
||||
c1;
|
||||
|
||||
if (
|
||||
((state.individualTargets === true) && (state.targetsLoaded === false)) ||
|
||||
(state.draggablesLoaded === false)
|
||||
) {
|
||||
window.setTimeout(function () {
|
||||
repositionDraggables(answer);
|
||||
}, 50);
|
||||
|
||||
return;
|
||||
}
|
||||
logme(answer);
|
||||
|
||||
if (
|
||||
((typeof answer.use_targets === 'boolean') && (answer.use_targets === true)) ||
|
||||
|
||||
Reference in New Issue
Block a user