studio - alerts: resolving local master merge conflcits
@@ -79,6 +79,17 @@ if Backbone?
|
||||
@getContent(id).updateInfo(info)
|
||||
$.extend @contentInfos, infos
|
||||
|
||||
pinThread: ->
|
||||
pinned = @get("pinned")
|
||||
@set("pinned",pinned)
|
||||
@trigger "change", @
|
||||
|
||||
unPinThread: ->
|
||||
pinned = @get("pinned")
|
||||
@set("pinned",pinned)
|
||||
@trigger "change", @
|
||||
|
||||
|
||||
class @Thread extends @Content
|
||||
urlMappers:
|
||||
'retrieve' : -> DiscussionUtil.urlFor('retrieve_single_thread', @discussion.id, @id)
|
||||
@@ -91,6 +102,8 @@ if Backbone?
|
||||
'delete' : -> DiscussionUtil.urlFor('delete_thread', @id)
|
||||
'follow' : -> DiscussionUtil.urlFor('follow_thread', @id)
|
||||
'unfollow' : -> DiscussionUtil.urlFor('unfollow_thread', @id)
|
||||
'pinThread' : -> DiscussionUtil.urlFor("pin_thread", @id)
|
||||
'unPinThread' : -> DiscussionUtil.urlFor("un_pin_thread", @id)
|
||||
|
||||
initialize: ->
|
||||
@set('thread', @)
|
||||
|
||||
@@ -58,10 +58,31 @@ if Backbone?
|
||||
@current_page = response.page
|
||||
|
||||
sortByDate: (thread) ->
|
||||
thread.get("created_at")
|
||||
#
|
||||
#The comment client asks each thread for a value by which to sort the collection
|
||||
#and calls this sort routine regardless of the order returned from the LMS/comments service
|
||||
#so, this takes advantage of this per-thread value and returns tomorrow's date
|
||||
#for pinned threads, ensuring that they appear first, (which is the intent of pinned threads)
|
||||
#
|
||||
if thread.get('pinned')
|
||||
#use tomorrow's date
|
||||
today = new Date();
|
||||
new Date(today.getTime() + (24 * 60 * 60 * 1000));
|
||||
else
|
||||
thread.get("created_at")
|
||||
|
||||
|
||||
sortByDateRecentFirst: (thread) ->
|
||||
-(new Date(thread.get("created_at")).getTime())
|
||||
#
|
||||
#Same as above
|
||||
#but negative to flip the order (newest first)
|
||||
#
|
||||
if thread.get('pinned')
|
||||
#use tomorrow's date
|
||||
today = new Date();
|
||||
-(new Date(today.getTime() + (24 * 60 * 60 * 1000)));
|
||||
else
|
||||
-(new Date(thread.get("created_at")).getTime())
|
||||
#return String.fromCharCode.apply(String,
|
||||
# _.map(thread.get("created_at").split(""),
|
||||
# ((c) -> return 0xffff - c.charChodeAt()))
|
||||
|
||||
@@ -50,6 +50,8 @@ class @DiscussionUtil
|
||||
delete_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/delete"
|
||||
upvote_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/upvote"
|
||||
downvote_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/downvote"
|
||||
pin_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/pin"
|
||||
un_pin_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/unpin"
|
||||
undo_vote_for_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/unvote"
|
||||
follow_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/follow"
|
||||
unfollow_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/unfollow"
|
||||
|
||||
@@ -3,6 +3,7 @@ if Backbone?
|
||||
|
||||
events:
|
||||
"click .discussion-vote": "toggleVote"
|
||||
"click .admin-pin": "togglePin"
|
||||
"click .action-follow": "toggleFollowing"
|
||||
"click .action-edit": "edit"
|
||||
"click .action-delete": "delete"
|
||||
@@ -24,6 +25,7 @@ if Backbone?
|
||||
@delegateEvents()
|
||||
@renderDogear()
|
||||
@renderVoted()
|
||||
@renderPinned()
|
||||
@renderAttrs()
|
||||
@$("span.timeago").timeago()
|
||||
@convertMath()
|
||||
@@ -41,8 +43,20 @@ if Backbone?
|
||||
else
|
||||
@$("[data-role=discussion-vote]").removeClass("is-cast")
|
||||
|
||||
renderPinned: =>
|
||||
if @model.get("pinned")
|
||||
@$("[data-role=thread-pin]").addClass("pinned")
|
||||
@$("[data-role=thread-pin]").removeClass("notpinned")
|
||||
@$(".discussion-pin .pin-label").html("Pinned")
|
||||
else
|
||||
@$("[data-role=thread-pin]").removeClass("pinned")
|
||||
@$("[data-role=thread-pin]").addClass("notpinned")
|
||||
@$(".discussion-pin .pin-label").html("Pin Thread")
|
||||
|
||||
|
||||
updateModelDetails: =>
|
||||
@renderVoted()
|
||||
@renderPinned()
|
||||
@$("[data-role=discussion-vote] .votes-count-number").html(@model.get("votes")["up_count"])
|
||||
|
||||
convertMath: ->
|
||||
@@ -99,6 +113,34 @@ if Backbone?
|
||||
delete: (event) ->
|
||||
@trigger "thread:delete", event
|
||||
|
||||
togglePin: (event) ->
|
||||
event.preventDefault()
|
||||
if @model.get('pinned')
|
||||
@unPin()
|
||||
else
|
||||
@pin()
|
||||
|
||||
pin: ->
|
||||
url = @model.urlFor("pinThread")
|
||||
DiscussionUtil.safeAjax
|
||||
$elem: @$(".discussion-pin")
|
||||
url: url
|
||||
type: "POST"
|
||||
success: (response, textStatus) =>
|
||||
if textStatus == 'success'
|
||||
@model.set('pinned', true)
|
||||
|
||||
unPin: ->
|
||||
url = @model.urlFor("unPinThread")
|
||||
DiscussionUtil.safeAjax
|
||||
$elem: @$(".discussion-pin")
|
||||
url: url
|
||||
type: "POST"
|
||||
success: (response, textStatus) =>
|
||||
if textStatus == 'success'
|
||||
@model.set('pinned', false)
|
||||
|
||||
|
||||
toggleClosed: (event) ->
|
||||
$elem = $(event.target)
|
||||
url = @model.urlFor('close')
|
||||
@@ -137,3 +179,5 @@ if Backbone?
|
||||
if @model.get('username')?
|
||||
params = $.extend(params, user:{username: @model.username, user_url: @model.user_url})
|
||||
Mustache.render(@template, params)
|
||||
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
|
||||
// define() functions from Require JS available inside the anonymous function.
|
||||
//
|
||||
// See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(['logme'], function (logme) {
|
||||
return BaseImage;
|
||||
|
||||
@@ -50,10 +45,5 @@ define(['logme'], function (logme) {
|
||||
baseImageElContainer.appendTo(state.containerEl);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// End of wrapper for RequireJS. As you can see, we are passing
|
||||
// namespaced Require JS variables to an anonymous function. Within
|
||||
// it, you can use the standard requirejs(), require(), and define()
|
||||
// functions as if they were in the global namespace.
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
|
||||
}); // End-of: define(['logme'], function (logme) {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
|
||||
// define() functions from Require JS available inside the anonymous function.
|
||||
//
|
||||
// See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(['logme'], function (logme) {
|
||||
return configParser;
|
||||
|
||||
@@ -16,7 +11,7 @@ define(['logme'], function (logme) {
|
||||
'targetOutline': true,
|
||||
'labelBgColor': '#d6d6d6',
|
||||
'individualTargets': null, // Depends on 'targets'.
|
||||
'errors': 0 // Number of errors found while parsing config.
|
||||
'foundErrors': false // Whether or not we find errors while processing the config.
|
||||
};
|
||||
|
||||
getDraggables(state, config);
|
||||
@@ -28,7 +23,7 @@ define(['logme'], function (logme) {
|
||||
|
||||
setIndividualTargets(state);
|
||||
|
||||
if (state.config.errors !== 0) {
|
||||
if (state.config.foundErrors !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -38,35 +33,34 @@ define(['logme'], function (logme) {
|
||||
function getDraggables(state, config) {
|
||||
if (config.hasOwnProperty('draggables') === false) {
|
||||
logme('ERROR: "config" does not have a property "draggables".');
|
||||
state.config.errors += 1;
|
||||
state.config.foundErrors = true;
|
||||
} else if ($.isArray(config.draggables) === true) {
|
||||
(function (i) {
|
||||
while (i < config.draggables.length) {
|
||||
if (processDraggable(state, config.draggables[i]) !== true) {
|
||||
state.config.errors += 1;
|
||||
}
|
||||
i += 1;
|
||||
config.draggables.every(function (draggable) {
|
||||
if (processDraggable(state, draggable) !== true) {
|
||||
state.config.foundErrors = true;
|
||||
|
||||
// Exit immediately from .every() call.
|
||||
return false;
|
||||
}
|
||||
}(0));
|
||||
} else if ($.isPlainObject(config.draggables) === true) {
|
||||
if (processDraggable(state, config.draggables) !== true) {
|
||||
state.config.errors += 1;
|
||||
}
|
||||
|
||||
// Continue to next .every() call.
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
logme('ERROR: The type of config.draggables is no supported.');
|
||||
state.config.errors += 1;
|
||||
state.config.foundErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
function getBaseImage(state, config) {
|
||||
if (config.hasOwnProperty('base_image') === false) {
|
||||
logme('ERROR: "config" does not have a property "base_image".');
|
||||
state.config.errors += 1;
|
||||
state.config.foundErrors = true;
|
||||
} 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".');
|
||||
state.config.errors += 1;
|
||||
state.config.foundErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,28 +71,27 @@ define(['logme'], function (logme) {
|
||||
// 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(state, config.targets[i]) !== true) {
|
||||
state.config.errors += 1;
|
||||
}
|
||||
i += 1;
|
||||
config.targets.every(function (target) {
|
||||
if (processTarget(state, target) !== true) {
|
||||
state.config.foundErrors = true;
|
||||
|
||||
// Exit immediately from .every() call.
|
||||
return false;
|
||||
}
|
||||
}(0));
|
||||
} else if ($.isPlainObject(config.targets) === true) {
|
||||
if (processTarget(state, config.targets) !== true) {
|
||||
state.config.errors += 1;
|
||||
}
|
||||
|
||||
// Continue to next .every() call.
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
logme('ERROR: Property config.targets is not of a supported type.');
|
||||
state.config.errors += 1;
|
||||
state.config.foundErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
state.config.foundErrors = true;
|
||||
} else if (typeof config.one_per_target === 'string') {
|
||||
if (config.one_per_target.toLowerCase() === 'true') {
|
||||
state.config.onePerTarget = true;
|
||||
@@ -106,42 +99,45 @@ define(['logme'], function (logme) {
|
||||
state.config.onePerTarget = false;
|
||||
} else {
|
||||
logme('ERROR: Property config.one_per_target can either be "true", or "false".');
|
||||
state.config.errors += 1;
|
||||
state.config.foundErrors = true;
|
||||
}
|
||||
} else {
|
||||
logme('ERROR: Property config.one_per_target is not of a supported type.');
|
||||
state.config.errors += 1;
|
||||
state.config.foundErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
// 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.
|
||||
|
||||
if (config.hasOwnProperty('target_outline') === true) {
|
||||
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".');
|
||||
state.config.foundErrors = true;
|
||||
}
|
||||
} else {
|
||||
logme('ERROR: Property config.target_outline can either be "true", or "false".');
|
||||
state.config.errors += 1;
|
||||
logme('ERROR: Property config.target_outline is not of a supported type.');
|
||||
state.config.foundErrors = true;
|
||||
}
|
||||
} else {
|
||||
logme('ERROR: Property config.target_outline is not of a supported type.');
|
||||
state.config.errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
logme('ERROR: Property config.label_bg_color is not of a supported type.');
|
||||
returnStatus = 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.
|
||||
|
||||
if (config.hasOwnProperty('label_bg_color') === true) {
|
||||
if (typeof config.label_bg_color === 'string') {
|
||||
state.config.labelBgColor = config.label_bg_color;
|
||||
} else {
|
||||
logme('ERROR: Property config.label_bg_color is not of a supported type.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,17 +155,36 @@ define(['logme'], function (logme) {
|
||||
(attrIsString(obj, 'icon') === false) ||
|
||||
(attrIsString(obj, 'label') === false) ||
|
||||
|
||||
(attrIsBoolean(obj, 'can_reuse', false) === false)
|
||||
(attrIsBoolean(obj, 'can_reuse', false) === false) ||
|
||||
|
||||
(obj.hasOwnProperty('target_fields') === false)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that all targets in the 'target_fields' property are proper target objects.
|
||||
// We will be testing the return value from .every() call (it can be 'true' or 'false').
|
||||
if (obj.target_fields.every(
|
||||
function (targetObj) {
|
||||
return processTarget(state, targetObj, false);
|
||||
}
|
||||
) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state.config.draggables.push(obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function processTarget(state, obj) {
|
||||
// We need 'pushToState' parameter in order to simply test an object for the fact that it is a
|
||||
// proper target (without pushing it to the 'state' object). When
|
||||
//
|
||||
// pushToState === false
|
||||
//
|
||||
// the object being tested is not going to be pushed to 'state'. The function will onyl return
|
||||
// 'true' or 'false.
|
||||
function processTarget(state, obj, pushToState) {
|
||||
if (
|
||||
(attrIsString(obj, 'id') === false) ||
|
||||
|
||||
@@ -182,7 +197,9 @@ define(['logme'], function (logme) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state.config.targets.push(obj);
|
||||
if (pushToState !== false) {
|
||||
state.config.targets.push(obj);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -250,10 +267,5 @@ define(['logme'], function (logme) {
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// End of wrapper for RequireJS. As you can see, we are passing
|
||||
// namespaced Require JS variables to an anonymous function. Within
|
||||
// it, you can use the standard requirejs(), require(), and define()
|
||||
// functions as if they were in the global namespace.
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
|
||||
}); // End-of: define(['logme'], function (logme) {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
|
||||
// define() functions from Require JS available inside the anonymous function.
|
||||
//
|
||||
// See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(['logme'], function (logme) {
|
||||
return Container;
|
||||
|
||||
@@ -21,10 +16,5 @@ define(['logme'], function (logme) {
|
||||
|
||||
$('#inputtype_' + state.problemId).before(state.containerEl);
|
||||
}
|
||||
});
|
||||
|
||||
// End of wrapper for RequireJS. As you can see, we are passing
|
||||
// namespaced Require JS variables to an anonymous function. Within
|
||||
// it, you can use the standard requirejs(), require(), and define()
|
||||
// functions as if they were in the global namespace.
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
|
||||
}); // End-of: define(['logme'], function (logme) {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
|
||||
131
common/static/js/capa/drag_and_drop/draggable_events.js
Normal file
@@ -0,0 +1,131 @@
|
||||
(function (requirejs, require, define) {
|
||||
define(['logme'], function (logme) {
|
||||
return {
|
||||
'attachMouseEventsTo': function (element) {
|
||||
var self;
|
||||
|
||||
self = this;
|
||||
|
||||
this[element].mousedown(function (event) {
|
||||
self.mouseDown(event);
|
||||
});
|
||||
this[element].mouseup(function (event) {
|
||||
self.mouseUp(event);
|
||||
});
|
||||
this[element].mousemove(function (event) {
|
||||
self.mouseMove(event);
|
||||
});
|
||||
},
|
||||
|
||||
'mouseDown': function (event) {
|
||||
if (this.mousePressed === false) {
|
||||
// So that the browser does not perform a default drag.
|
||||
// If we don't do this, each drag operation will
|
||||
// potentially cause the highlghting of the dragged element.
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (this.numDraggablesOnMe > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this draggable is just being dragged out of the
|
||||
// container, we must perform some additional tasks.
|
||||
if (this.inContainer === true) {
|
||||
if ((this.isReusable === true) && (this.isOriginal === true)) {
|
||||
this.makeDraggableCopy(function (draggableCopy) {
|
||||
draggableCopy.mouseDown(event);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.containerEl.hide();
|
||||
this.iconEl.detach();
|
||||
}
|
||||
|
||||
if (this.iconImgEl !== null) {
|
||||
this.iconImgEl.css({
|
||||
'width': this.iconWidth,
|
||||
'height': this.iconHeight
|
||||
});
|
||||
}
|
||||
this.iconEl.css({
|
||||
'background-color': this.iconElBGColor,
|
||||
'padding-left': this.iconElPadding,
|
||||
'padding-right': this.iconElPadding,
|
||||
'border': this.iconElBorder,
|
||||
'width': this.iconWidth,
|
||||
'height': this.iconHeight,
|
||||
'left': event.pageX - this.state.baseImageEl.offset().left - this.iconWidth * 0.5 - this.iconElLeftOffset,
|
||||
'top': event.pageY - this.state.baseImageEl.offset().top - this.iconHeight * 0.5
|
||||
});
|
||||
this.iconEl.appendTo(this.state.baseImageEl.parent());
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
if (this.isOriginal === true) {
|
||||
this.labelEl.detach();
|
||||
}
|
||||
this.labelEl.css({
|
||||
'background-color': this.state.config.labelBgColor,
|
||||
'padding-left': 8,
|
||||
'padding-right': 8,
|
||||
'border': '1px solid black',
|
||||
'left': event.pageX - this.state.baseImageEl.offset().left - this.labelWidth * 0.5 - 9, // Account for padding, border.
|
||||
'top': event.pageY - this.state.baseImageEl.offset().top + this.iconHeight * 0.5 + 5
|
||||
});
|
||||
this.labelEl.appendTo(this.state.baseImageEl.parent());
|
||||
}
|
||||
|
||||
this.inContainer = false;
|
||||
if (this.isOriginal === true) {
|
||||
this.state.numDraggablesInSlider -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.zIndex = 1000;
|
||||
this.iconEl.css('z-index', '1000');
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.css('z-index', '1000');
|
||||
}
|
||||
|
||||
this.mousePressed = true;
|
||||
this.state.currentMovingDraggable = this;
|
||||
}
|
||||
},
|
||||
|
||||
'mouseUp': function () {
|
||||
if (this.mousePressed === true) {
|
||||
this.state.currentMovingDraggable = null;
|
||||
|
||||
this.checkLandingElement();
|
||||
}
|
||||
},
|
||||
|
||||
'mouseMove': function (event) {
|
||||
if (this.mousePressed === true) {
|
||||
// Because we have also attached a 'mousemove' event to the
|
||||
// 'document' (that will do the same thing), let's tell the
|
||||
// browser not to bubble up this event. The attached event
|
||||
// on the 'document' will only be triggered when the mouse
|
||||
// pointer leaves the draggable while it is in the middle
|
||||
// of a drag operation (user moves the mouse very quickly).
|
||||
event.stopPropagation();
|
||||
|
||||
this.iconEl.css({
|
||||
'left': event.pageX - this.state.baseImageEl.offset().left - this.iconWidth * 0.5 - this.iconElLeftOffset,
|
||||
'top': event.pageY - this.state.baseImageEl.offset().top - this.iconHeight * 0.5
|
||||
});
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.css({
|
||||
'left': event.pageX - this.state.baseImageEl.offset().left - this.labelWidth * 0.5 - 9, // Acoount for padding, border.
|
||||
'top': event.pageY - this.state.baseImageEl.offset().top + this.iconHeight * 0.5 + 5
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}; // End-of: return {
|
||||
}); // End-of: define(['logme'], function (logme) {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
387
common/static/js/capa/drag_and_drop/draggable_logic.js
Normal file
@@ -0,0 +1,387 @@
|
||||
(function (requirejs, require, define) {
|
||||
define(['logme', 'update_input', 'targets'], function (logme, updateInput, Targets) {
|
||||
return {
|
||||
'moveDraggableTo': function (moveType, target, funcCallback) {
|
||||
var self, offset;
|
||||
|
||||
if (this.hasLoaded === false) {
|
||||
self = this;
|
||||
|
||||
setTimeout(function () {
|
||||
self.moveDraggableTo(moveType, target, funcCallback);
|
||||
}, 50);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((this.isReusable === true) && (this.isOriginal === true)) {
|
||||
this.makeDraggableCopy(function (draggableCopy) {
|
||||
draggableCopy.moveDraggableTo(moveType, target, funcCallback);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
if (this.state.config.targetOutline === true) {
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
this.inContainer = false;
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.containerEl.hide();
|
||||
this.iconEl.detach();
|
||||
}
|
||||
|
||||
if (this.iconImgEl !== null) {
|
||||
this.iconImgEl.css({
|
||||
'width': this.iconWidth,
|
||||
'height': this.iconHeight
|
||||
});
|
||||
}
|
||||
|
||||
this.iconEl.css({
|
||||
'background-color': this.iconElBGColor,
|
||||
'padding-left': this.iconElPadding,
|
||||
'padding-right': this.iconElPadding,
|
||||
'border': this.iconElBorder,
|
||||
'width': this.iconWidth,
|
||||
'height': this.iconHeight
|
||||
});
|
||||
if (moveType === 'target') {
|
||||
this.iconEl.css({
|
||||
'left': target.offset.left + 0.5 * target.w - this.iconWidth * 0.5 + offset - this.iconElLeftOffset,
|
||||
'top': target.offset.top + 0.5 * target.h - this.iconHeight * 0.5 + offset
|
||||
});
|
||||
} else {
|
||||
this.iconEl.css({
|
||||
'left': target.x - this.iconWidth * 0.5 + offset - this.iconElLeftOffset,
|
||||
'top': target.y - this.iconHeight * 0.5 + offset
|
||||
});
|
||||
}
|
||||
this.iconEl.appendTo(this.state.baseImageEl.parent());
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
if (this.isOriginal === true) {
|
||||
this.labelEl.detach();
|
||||
}
|
||||
this.labelEl.css({
|
||||
'background-color': this.state.config.labelBgColor,
|
||||
'padding-left': 8,
|
||||
'padding-right': 8,
|
||||
'border': '1px solid black'
|
||||
});
|
||||
if (moveType === 'target') {
|
||||
this.labelEl.css({
|
||||
'left': target.offset.left + 0.5 * target.w - this.labelWidth * 0.5 + offset - 9, // Account for padding, border.
|
||||
'top': target.offset.top + 0.5 * target.h + this.iconHeight * 0.5 + 5 + offset
|
||||
});
|
||||
} else {
|
||||
this.labelEl.css({
|
||||
'left': target.x - this.labelWidth * 0.5 + offset - 9, // Account for padding, border.
|
||||
'top': target.y - this.iconHeight * 0.5 + this.iconHeight + 5 + offset
|
||||
});
|
||||
}
|
||||
this.labelEl.appendTo(this.state.baseImageEl.parent());
|
||||
}
|
||||
|
||||
if (moveType === 'target') {
|
||||
target.addDraggable(this);
|
||||
} else {
|
||||
this.x = target.x;
|
||||
this.y = target.y;
|
||||
}
|
||||
|
||||
this.zIndex = 1000;
|
||||
this.correctZIndexes();
|
||||
|
||||
Targets.initializeTargetField(this);
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.state.numDraggablesInSlider -= 1;
|
||||
this.state.updateArrowOpacity();
|
||||
}
|
||||
|
||||
if ($.isFunction(funcCallback) === true) {
|
||||
funcCallback();
|
||||
}
|
||||
},
|
||||
|
||||
// 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.
|
||||
'checkLandingElement': function () {
|
||||
var positionIE;
|
||||
|
||||
this.mousePressed = false;
|
||||
positionIE = this.iconEl.position();
|
||||
|
||||
if (this.state.config.individualTargets === true) {
|
||||
if (this.checkIfOnTarget(positionIE) === true) {
|
||||
this.correctZIndexes();
|
||||
|
||||
Targets.initializeTargetField(this);
|
||||
} else {
|
||||
if (this.onTarget !== null) {
|
||||
this.onTarget.removeDraggable(this);
|
||||
}
|
||||
|
||||
this.moveBackToSlider();
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.state.numDraggablesInSlider += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
(positionIE.left < 0) ||
|
||||
(positionIE.left + this.iconWidth > this.state.baseImageEl.width()) ||
|
||||
(positionIE.top < 0) ||
|
||||
(positionIE.top + this.iconHeight > this.state.baseImageEl.height())
|
||||
) {
|
||||
this.moveBackToSlider();
|
||||
|
||||
this.x = -1;
|
||||
this.y = -1;
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.state.numDraggablesInSlider += 1;
|
||||
}
|
||||
} else {
|
||||
this.correctZIndexes();
|
||||
|
||||
this.x = positionIE.left + this.iconWidth * 0.5;
|
||||
this.y = positionIE.top + this.iconHeight * 0.5;
|
||||
|
||||
Targets.initializeTargetField(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.state.updateArrowOpacity();
|
||||
}
|
||||
updateInput.update(this.state);
|
||||
},
|
||||
|
||||
// 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.
|
||||
//
|
||||
// positionIE is the object as returned by
|
||||
//
|
||||
// this.iconEl.position()
|
||||
'checkIfOnTarget': function (positionIE) {
|
||||
var c1, target;
|
||||
|
||||
for (c1 = 0; c1 < this.state.targets.length; c1 += 1) {
|
||||
target = this.state.targets[c1];
|
||||
|
||||
// If only one draggable per target is allowed, and
|
||||
// the current target already has a draggable on it
|
||||
// (with an ID different from the one we are checking
|
||||
// against), then go to next target.
|
||||
if (
|
||||
(this.state.config.onePerTarget === true) &&
|
||||
(target.draggableList.length === 1) &&
|
||||
(target.draggableList[0].uniqueId !== this.uniqueId)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the target is on a draggable (from target field), we must make sure that
|
||||
// this draggable is not the same as "this" one.
|
||||
if ((target.type === 'on_drag') && (target.draggableObj.uniqueId === this.uniqueId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the draggable's center coordinate is within
|
||||
// the target's dimensions. If not, go to next target.
|
||||
if (
|
||||
(positionIE.top + this.iconHeight * 0.5 < target.offset.top) ||
|
||||
(positionIE.top + this.iconHeight * 0.5 > target.offset.top + target.h) ||
|
||||
(positionIE.left + this.iconWidth * 0.5 < target.offset.left) ||
|
||||
(positionIE.left + this.iconWidth * 0.5 > target.offset.left + target.w)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the draggable was moved from one target to
|
||||
// another, then we need to remove it from the
|
||||
// previous target's draggables list, and add it to the
|
||||
// new target's draggables list.
|
||||
if ((this.onTarget !== null) && (this.onTarget.uniqueId !== target.uniqueId)) {
|
||||
this.onTarget.removeDraggable(this);
|
||||
target.addDraggable(this);
|
||||
}
|
||||
// If the draggable was moved from the slider to a
|
||||
// target, remember the target, and add ID to the
|
||||
// target's draggables list.
|
||||
else if (this.onTarget === null) {
|
||||
target.addDraggable(this);
|
||||
}
|
||||
|
||||
// Reposition the draggable so that it's center
|
||||
// coincides with the center of the target.
|
||||
this.snapToTarget(target);
|
||||
|
||||
// Target was found.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Target was not found.
|
||||
return false;
|
||||
},
|
||||
|
||||
'snapToTarget': function (target) {
|
||||
var offset;
|
||||
|
||||
offset = 0;
|
||||
if (this.state.config.targetOutline === true) {
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
this.iconEl.css({
|
||||
'left': target.offset.left + 0.5 * target.w - this.iconWidth * 0.5 + offset - this.iconElLeftOffset,
|
||||
'top': target.offset.top + 0.5 * target.h - this.iconHeight * 0.5 + offset
|
||||
});
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.css({
|
||||
'left': target.offset.left + 0.5 * target.w - this.labelWidth * 0.5 + offset - 9, // Acoount for padding, border.
|
||||
'top': target.offset.top + 0.5 * target.h + this.iconHeight * 0.5 + 5 + offset
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 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.
|
||||
'correctZIndexes': function () {
|
||||
var c1, highestZIndex;
|
||||
|
||||
highestZIndex = -10000;
|
||||
|
||||
if (this.state.config.individualTargets === true) {
|
||||
if (this.onTarget.draggableList.length > 0) {
|
||||
for (c1 = 0; c1 < this.onTarget.draggableList.length; c1 += 1) {
|
||||
if (
|
||||
(this.onTarget.draggableList[c1].zIndex > highestZIndex) &&
|
||||
(this.onTarget.draggableList[c1].zIndex !== 1000)
|
||||
) {
|
||||
highestZIndex = this.onTarget.draggableList[c1].zIndex;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
highestZIndex = 0;
|
||||
}
|
||||
} else {
|
||||
for (c1 = 0; c1 < this.state.draggables.length; c1++) {
|
||||
if (this.inContainer === false) {
|
||||
if (
|
||||
(this.state.draggables[c1].zIndex > highestZIndex) &&
|
||||
(this.state.draggables[c1].zIndex !== 1000)
|
||||
) {
|
||||
highestZIndex = this.state.draggables[c1].zIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (highestZIndex === -10000) {
|
||||
highestZIndex = 0;
|
||||
}
|
||||
|
||||
this.zIndex = highestZIndex + 1;
|
||||
|
||||
this.iconEl.css('z-index', this.zIndex);
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.css('z-index', this.zIndex);
|
||||
}
|
||||
},
|
||||
|
||||
// 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.
|
||||
'moveBackToSlider': function () {
|
||||
var c1;
|
||||
|
||||
Targets.destroyTargetField(this);
|
||||
|
||||
if (this.isOriginal === false) {
|
||||
this.iconEl.remove();
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.remove();
|
||||
}
|
||||
|
||||
this.state.draggables.splice(this.stateDraggablesIndex, 1);
|
||||
|
||||
for (c1 = 0; c1 < this.state.draggables.length; c1 += 1) {
|
||||
if (this.state.draggables[c1].stateDraggablesIndex > this.stateDraggablesIndex) {
|
||||
this.state.draggables[c1].stateDraggablesIndex -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.containerEl.show();
|
||||
this.zIndex = 1;
|
||||
|
||||
this.iconEl.detach();
|
||||
if (this.iconImgEl !== null) {
|
||||
this.iconImgEl.css({
|
||||
'width': this.iconWidthSmall,
|
||||
'height': this.iconHeightSmall
|
||||
});
|
||||
}
|
||||
this.iconEl.css({
|
||||
'border': 'none',
|
||||
'background-color': 'transparent',
|
||||
'padding-left': 0,
|
||||
'padding-right': 0,
|
||||
'z-index': this.zIndex,
|
||||
'width': this.iconWidthSmall,
|
||||
'height': this.iconHeightSmall,
|
||||
'left': 50 - this.iconWidthSmall * 0.5,
|
||||
|
||||
// Before:
|
||||
// 'top': ((this.labelEl !== null) ? (100 - this.iconHeightSmall - 25) * 0.5 : 50 - this.iconHeightSmall * 0.5)
|
||||
// After:
|
||||
'top': ((this.labelEl !== null) ? 37.5 : 50.0) - 0.5 * this.iconHeightSmall
|
||||
});
|
||||
this.iconEl.appendTo(this.containerEl);
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.detach();
|
||||
this.labelEl.css({
|
||||
'border': 'none',
|
||||
'background-color': 'transparent',
|
||||
'padding-left': 0,
|
||||
'padding-right': 0,
|
||||
'z-index': this.zIndex,
|
||||
'left': 50 - this.labelWidth * 0.5,
|
||||
|
||||
// Before:
|
||||
// 'top': (100 - this.iconHeightSmall - 25) * 0.5 + this.iconHeightSmall + 5
|
||||
// After:
|
||||
'top': 42.5 + 0.5 * this.iconHeightSmall
|
||||
});
|
||||
this.labelEl.appendTo(this.containerEl);
|
||||
}
|
||||
|
||||
this.inContainer = true;
|
||||
}
|
||||
}; // End-of: return {
|
||||
}); // End-of: define(['logme', 'update_input', 'targets'], function (logme, updateInput, Targets) {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
@@ -1,21 +1,15 @@
|
||||
// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
|
||||
// define() functions from Require JS available inside the anonymous function.
|
||||
//
|
||||
// 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', 'draggable_events', 'draggable_logic'], function (logme, draggableEvents, draggableLogic) {
|
||||
return {
|
||||
'init': init
|
||||
};
|
||||
|
||||
function init(state) {
|
||||
(function (c1) {
|
||||
while (c1 < state.config.draggables.length) {
|
||||
processDraggable(state, state.config.draggables[c1]);
|
||||
c1 += 1
|
||||
}
|
||||
}(0));
|
||||
state.config.draggables.every(function (draggable) {
|
||||
processDraggable(state, draggable);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function makeDraggableCopy(callbackFunc) {
|
||||
@@ -34,13 +28,18 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
draggableObj.stateDraggablesIndex = null; // Will be set.
|
||||
draggableObj.containerEl = null; // Not needed, since a copy will never return to a container element.
|
||||
draggableObj.iconEl = null; // Will be created.
|
||||
draggableObj.iconImgEl = null; // Will be created.
|
||||
draggableObj.labelEl = null; // Will be created.
|
||||
draggableObj.targetField = []; // Will be populated.
|
||||
|
||||
// Create DOM elements and attach events.
|
||||
if (draggableObj.originalConfigObj.icon.length > 0) {
|
||||
draggableObj.iconEl = $('<img />');
|
||||
draggableObj.iconEl.attr('src', draggableObj.originalConfigObj.icon);
|
||||
draggableObj.iconEl.load(function () {
|
||||
|
||||
draggableObj.iconEl = $('<div></div>');
|
||||
draggableObj.iconImgEl = $('<img />');
|
||||
draggableObj.iconImgEl.attr('src', draggableObj.originalConfigObj.icon);
|
||||
draggableObj.iconImgEl.load(function () {
|
||||
|
||||
draggableObj.iconEl.css({
|
||||
'position': 'absolute',
|
||||
'width': draggableObj.iconWidthSmall,
|
||||
@@ -48,6 +47,14 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
'left': 50 - draggableObj.iconWidthSmall * 0.5,
|
||||
'top': ((draggableObj.originalConfigObj.label.length > 0) ? 5 : 50 - draggableObj.iconHeightSmall * 0.5)
|
||||
});
|
||||
draggableObj.iconImgEl.css({
|
||||
'position': 'absolute',
|
||||
'width': draggableObj.iconWidthSmall,
|
||||
'height': draggableObj.iconHeightSmall,
|
||||
'left': 0,
|
||||
'top': 0
|
||||
});
|
||||
draggableObj.iconImgEl.appendTo(draggableObj.iconEl);
|
||||
|
||||
if (draggableObj.originalConfigObj.label.length > 0) {
|
||||
draggableObj.labelEl = $(
|
||||
@@ -71,7 +78,7 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
|
||||
draggableObj.attachMouseEventsTo('iconEl');
|
||||
|
||||
draggableObj.stateDraggablesIndex = draggableObj.state.draggables.push(draggableObj);
|
||||
draggableObj.stateDraggablesIndex = draggableObj.state.draggables.push(draggableObj) - 1;
|
||||
|
||||
setTimeout(function () {
|
||||
callbackFunc(draggableObj);
|
||||
@@ -99,7 +106,7 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
|
||||
draggableObj.attachMouseEventsTo('iconEl');
|
||||
|
||||
draggableObj.stateDraggablesIndex = draggableObj.state.draggables.push(draggableObj);
|
||||
draggableObj.stateDraggablesIndex = draggableObj.state.draggables.push(draggableObj) - 1;
|
||||
|
||||
setTimeout(function () {
|
||||
callbackFunc(draggableObj);
|
||||
@@ -110,115 +117,6 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
}
|
||||
}
|
||||
|
||||
function attachMouseEventsTo(element) {
|
||||
var self;
|
||||
|
||||
self = this;
|
||||
|
||||
this[element].mousedown(function (event) {
|
||||
self.mouseDown(event);
|
||||
});
|
||||
this[element].mouseup(function (event) {
|
||||
self.mouseUp(event);
|
||||
});
|
||||
this[element].mousemove(function (event) {
|
||||
self.mouseMove(event);
|
||||
});
|
||||
}
|
||||
|
||||
function moveDraggableTo(moveType, target) {
|
||||
var self, offset;
|
||||
|
||||
if (this.hasLoaded === false) {
|
||||
self = this;
|
||||
|
||||
setTimeout(function () {
|
||||
self.moveDraggableTo(moveType, target);
|
||||
}, 50);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((this.isReusable === true) && (this.isOriginal === true)) {
|
||||
this.makeDraggableCopy(function (draggableCopy) {
|
||||
draggableCopy.moveDraggableTo(moveType, target);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
if (this.state.config.targetOutline === true) {
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
this.inContainer = false;
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.containerEl.hide();
|
||||
this.iconEl.detach();
|
||||
}
|
||||
this.iconEl.css({
|
||||
'background-color': this.iconElBGColor,
|
||||
'padding-left': this.iconElPadding,
|
||||
'padding-right': this.iconElPadding,
|
||||
'border': this.iconElBorder,
|
||||
'width': this.iconWidth,
|
||||
'height': this.iconHeight
|
||||
});
|
||||
if (moveType === 'target') {
|
||||
this.iconEl.css({
|
||||
'left': target.offset.left + 0.5 * target.w - this.iconWidth * 0.5 + offset - this.iconElLeftOffset,
|
||||
'top': target.offset.top + 0.5 * target.h - this.iconHeight * 0.5 + offset
|
||||
});
|
||||
} else {
|
||||
this.iconEl.css({
|
||||
'left': target.x - this.iconWidth * 0.5 + offset - this.iconElLeftOffset,
|
||||
'top': target.y - this.iconHeight * 0.5 + offset
|
||||
});
|
||||
}
|
||||
this.iconEl.appendTo(this.state.baseImageEl.parent());
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
if (this.isOriginal === true) {
|
||||
this.labelEl.detach();
|
||||
}
|
||||
this.labelEl.css({
|
||||
'background-color': this.state.config.labelBgColor,
|
||||
'padding-left': 8,
|
||||
'padding-right': 8,
|
||||
'border': '1px solid black'
|
||||
});
|
||||
if (moveType === 'target') {
|
||||
this.labelEl.css({
|
||||
'left': target.offset.left + 0.5 * target.w - this.labelWidth * 0.5 + offset - 9, // Account for padding, border.
|
||||
'top': target.offset.top + 0.5 * target.h + this.iconHeight * 0.5 + 5 + offset
|
||||
});
|
||||
} else {
|
||||
this.labelEl.css({
|
||||
'left': target.x - this.labelWidth * 0.5 + offset - 9, // Account for padding, border.
|
||||
'top': target.y - this.iconHeight * 0.5 + this.iconHeight + 5 + offset
|
||||
});
|
||||
}
|
||||
this.labelEl.appendTo(this.state.baseImageEl.parent());
|
||||
}
|
||||
|
||||
if (moveType === 'target') {
|
||||
target.addDraggable(this);
|
||||
} else {
|
||||
this.x = target.x;
|
||||
this.y = target.y;
|
||||
}
|
||||
|
||||
this.zIndex = 1000;
|
||||
this.correctZIndexes();
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.state.numDraggablesInSlider -= 1;
|
||||
this.state.updateArrowOpacity();
|
||||
}
|
||||
}
|
||||
|
||||
function processDraggable(state, obj) {
|
||||
var draggableObj;
|
||||
|
||||
@@ -234,6 +132,7 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
'zIndex': 1,
|
||||
'containerEl': null,
|
||||
'iconEl': null,
|
||||
'iconImgEl': null,
|
||||
'iconElBGColor': null,
|
||||
'iconElPadding': null,
|
||||
'iconElBorder': null,
|
||||
@@ -251,17 +150,23 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
'onTargetIndex': null,
|
||||
'state': state,
|
||||
|
||||
'mouseDown': mouseDown,
|
||||
'mouseUp': mouseUp,
|
||||
'mouseMove': mouseMove,
|
||||
'checkLandingElement': checkLandingElement,
|
||||
'checkIfOnTarget': checkIfOnTarget,
|
||||
'snapToTarget': snapToTarget,
|
||||
'correctZIndexes': correctZIndexes,
|
||||
'moveBackToSlider': moveBackToSlider,
|
||||
'moveDraggableTo': moveDraggableTo,
|
||||
'mouseDown': draggableEvents.mouseDown,
|
||||
'mouseUp': draggableEvents.mouseUp,
|
||||
'mouseMove': draggableEvents.mouseMove,
|
||||
|
||||
'checkLandingElement': draggableLogic.checkLandingElement,
|
||||
'checkIfOnTarget': draggableLogic.checkIfOnTarget,
|
||||
'snapToTarget': draggableLogic.snapToTarget,
|
||||
'correctZIndexes': draggableLogic.correctZIndexes,
|
||||
'moveBackToSlider': draggableLogic.moveBackToSlider,
|
||||
'moveDraggableTo': draggableLogic.moveDraggableTo,
|
||||
|
||||
'makeDraggableCopy': makeDraggableCopy,
|
||||
'attachMouseEventsTo': attachMouseEventsTo
|
||||
|
||||
'attachMouseEventsTo': draggableEvents.attachMouseEventsTo,
|
||||
|
||||
'targetField': [],
|
||||
'numDraggablesOnMe': 0
|
||||
};
|
||||
|
||||
draggableObj.containerEl = $(
|
||||
@@ -288,9 +193,11 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
draggableObj.iconElBorder = 'none';
|
||||
draggableObj.iconElLeftOffset = 0;
|
||||
|
||||
draggableObj.iconEl = $('<img />');
|
||||
draggableObj.iconEl.attr('src', obj.icon);
|
||||
draggableObj.iconEl.load(function () {
|
||||
draggableObj.iconEl = $('<div></div>');
|
||||
|
||||
draggableObj.iconImgEl = $('<img />');
|
||||
draggableObj.iconImgEl.attr('src', obj.icon);
|
||||
draggableObj.iconImgEl.load(function () {
|
||||
draggableObj.iconWidth = this.width;
|
||||
draggableObj.iconHeight = this.height;
|
||||
|
||||
@@ -307,8 +214,20 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
'width': draggableObj.iconWidthSmall,
|
||||
'height': draggableObj.iconHeightSmall,
|
||||
'left': 50 - draggableObj.iconWidthSmall * 0.5,
|
||||
'top': ((obj.label.length > 0) ? 5 : 50 - draggableObj.iconHeightSmall * 0.5)
|
||||
|
||||
// Before:
|
||||
// 'top': ((obj.label.length > 0) ? (100 - draggableObj.iconHeightSmall - 25) * 0.5 : 50 - draggableObj.iconHeightSmall * 0.5)
|
||||
// After:
|
||||
'top': ((obj.label.length > 0) ? 37.5 : 50.0) - 0.5 * draggableObj.iconHeightSmall
|
||||
});
|
||||
draggableObj.iconImgEl.css({
|
||||
'position': 'absolute',
|
||||
'width': draggableObj.iconWidthSmall,
|
||||
'height': draggableObj.iconHeightSmall,
|
||||
'left': 0,
|
||||
'top': 0
|
||||
});
|
||||
draggableObj.iconImgEl.appendTo(draggableObj.iconEl);
|
||||
draggableObj.iconEl.appendTo(draggableObj.containerEl);
|
||||
|
||||
if (obj.label.length > 0) {
|
||||
@@ -328,7 +247,11 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
draggableObj.labelWidth = draggableObj.labelEl.width();
|
||||
draggableObj.labelEl.css({
|
||||
'left': 50 - draggableObj.labelWidth * 0.5,
|
||||
'top': 5 + draggableObj.iconHeightSmall + 5
|
||||
|
||||
// Before:
|
||||
// 'top': (100 - this.iconHeightSmall - 25) * 0.5 + this.iconHeightSmall + 5
|
||||
// After:
|
||||
'top': 42.5 + 0.5 * draggableObj.iconHeightSmall
|
||||
});
|
||||
|
||||
draggableObj.attachMouseEventsTo('labelEl');
|
||||
@@ -384,357 +307,5 @@ define(['logme', 'update_input'], function (logme, updateInput) {
|
||||
state.numDraggablesInSlider += 1;
|
||||
draggableObj.stateDraggablesIndex = state.draggables.push(draggableObj) - 1;
|
||||
}
|
||||
|
||||
function mouseDown(event) {
|
||||
if (this.mousePressed === false) {
|
||||
// So that the browser does not perform a default drag.
|
||||
// If we don't do this, each drag operation will
|
||||
// potentially cause the highlghting of the dragged element.
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// If this draggable is just being dragged out of the
|
||||
// container, we must perform some additional tasks.
|
||||
if (this.inContainer === true) {
|
||||
if ((this.isReusable === true) && (this.isOriginal === true)) {
|
||||
this.makeDraggableCopy(function (draggableCopy) {
|
||||
draggableCopy.mouseDown(event);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.containerEl.hide();
|
||||
this.iconEl.detach();
|
||||
}
|
||||
this.iconEl.css({
|
||||
'background-color': this.iconElBGColor,
|
||||
'padding-left': this.iconElPadding,
|
||||
'padding-right': this.iconElPadding,
|
||||
'border': this.iconElBorder,
|
||||
'width': this.iconWidth,
|
||||
'height': this.iconHeight,
|
||||
'left': event.pageX - this.state.baseImageEl.offset().left - this.iconWidth * 0.5 - this.iconElLeftOffset,
|
||||
'top': event.pageY - this.state.baseImageEl.offset().top - this.iconHeight * 0.5
|
||||
});
|
||||
this.iconEl.appendTo(this.state.baseImageEl.parent());
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
if (this.isOriginal === true) {
|
||||
this.labelEl.detach();
|
||||
}
|
||||
this.labelEl.css({
|
||||
'background-color': this.state.config.labelBgColor,
|
||||
'padding-left': 8,
|
||||
'padding-right': 8,
|
||||
'border': '1px solid black',
|
||||
'left': event.pageX - this.state.baseImageEl.offset().left - this.labelWidth * 0.5 - 9, // Account for padding, border.
|
||||
'top': event.pageY - this.state.baseImageEl.offset().top + this.iconHeight * 0.5 + 5
|
||||
});
|
||||
this.labelEl.appendTo(this.state.baseImageEl.parent());
|
||||
}
|
||||
|
||||
this.inContainer = false;
|
||||
if (this.isOriginal === true) {
|
||||
this.state.numDraggablesInSlider -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.zIndex = 1000;
|
||||
this.iconEl.css('z-index', '1000');
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.css('z-index', '1000');
|
||||
}
|
||||
|
||||
this.mousePressed = true;
|
||||
this.state.currentMovingDraggable = this;
|
||||
}
|
||||
}
|
||||
|
||||
function mouseUp() {
|
||||
if (this.mousePressed === true) {
|
||||
this.state.currentMovingDraggable = null;
|
||||
|
||||
this.checkLandingElement();
|
||||
}
|
||||
}
|
||||
|
||||
function mouseMove(event) {
|
||||
if (this.mousePressed === true) {
|
||||
// Because we have also attached a 'mousemove' event to the
|
||||
// 'document' (that will do the same thing), let's tell the
|
||||
// browser not to bubble up this event. The attached event
|
||||
// on the 'document' will only be triggered when the mouse
|
||||
// pointer leaves the draggable while it is in the middle
|
||||
// of a drag operation (user moves the mouse very quickly).
|
||||
event.stopPropagation();
|
||||
|
||||
this.iconEl.css({
|
||||
'left': event.pageX - this.state.baseImageEl.offset().left - this.iconWidth * 0.5 - this.iconElLeftOffset,
|
||||
'top': event.pageY - this.state.baseImageEl.offset().top - this.iconHeight * 0.5
|
||||
});
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.css({
|
||||
'left': event.pageX - this.state.baseImageEl.offset().left - this.labelWidth * 0.5 - 9, // Acoount for padding, border.
|
||||
'top': event.pageY - this.state.baseImageEl.offset().top + this.iconHeight * 0.5 + 5
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 positionIE;
|
||||
|
||||
this.mousePressed = false;
|
||||
positionIE = this.iconEl.position();
|
||||
|
||||
if (this.state.config.individualTargets === true) {
|
||||
if (this.checkIfOnTarget(positionIE) === true) {
|
||||
this.correctZIndexes();
|
||||
} else {
|
||||
if (this.onTarget !== null) {
|
||||
this.onTarget.removeDraggable(this);
|
||||
}
|
||||
|
||||
this.moveBackToSlider();
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.state.numDraggablesInSlider += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
(positionIE.left < 0) ||
|
||||
(positionIE.left + this.iconWidth > this.state.baseImageEl.width()) ||
|
||||
(positionIE.top < 0) ||
|
||||
(positionIE.top + this.iconHeight > this.state.baseImageEl.height())
|
||||
) {
|
||||
this.moveBackToSlider();
|
||||
|
||||
this.x = -1;
|
||||
this.y = -1;
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.state.numDraggablesInSlider += 1;
|
||||
}
|
||||
} else {
|
||||
this.correctZIndexes();
|
||||
|
||||
this.x = positionIE.left + this.iconWidth * 0.5;
|
||||
this.y = positionIE.top + this.iconHeight * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isOriginal === true) {
|
||||
this.state.updateArrowOpacity();
|
||||
}
|
||||
updateInput.update(this.state);
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// positionIE is the object as returned by
|
||||
//
|
||||
// this.iconEl.position()
|
||||
function checkIfOnTarget(positionIE) {
|
||||
var c1, target;
|
||||
|
||||
for (c1 = 0; c1 < this.state.targets.length; c1 += 1) {
|
||||
target = this.state.targets[c1];
|
||||
|
||||
// If only one draggable per target is allowed, and
|
||||
// the current target already has a draggable on it
|
||||
// (with an ID different from the one we are checking
|
||||
// against), then go to next target.
|
||||
if (
|
||||
(this.state.config.onePerTarget === true) &&
|
||||
(target.draggableList.length === 1) &&
|
||||
(target.draggableList[0].uniqueId !== this.uniqueId)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the draggable's center coordinate is within
|
||||
// the target's dimensions. If not, go to next target.
|
||||
if (
|
||||
(positionIE.top + this.iconHeight * 0.5 < target.offset.top) ||
|
||||
(positionIE.top + this.iconHeight * 0.5 > target.offset.top + target.h) ||
|
||||
(positionIE.left + this.iconWidth * 0.5 < target.offset.left) ||
|
||||
(positionIE.left + this.iconWidth * 0.5 > target.offset.left + target.w)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the draggable was moved from one target to
|
||||
// another, then we need to remove it from the
|
||||
// previous target's draggables list, and add it to the
|
||||
// new target's draggables list.
|
||||
if ((this.onTarget !== null) && (this.onTarget.id !== target.id)) {
|
||||
this.onTarget.removeDraggable(this);
|
||||
target.addDraggable(this);
|
||||
}
|
||||
// If the draggable was moved from the slider to a
|
||||
// target, remember the target, and add ID to the
|
||||
// target's draggables list.
|
||||
else if (this.onTarget === null) {
|
||||
target.addDraggable(this);
|
||||
}
|
||||
|
||||
// Reposition the draggable so that it's center
|
||||
// coincides with the center of the target.
|
||||
this.snapToTarget(target);
|
||||
|
||||
// Target was found.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Target was not found.
|
||||
return false;
|
||||
}
|
||||
|
||||
function snapToTarget(target) {
|
||||
var offset;
|
||||
|
||||
offset = 0;
|
||||
if (this.state.config.targetOutline === true) {
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
this.iconEl.css({
|
||||
'left': target.offset.left + 0.5 * target.w - this.iconWidth * 0.5 + offset - this.iconElLeftOffset,
|
||||
'top': target.offset.top + 0.5 * target.h - this.iconHeight * 0.5 + offset
|
||||
});
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.css({
|
||||
'left': target.offset.left + 0.5 * target.w - this.labelWidth * 0.5 + offset - 9, // Acoount for padding, border.
|
||||
'top': target.offset.top + 0.5 * target.h + this.iconHeight * 0.5 + 5 + offset
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 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, highestZIndex;
|
||||
|
||||
highestZIndex = -10000;
|
||||
|
||||
if (this.state.config.individualTargets === true) {
|
||||
if (this.onTarget.draggableList.length > 0) {
|
||||
for (c1 = 0; c1 < this.onTarget.draggableList.length; c1 += 1) {
|
||||
if (
|
||||
(this.onTarget.draggableList[c1].zIndex > highestZIndex) &&
|
||||
(this.onTarget.draggableList[c1].zIndex !== 1000)
|
||||
) {
|
||||
highestZIndex = this.onTarget.draggableList[c1].zIndex;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
highestZIndex = 0;
|
||||
}
|
||||
} else {
|
||||
for (c1 = 0; c1 < this.state.draggables.length; c1++) {
|
||||
if (this.inContainer === false) {
|
||||
if (
|
||||
(this.state.draggables[c1].zIndex > highestZIndex) &&
|
||||
(this.state.draggables[c1].zIndex !== 1000)
|
||||
) {
|
||||
highestZIndex = this.state.draggables[c1].zIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (highestZIndex === -10000) {
|
||||
highestZIndex = 0;
|
||||
}
|
||||
|
||||
this.zIndex = highestZIndex + 1;
|
||||
|
||||
this.iconEl.css('z-index', this.zIndex);
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.css('z-index', this.zIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
if (this.isOriginal === false) {
|
||||
this.iconEl.remove();
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.remove();
|
||||
}
|
||||
this.state.draggables.splice(this.stateDraggablesIndex, 1);
|
||||
|
||||
for (c1 = 0; c1 < this.state.draggables; c1 += 1) {
|
||||
if (this.state.draggables[c1].stateDraggablesIndex > this.stateDraggablesIndex) {
|
||||
this.state.draggables[c1].stateDraggablesIndex -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.containerEl.show();
|
||||
this.zIndex = 1;
|
||||
|
||||
this.iconEl.detach();
|
||||
this.iconEl.css({
|
||||
'border': 'none',
|
||||
'background-color': 'transparent',
|
||||
'padding-left': 0,
|
||||
'padding-right': 0,
|
||||
'z-index': this.zIndex,
|
||||
'width': this.iconWidthSmall,
|
||||
'height': this.iconHeightSmall,
|
||||
'left': 50 - this.iconWidthSmall * 0.5,
|
||||
'top': ((this.labelEl !== null) ? 5 : 50 - this.iconHeightSmall * 0.5)
|
||||
});
|
||||
this.iconEl.appendTo(this.containerEl);
|
||||
|
||||
if (this.labelEl !== null) {
|
||||
this.labelEl.detach();
|
||||
this.labelEl.css({
|
||||
'border': 'none',
|
||||
'background-color': 'transparent',
|
||||
'padding-left': 0,
|
||||
'padding-right': 0,
|
||||
'z-index': this.zIndex,
|
||||
'left': 50 - this.labelWidth * 0.5,
|
||||
'top': 5 + this.iconHeightSmall + 5
|
||||
});
|
||||
this.labelEl.appendTo(this.containerEl);
|
||||
}
|
||||
|
||||
this.inContainer = true;
|
||||
}
|
||||
});
|
||||
|
||||
// End of wrapper for RequireJS. As you can see, we are passing
|
||||
// namespaced Require JS variables to an anonymous function. Within
|
||||
// it, you can use the standard requirejs(), require(), and define()
|
||||
// functions as if they were in the global namespace.
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
|
||||
}); // End-of: define(['logme', 'draggable_events', 'draggable_logic'], function (logme, draggableEvents, draggableLogic) {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
|
||||
// define() functions from Require JS available inside the anonymous function.
|
||||
//
|
||||
// See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define([], function () {
|
||||
var debugMode;
|
||||
|
||||
@@ -27,10 +22,5 @@ define([], function () {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// End of wrapper for RequireJS. As you can see, we are passing
|
||||
// namespaced Require JS variables to an anonymous function. Within
|
||||
// it, you can use the standard requirejs(), require(), and define()
|
||||
// functions as if they were in the global namespace.
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
|
||||
}); // End-of: define([], function () {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
|
||||
@@ -1,15 +1,41 @@
|
||||
// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
|
||||
// define() functions from Require JS available inside the anonymous function.
|
||||
//
|
||||
// See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(
|
||||
['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() {
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/every
|
||||
//
|
||||
// Array.prototype.every is a recent addition to the ECMA-262 standard; as such it may not be present in
|
||||
// other implementations of the standard.
|
||||
if (!Array.prototype.every) {
|
||||
Array.prototype.every = function(fun /*, thisp */) {
|
||||
var thisp, t, len, i;
|
||||
|
||||
if (this == null) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
t = Object(this);
|
||||
len = t.length >>> 0;
|
||||
if (typeof fun != 'function') {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
thisp = arguments[1];
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i in t && !fun.call(thisp, t[i], i, t)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
$('.drag_and_drop_problem_div').each(processProblem);
|
||||
}
|
||||
|
||||
@@ -59,7 +85,7 @@ define(
|
||||
return;
|
||||
}
|
||||
|
||||
Targets(state);
|
||||
Targets.initializeBaseTargets(state);
|
||||
Scroller(state);
|
||||
Draggables.init(state);
|
||||
|
||||
@@ -72,10 +98,5 @@ define(
|
||||
}
|
||||
}());
|
||||
}
|
||||
});
|
||||
|
||||
// End of wrapper for RequireJS. As you can see, we are passing
|
||||
// namespaced Require JS variables to an anonymous function. Within
|
||||
// it, you can use the standard requirejs(), require(), and define()
|
||||
// functions as if they were in the global namespace.
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
|
||||
}); // End-of: define(
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
|
||||
// define() functions from Require JS available inside the anonymous function.
|
||||
//
|
||||
// See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(['logme'], function (logme) {
|
||||
return Scroller;
|
||||
|
||||
@@ -206,10 +201,5 @@ define(['logme'], function (logme) {
|
||||
}
|
||||
}
|
||||
} // End-of: function Scroller(state)
|
||||
});
|
||||
|
||||
// End of wrapper for RequireJS. As you can see, we are passing
|
||||
// namespaced Require JS variables to an anonymous function. Within
|
||||
// it, you can use the standard requirejs(), require(), and define()
|
||||
// functions as if they were in the global namespace.
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
|
||||
}); // End-of: define(['logme'], function (logme) {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
|
||||
// define() functions from Require JS available inside the anonymous function.
|
||||
//
|
||||
// See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define([], function () {
|
||||
return State;
|
||||
|
||||
@@ -96,10 +91,5 @@ define([], function () {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// End of wrapper for RequireJS. As you can see, we are passing
|
||||
// namespaced Require JS variables to an anonymous function. Within
|
||||
// it, you can use the standard requirejs(), require(), and define()
|
||||
// functions as if they were in the global namespace.
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
|
||||
}); // End-of: define([], function () {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
|
||||
// define() functions from Require JS available inside the anonymous function.
|
||||
//
|
||||
// See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(['logme'], function (logme) {
|
||||
return Targets;
|
||||
return {
|
||||
'initializeBaseTargets': initializeBaseTargets,
|
||||
'initializeTargetField': initializeTargetField,
|
||||
'destroyTargetField': destroyTargetField
|
||||
};
|
||||
|
||||
function Targets(state) {
|
||||
function initializeBaseTargets(state) {
|
||||
(function (c1) {
|
||||
while (c1 < state.config.targets.length) {
|
||||
processTarget(state, state.config.targets[c1]);
|
||||
@@ -17,7 +16,58 @@ define(['logme'], function (logme) {
|
||||
}(0));
|
||||
}
|
||||
|
||||
function processTarget(state, obj) {
|
||||
function initializeTargetField(draggableObj) {
|
||||
var iconElOffset;
|
||||
|
||||
if (draggableObj.targetField.length === 0) {
|
||||
draggableObj.originalConfigObj.target_fields.every(function (targetObj) {
|
||||
processTarget(draggableObj.state, targetObj, true, draggableObj);
|
||||
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
iconElOffset = draggableObj.iconEl.position();
|
||||
|
||||
draggableObj.targetField.every(function (targetObj) {
|
||||
targetObj.offset.top = iconElOffset.top + targetObj.y;
|
||||
targetObj.offset.left = iconElOffset.left + targetObj.x;
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function destroyTargetField(draggableObj) {
|
||||
var indexOffset, lowestRemovedIndex;
|
||||
|
||||
indexOffset = 0;
|
||||
lowestRemovedIndex = draggableObj.state.targets.length + 1;
|
||||
|
||||
draggableObj.targetField.every(function (target) {
|
||||
target.el.remove();
|
||||
|
||||
if (lowestRemovedIndex > target.indexInStateArray) {
|
||||
lowestRemovedIndex = target.indexInStateArray;
|
||||
}
|
||||
|
||||
draggableObj.state.targets.splice(target.indexInStateArray - indexOffset, 1);
|
||||
indexOffset += 1;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
draggableObj.state.targets.every(function (target) {
|
||||
if (target.indexInStateArray > lowestRemovedIndex) {
|
||||
target.indexInStateArray -= indexOffset;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
draggableObj.targetField = [];
|
||||
}
|
||||
|
||||
function processTarget(state, obj, fromTargetField, draggableObj) {
|
||||
var targetEl, borderCss, numTextEl, targetObj;
|
||||
|
||||
borderCss = '';
|
||||
@@ -38,7 +88,13 @@ define(['logme'], function (logme) {
|
||||
'" ' +
|
||||
'></div>'
|
||||
);
|
||||
targetEl.appendTo(state.baseImageEl.parent());
|
||||
|
||||
if (fromTargetField === true) {
|
||||
targetEl.appendTo(draggableObj.iconEl);
|
||||
} else {
|
||||
targetEl.appendTo(state.baseImageEl.parent());
|
||||
}
|
||||
|
||||
targetEl.mousedown(function (event) {
|
||||
event.preventDefault();
|
||||
});
|
||||
@@ -68,8 +124,13 @@ define(['logme'], function (logme) {
|
||||
}
|
||||
|
||||
targetObj = {
|
||||
'uniqueId': state.getUniqueId(),
|
||||
|
||||
'id': obj.id,
|
||||
|
||||
'x': obj.x,
|
||||
'y': obj.y,
|
||||
|
||||
'w': obj.w,
|
||||
'h': obj.h,
|
||||
|
||||
@@ -86,9 +147,21 @@ define(['logme'], function (logme) {
|
||||
'updateNumTextEl': updateNumTextEl,
|
||||
|
||||
'removeDraggable': removeDraggable,
|
||||
'addDraggable': addDraggable
|
||||
'addDraggable': addDraggable,
|
||||
|
||||
'type': 'base',
|
||||
'draggableObj': null
|
||||
};
|
||||
|
||||
if (fromTargetField === true) {
|
||||
targetObj.offset = draggableObj.iconEl.position();
|
||||
targetObj.offset.top += obj.y;
|
||||
targetObj.offset.left += obj.x;
|
||||
|
||||
targetObj.type = 'on_drag';
|
||||
targetObj.draggableObj = draggableObj;
|
||||
}
|
||||
|
||||
if (state.config.onePerTarget === false) {
|
||||
numTextEl.appendTo(state.baseImageEl.parent());
|
||||
numTextEl.mousedown(function (event) {
|
||||
@@ -99,7 +172,11 @@ define(['logme'], function (logme) {
|
||||
});
|
||||
}
|
||||
|
||||
state.targets.push(targetObj);
|
||||
targetObj.indexInStateArray = state.targets.push(targetObj) - 1;
|
||||
|
||||
if (fromTargetField === true) {
|
||||
draggableObj.targetField.push(targetObj);
|
||||
}
|
||||
}
|
||||
|
||||
function removeDraggable(draggable) {
|
||||
@@ -121,6 +198,10 @@ define(['logme'], function (logme) {
|
||||
draggable.onTarget = null;
|
||||
draggable.onTargetIndex = null;
|
||||
|
||||
if (this.type === 'on_drag') {
|
||||
this.draggableObj.numDraggablesOnMe -= 1;
|
||||
}
|
||||
|
||||
this.updateNumTextEl();
|
||||
}
|
||||
|
||||
@@ -128,6 +209,10 @@ define(['logme'], function (logme) {
|
||||
draggable.onTarget = this;
|
||||
draggable.onTargetIndex = this.draggableList.push(draggable) - 1;
|
||||
|
||||
if (this.type === 'on_drag') {
|
||||
this.draggableObj.numDraggablesOnMe += 1;
|
||||
}
|
||||
|
||||
this.updateNumTextEl();
|
||||
}
|
||||
|
||||
@@ -183,10 +268,5 @@ define(['logme'], function (logme) {
|
||||
this.numTextEl.html(this.draggableList.length);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// End of wrapper for RequireJS. As you can see, we are passing
|
||||
// namespaced Require JS variables to an anonymous function. Within
|
||||
// it, you can use the standard requirejs(), require(), and define()
|
||||
// functions as if they were in the global namespace.
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
|
||||
}); // End-of: define(['logme'], function (logme) {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
|
||||
// define() functions from Require JS available inside the anonymous function.
|
||||
//
|
||||
// See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
(function (requirejs, require, define) {
|
||||
|
||||
define(['logme'], function (logme) {
|
||||
return {
|
||||
'check': check,
|
||||
@@ -37,7 +32,12 @@ define(['logme'], function (logme) {
|
||||
(function (c2) {
|
||||
while (c2 < state.targets[c1].draggableList.length) {
|
||||
tempObj = {};
|
||||
tempObj[state.targets[c1].draggableList[c2].id] = state.targets[c1].id;
|
||||
|
||||
if (state.targets[c1].type === 'base') {
|
||||
tempObj[state.targets[c1].draggableList[c2].id] = state.targets[c1].id;
|
||||
} else {
|
||||
addTargetRecursively(tempObj, state.targets[c1].draggableList[c2], state.targets[c1]);
|
||||
}
|
||||
draggables.push(tempObj);
|
||||
tempObj = null;
|
||||
|
||||
@@ -50,7 +50,18 @@ define(['logme'], function (logme) {
|
||||
}(0));
|
||||
}
|
||||
|
||||
$('#input_' + state.problemId).val(JSON.stringify({'draggables': draggables}));
|
||||
$('#input_' + state.problemId).val(JSON.stringify(draggables));
|
||||
}
|
||||
|
||||
function addTargetRecursively(tempObj, draggable, target) {
|
||||
if (target.type === 'base') {
|
||||
tempObj[draggable.id] = target.id;
|
||||
} else {
|
||||
tempObj[draggable.id] = {};
|
||||
tempObj[draggable.id][target.id] = {};
|
||||
|
||||
addTargetRecursively(tempObj[draggable.id][target.id], target.draggableObj, target.draggableObj.onTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if input has an answer from server. If yes, then position
|
||||
@@ -59,6 +70,7 @@ define(['logme'], function (logme) {
|
||||
var inputElVal;
|
||||
|
||||
inputElVal = $('#input_' + state.problemId).val();
|
||||
|
||||
if (inputElVal.length === 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -68,95 +80,147 @@ define(['logme'], function (logme) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getUseTargets(answer) {
|
||||
if ($.isArray(answer.draggables) === false) {
|
||||
logme('ERROR: answer.draggables is not an array.');
|
||||
function processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i) {
|
||||
var baseDraggableId, baseDraggable, baseTargetId, baseTarget,
|
||||
layeredDraggableId, layeredDraggable, layeredTargetId, layeredTarget,
|
||||
chain;
|
||||
|
||||
return;
|
||||
} else if (answer.draggables.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($.isPlainObject(answer.draggables[0]) === false) {
|
||||
logme('ERROR: answer.draggables array does not contain objects.');
|
||||
if (depth === 0) {
|
||||
// We are at the lowest depth? The end.
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (c1 in answer.draggables[0]) {
|
||||
if (answer.draggables[0].hasOwnProperty(c1) === false) {
|
||||
continue;
|
||||
}
|
||||
if (answerSortedByDepth.hasOwnProperty(depth) === false) {
|
||||
// We have a depth that ts not valid, we decrease the depth by one.
|
||||
processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth - 1, 0);
|
||||
|
||||
if (typeof answer.draggables[0][c1] === 'string') {
|
||||
// use_targets = true;
|
||||
|
||||
return true;
|
||||
} else if (
|
||||
($.isArray(answer.draggables[0][c1]) === true) &&
|
||||
(answer.draggables[0][c1].length === 2)
|
||||
) {
|
||||
// use_targets = false;
|
||||
|
||||
return false;
|
||||
} else {
|
||||
logme('ERROR: answer.draggables[0] is inconsidtent.');
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
logme('ERROR: answer.draggables[0] is an empty object.');
|
||||
if (answerSortedByDepth[depth].length <= i) {
|
||||
// We ran out of answers at this depth, go to the next depth down.
|
||||
processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth - 1, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
chain = answerSortedByDepth[depth][i];
|
||||
|
||||
baseDraggableId = Object.keys(chain)[0];
|
||||
|
||||
// This is a hack. For now we will work with depths 1 and 3.
|
||||
if (depth === 1) {
|
||||
baseTargetId = chain[baseDraggableId];
|
||||
|
||||
layeredTargetId = null;
|
||||
layeredDraggableId = null;
|
||||
|
||||
// createBaseDraggableOnTarget(state, baseDraggableId, baseTargetId);
|
||||
} else if (depth === 3) {
|
||||
layeredDraggableId = baseDraggableId;
|
||||
|
||||
layeredTargetId = Object.keys(chain[layeredDraggableId])[0];
|
||||
|
||||
baseDraggableId = Object.keys(chain[layeredDraggableId][layeredTargetId])[0];
|
||||
|
||||
baseTargetId = chain[layeredDraggableId][layeredTargetId][baseDraggableId];
|
||||
}
|
||||
|
||||
checkBaseDraggable();
|
||||
|
||||
return;
|
||||
|
||||
function checkBaseDraggable() {
|
||||
if ((baseDraggable = getById(state, 'draggables', baseDraggableId, null, false, baseTargetId)) === null) {
|
||||
createBaseDraggableOnTarget(state, baseDraggableId, baseTargetId, true, function () {
|
||||
if ((baseDraggable = getById(state, 'draggables', baseDraggableId, null, false, baseTargetId)) === null) {
|
||||
console.log('ERROR: Could not successfully create a base draggable on a base target.');
|
||||
} else {
|
||||
baseTarget = baseDraggable.onTarget;
|
||||
|
||||
if ((layeredTargetId === null) || (layeredDraggableId === null)) {
|
||||
processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
|
||||
} else {
|
||||
checklayeredDraggable();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
baseTarget = baseDraggable.onTarget;
|
||||
|
||||
if ((layeredTargetId === null) || (layeredDraggableId === null)) {
|
||||
processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
|
||||
} else {
|
||||
checklayeredDraggable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checklayeredDraggable() {
|
||||
if ((layeredDraggable = getById(state, 'draggables', layeredDraggableId, null, false, layeredTargetId, baseDraggableId, baseTargetId)) === null) {
|
||||
layeredDraggable = getById(state, 'draggables', layeredDraggableId);
|
||||
layeredTarget = null;
|
||||
baseDraggable.targetField.every(function (target) {
|
||||
if (target.id === layeredTargetId) {
|
||||
layeredTarget = target;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if ((layeredDraggable !== null) && (layeredTarget !== null)) {
|
||||
layeredDraggable.moveDraggableTo('target', layeredTarget, function () {
|
||||
processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
|
||||
});
|
||||
} else {
|
||||
processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
|
||||
}
|
||||
} else {
|
||||
processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processAnswerTargets(state, answer) {
|
||||
var draggableId, draggable, targetId, target;
|
||||
function createBaseDraggableOnTarget(state, draggableId, targetId, reportError, funcCallback) {
|
||||
var draggable, target;
|
||||
|
||||
(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.moveDraggableTo('target', target);
|
||||
}
|
||||
|
||||
c1 += 1;
|
||||
if ((draggable = getById(state, 'draggables', draggableId)) === null) {
|
||||
if (reportError !== false) {
|
||||
logme(
|
||||
'ERROR: In answer there exists a ' +
|
||||
'draggable ID "' + draggableId + '". No ' +
|
||||
'draggable with this ID could be found.'
|
||||
);
|
||||
}
|
||||
}(0));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((target = getById(state, 'targets', targetId)) === null) {
|
||||
if (reportError !== false) {
|
||||
logme(
|
||||
'ERROR: In answer there exists a target ' +
|
||||
'ID "' + targetId + '". No target with this ' +
|
||||
'ID could be found.'
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
draggable.moveDraggableTo('target', target, funcCallback);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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) {
|
||||
while (c1 < answer.length) {
|
||||
for (draggableId in answer[c1]) {
|
||||
if (answer[c1].hasOwnProperty(draggableId) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -171,8 +235,8 @@ define(['logme'], function (logme) {
|
||||
}
|
||||
|
||||
draggable.moveDraggableTo('XY', {
|
||||
'x': answer.draggables[c1][draggableId][0],
|
||||
'y': answer.draggables[c1][draggableId][1]
|
||||
'x': answer[c1][draggableId][0],
|
||||
'y': answer[c1][draggableId][1]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -182,33 +246,110 @@ define(['logme'], function (logme) {
|
||||
}
|
||||
|
||||
function repositionDraggables(state, answer) {
|
||||
if (answer.draggables.length === 0) {
|
||||
var answerSortedByDepth, minDepth, maxDepth;
|
||||
|
||||
answerSortedByDepth = {};
|
||||
minDepth = 1000;
|
||||
maxDepth = 0;
|
||||
|
||||
answer.every(function (chain) {
|
||||
var depth;
|
||||
|
||||
depth = findDepth(chain, 0);
|
||||
|
||||
if (depth < minDepth) {
|
||||
minDepth = depth;
|
||||
}
|
||||
if (depth > maxDepth) {
|
||||
maxDepth = depth;
|
||||
}
|
||||
|
||||
if (answerSortedByDepth.hasOwnProperty(depth) === false) {
|
||||
answerSortedByDepth[depth] = [];
|
||||
}
|
||||
|
||||
answerSortedByDepth[depth].push(chain);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (answer.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.config.individualTargets !== getUseTargets(answer)) {
|
||||
logme('ERROR: JSON config is not consistent with server response.');
|
||||
|
||||
// For now we support only one case.
|
||||
if ((minDepth < 1) || (maxDepth > 3)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.config.individualTargets === true) {
|
||||
processAnswerTargets(state, answer);
|
||||
processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, maxDepth, 0);
|
||||
} else if (state.config.individualTargets === false) {
|
||||
processAnswerPositions(state, answer);
|
||||
}
|
||||
}
|
||||
|
||||
function getById(state, type, id) {
|
||||
function findDepth(tempObj, depth) {
|
||||
var i;
|
||||
|
||||
if ($.isPlainObject(tempObj) === false) {
|
||||
return depth;
|
||||
}
|
||||
|
||||
depth += 1;
|
||||
|
||||
for (i in tempObj) {
|
||||
if (tempObj.hasOwnProperty(i) === true) {
|
||||
depth = findDepth(tempObj[i], depth);
|
||||
}
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
function getById(state, type, id, fromTargetField, inContainer, targetId, baseDraggableId, baseTargetId) {
|
||||
return (function (c1) {
|
||||
while (c1 < state[type].length) {
|
||||
if (type === 'draggables') {
|
||||
if ((state[type][c1].id === id) && (state[type][c1].isOriginal === true)) {
|
||||
return state[type][c1];
|
||||
if ((targetId !== undefined) && (inContainer === false) && (baseDraggableId !== undefined) && (baseTargetId !== undefined)) {
|
||||
if (
|
||||
(state[type][c1].id === id) &&
|
||||
(state[type][c1].inContainer === false) &&
|
||||
(state[type][c1].onTarget.id === targetId) &&
|
||||
(state[type][c1].onTarget.type === 'on_drag') &&
|
||||
(state[type][c1].onTarget.draggableObj.id === baseDraggableId) &&
|
||||
(state[type][c1].onTarget.draggableObj.onTarget.id === baseTargetId)
|
||||
) {
|
||||
return state[type][c1];
|
||||
}
|
||||
} else if ((targetId !== undefined) && (inContainer === false)) {
|
||||
if (
|
||||
(state[type][c1].id === id) &&
|
||||
(state[type][c1].inContainer === false) &&
|
||||
(state[type][c1].onTarget.id === targetId)
|
||||
) {
|
||||
return state[type][c1];
|
||||
}
|
||||
} else {
|
||||
if (inContainer === false) {
|
||||
if ((state[type][c1].id === id) && (state[type][c1].inContainer === false)) {
|
||||
return state[type][c1];
|
||||
}
|
||||
} else {
|
||||
if ((state[type][c1].id === id) && (state[type][c1].inContainer === true)) {
|
||||
return state[type][c1];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // 'targets'
|
||||
if (state[type][c1].id === id) {
|
||||
return state[type][c1];
|
||||
if (fromTargetField === true) {
|
||||
if ((state[type][c1].id === id) && (state[type][c1].type === 'on_drag')) {
|
||||
return state[type][c1];
|
||||
}
|
||||
} else {
|
||||
if ((state[type][c1].id === id) && (state[type][c1].type === 'base')) {
|
||||
return state[type][c1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,10 +359,5 @@ define(['logme'], function (logme) {
|
||||
return null;
|
||||
}(0));
|
||||
}
|
||||
});
|
||||
|
||||
// End of wrapper for RequireJS. As you can see, we are passing
|
||||
// namespaced Require JS variables to an anonymous function. Within
|
||||
// it, you can use the standard requirejs(), require(), and define()
|
||||
// functions as if they were in the global namespace.
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
|
||||
}); // End-of: define(['logme'], function (logme) {
|
||||
}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
|
||||
|
||||
@@ -57,10 +57,15 @@ pre, #dna-strand {
|
||||
background: white;
|
||||
}
|
||||
.gwt-DialogBox .dialogBottomCenter {
|
||||
background: url(images/hborder.png) repeat-x 0px -2945px;
|
||||
-background: url(images/hborder_ie6.png) repeat-x 0px -2144px;
|
||||
}
|
||||
.gwt-DialogBox .dialogMiddleLeft {
|
||||
background: url(images/vborder.png) repeat-y -31px 0px;
|
||||
}
|
||||
.gwt-DialogBox .dialogMiddleRight {
|
||||
background: url(images/vborder.png) repeat-y -32px 0px;
|
||||
-background: url(images/vborder_ie6.png) repeat-y -32px 0px;
|
||||
}
|
||||
.gwt-DialogBox .dialogTopLeftInner {
|
||||
width: 10px;
|
||||
@@ -82,12 +87,20 @@ pre, #dna-strand {
|
||||
zoom: 1;
|
||||
}
|
||||
.gwt-DialogBox .dialogTopLeft {
|
||||
background: url(images/circles.png) no-repeat -20px 0px;
|
||||
-background: url(images/circles_ie6.png) no-repeat -20px 0px;
|
||||
}
|
||||
.gwt-DialogBox .dialogTopRight {
|
||||
background: url(images/circles.png) no-repeat -28px 0px;
|
||||
-background: url(images/circles_ie6.png) no-repeat -28px 0px;
|
||||
}
|
||||
.gwt-DialogBox .dialogBottomLeft {
|
||||
background: url(images/circles.png) no-repeat 0px -36px;
|
||||
-background: url(images/circles_ie6.png) no-repeat 0px -36px;
|
||||
}
|
||||
.gwt-DialogBox .dialogBottomRight {
|
||||
background: url(images/circles.png) no-repeat -8px -36px;
|
||||
-background: url(images/circles_ie6.png) no-repeat -8px -36px;
|
||||
}
|
||||
* html .gwt-DialogBox .dialogTopLeftInner {
|
||||
width: 10px;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function genex(){var P='',xb='" for "gwt:onLoadErrorFn"',vb='" for "gwt:onPropertyErrorFn"',ib='"><\/script>',Z='#',Xb='.cache.html',_='/',lb='//',Qb='026A6180B5959B8660E084245FEE5E9E',Rb='1F433010E1134C95BF6CB43F552F3019',Sb='2DDA730EDABB80B88A6B0DFA3AFEACA2',Tb='4EEB1DCF4B30D366C27968D1B5C0BD04',Ub='5033ABB047340FB9346B622E2CC7107D',Wb=':',pb='::',dc='<script defer="defer">genex.onInjectionDone(\'genex\')<\/script>',hb='<script id="',sb='=',$='?',ub='Bad handler "',Vb='DF3D3A7FAEE63D711CF2D95BDB3F538C',cc='DOMContentLoaded',jb='SCRIPT',gb='__gwt_marker_genex',kb='base',cb='baseUrl',T='begin',S='bootstrap',bb='clear.cache.gif',rb='content',Y='end',Kb='gecko',Lb='gecko1_8',Q='genex',Yb='genex.css',eb='genex.nocache.js',ob='genex::',U='gwt.codesvr=',V='gwt.hosted=',W='gwt.hybrid',wb='gwt:onLoadErrorFn',tb='gwt:onPropertyErrorFn',qb='gwt:property',bc='head',Ob='hosted.html?genex',ac='href',Jb='ie6',Ib='ie8',Hb='ie9',yb='iframe',ab='img',zb="javascript:''",Zb='link',Nb='loadExternalRefs',mb='meta',Bb='moduleRequested',X='moduleStartup',Gb='msie',nb='name',Db='opera',Ab='position:absolute;width:0;height:0;border:none',$b='rel',Fb='safari',db='script',Pb='selectingPermutation',R='startup',_b='stylesheet',fb='undefined',Mb='unknown',Cb='user.agent',Eb='webkit';var m=window,n=document,o=m.__gwtStatsEvent?function(a){return m.__gwtStatsEvent(a)}:null,p=m.__gwtStatsSessionId?m.__gwtStatsSessionId:null,q,r,s,t=P,u={},v=[],w=[],x=[],y=0,z,A;o&&o({moduleName:Q,sessionId:p,subSystem:R,evtGroup:S,millis:(new Date).getTime(),type:T});if(!m.__gwt_stylesLoaded){m.__gwt_stylesLoaded={}}if(!m.__gwt_scriptsLoaded){m.__gwt_scriptsLoaded={}}function B(){var b=false;try{var c=m.location.search;return (c.indexOf(U)!=-1||(c.indexOf(V)!=-1||m.external&&m.external.gwtOnLoad))&&c.indexOf(W)==-1}catch(a){}B=function(){return b};return b}
|
||||
function genex(){var P='',xb='" for "gwt:onLoadErrorFn"',vb='" for "gwt:onPropertyErrorFn"',ib='"><\/script>',Z='#',Xb='.cache.html',_='/',lb='//',Qb='3F4ADBED36D589545A9300A1EA686D36',Rb='73F4B6D6D466BAD6850A60128DF5B80D',Wb=':',pb='::',dc='<script defer="defer">genex.onInjectionDone(\'genex\')<\/script>',hb='<script id="',sb='=',$='?',Sb='BA18AC23ACC5016C5D0799E864BBDFFE',ub='Bad handler "',Tb='C7B18436BA03373FB13ED589C2CCF417',cc='DOMContentLoaded',Ub='E1A9A95677AFC620CAD5759B7ACC3E67',Vb='FF175D5583BDD5ACF40C7F0AFF9A374B',jb='SCRIPT',gb='__gwt_marker_genex',kb='base',cb='baseUrl',T='begin',S='bootstrap',bb='clear.cache.gif',rb='content',Y='end',Kb='gecko',Lb='gecko1_8',Q='genex',Yb='genex.css',eb='genex.nocache.js',ob='genex::',U='gwt.codesvr=',V='gwt.hosted=',W='gwt.hybrid',wb='gwt:onLoadErrorFn',tb='gwt:onPropertyErrorFn',qb='gwt:property',bc='head',Ob='hosted.html?genex',ac='href',Jb='ie6',Ib='ie8',Hb='ie9',yb='iframe',ab='img',zb="javascript:''",Zb='link',Nb='loadExternalRefs',mb='meta',Bb='moduleRequested',X='moduleStartup',Gb='msie',nb='name',Db='opera',Ab='position:absolute;width:0;height:0;border:none',$b='rel',Fb='safari',db='script',Pb='selectingPermutation',R='startup',_b='stylesheet',fb='undefined',Mb='unknown',Cb='user.agent',Eb='webkit';var m=window,n=document,o=m.__gwtStatsEvent?function(a){return m.__gwtStatsEvent(a)}:null,p=m.__gwtStatsSessionId?m.__gwtStatsSessionId:null,q,r,s,t=P,u={},v=[],w=[],x=[],y=0,z,A;o&&o({moduleName:Q,sessionId:p,subSystem:R,evtGroup:S,millis:(new Date).getTime(),type:T});if(!m.__gwt_stylesLoaded){m.__gwt_stylesLoaded={}}if(!m.__gwt_scriptsLoaded){m.__gwt_scriptsLoaded={}}function B(){var b=false;try{var c=m.location.search;return (c.indexOf(U)!=-1||(c.indexOf(V)!=-1||m.external&&m.external.gwtOnLoad))&&c.indexOf(W)==-1}catch(a){}B=function(){return b};return b}
|
||||
function C(){if(q&&r){var b=n.getElementById(Q);var c=b.contentWindow;if(B()){c.__gwt_getProperty=function(a){return H(a)}}genex=null;c.gwtOnLoad(z,Q,t,y);o&&o({moduleName:Q,sessionId:p,subSystem:R,evtGroup:X,millis:(new Date).getTime(),type:Y})}}
|
||||
function D(){function e(a){var b=a.lastIndexOf(Z);if(b==-1){b=a.length}var c=a.indexOf($);if(c==-1){c=a.length}var d=a.lastIndexOf(_,Math.min(c,b));return d>=0?a.substring(0,d+1):P}
|
||||
function f(a){if(a.match(/^\w+:\/\//)){}else{var b=n.createElement(ab);b.src=a+bb;a=e(b.src)}return a}
|
||||
@@ -13,6 +13,6 @@ function F(a){var b=u[a];return b==null?null:b}
|
||||
function G(a,b){var c=x;for(var d=0,e=a.length-1;d<e;++d){c=c[a[d]]||(c[a[d]]=[])}c[a[e]]=b}
|
||||
function H(a){var b=w[a](),c=v[a];if(b in c){return b}var d=[];for(var e in c){d[c[e]]=e}if(A){A(a,d,b)}throw null}
|
||||
var I;function J(){if(!I){I=true;var a=n.createElement(yb);a.src=zb;a.id=Q;a.style.cssText=Ab;a.tabIndex=-1;n.body.appendChild(a);o&&o({moduleName:Q,sessionId:p,subSystem:R,evtGroup:X,millis:(new Date).getTime(),type:Bb});a.contentWindow.location.replace(t+L)}}
|
||||
w[Cb]=function(){var b=navigator.userAgent.toLowerCase();var c=function(a){return parseInt(a[1])*1000+parseInt(a[2])};if(function(){return b.indexOf(Db)!=-1}())return Db;if(function(){return b.indexOf(Eb)!=-1}())return Fb;if(function(){return b.indexOf(Gb)!=-1&&n.documentMode>=9}())return Hb;if(function(){return b.indexOf(Gb)!=-1&&n.documentMode>=8}())return Ib;if(function(){var a=/msie ([0-9]+)\.([0-9]+)/.exec(b);if(a&&a.length==3)return c(a)>=6000}())return Jb;if(function(){return b.indexOf(Kb)!=-1}())return Lb;return Mb};v[Cb]={gecko1_8:0,ie6:1,ie8:2,ie9:3,opera:4,safari:5};genex.onScriptLoad=function(){if(I){r=true;C()}};genex.onInjectionDone=function(){q=true;o&&o({moduleName:Q,sessionId:p,subSystem:R,evtGroup:Nb,millis:(new Date).getTime(),type:Y});C()};E();D();var K;var L;if(B()){if(m.external&&(m.external.initModule&&m.external.initModule(Q))){m.location.reload();return}L=Ob;K=P}o&&o({moduleName:Q,sessionId:p,subSystem:R,evtGroup:S,millis:(new Date).getTime(),type:Pb});if(!B()){try{G([Fb],Qb);G([Lb],Rb);G([Hb],Sb);G([Jb],Tb);G([Db],Ub);G([Ib],Vb);K=x[H(Cb)];var M=K.indexOf(Wb);if(M!=-1){y=Number(K.substring(M+1));K=K.substring(0,M)}L=K+Xb}catch(a){return}}var N;function O(){if(!s){s=true;if(!__gwt_stylesLoaded[Yb]){var a=n.createElement(Zb);__gwt_stylesLoaded[Yb]=a;a.setAttribute($b,_b);a.setAttribute(ac,t+Yb);n.getElementsByTagName(bc)[0].appendChild(a)}C();if(n.removeEventListener){n.removeEventListener(cc,O,false)}if(N){clearInterval(N)}}}
|
||||
w[Cb]=function(){var b=navigator.userAgent.toLowerCase();var c=function(a){return parseInt(a[1])*1000+parseInt(a[2])};if(function(){return b.indexOf(Db)!=-1}())return Db;if(function(){return b.indexOf(Eb)!=-1}())return Fb;if(function(){return b.indexOf(Gb)!=-1&&n.documentMode>=9}())return Hb;if(function(){return b.indexOf(Gb)!=-1&&n.documentMode>=8}())return Ib;if(function(){var a=/msie ([0-9]+)\.([0-9]+)/.exec(b);if(a&&a.length==3)return c(a)>=6000}())return Jb;if(function(){return b.indexOf(Kb)!=-1}())return Lb;return Mb};v[Cb]={gecko1_8:0,ie6:1,ie8:2,ie9:3,opera:4,safari:5};genex.onScriptLoad=function(){if(I){r=true;C()}};genex.onInjectionDone=function(){q=true;o&&o({moduleName:Q,sessionId:p,subSystem:R,evtGroup:Nb,millis:(new Date).getTime(),type:Y});C()};E();D();var K;var L;if(B()){if(m.external&&(m.external.initModule&&m.external.initModule(Q))){m.location.reload();return}L=Ob;K=P}o&&o({moduleName:Q,sessionId:p,subSystem:R,evtGroup:S,millis:(new Date).getTime(),type:Pb});if(!B()){try{G([Hb],Qb);G([Fb],Rb);G([Ib],Sb);G([Lb],Tb);G([Db],Ub);G([Jb],Vb);K=x[H(Cb)];var M=K.indexOf(Wb);if(M!=-1){y=Number(K.substring(M+1));K=K.substring(0,M)}L=K+Xb}catch(a){return}}var N;function O(){if(!s){s=true;if(!__gwt_stylesLoaded[Yb]){var a=n.createElement(Zb);__gwt_stylesLoaded[Yb]=a;a.setAttribute($b,_b);a.setAttribute(ac,t+Yb);n.getElementsByTagName(bc)[0].appendChild(a)}C();if(n.removeEventListener){n.removeEventListener(cc,O,false)}if(N){clearInterval(N)}}}
|
||||
if(n.addEventListener){n.addEventListener(cc,function(){J();O()},false)}var N=setInterval(function(){if(/loaded|complete/.test(n.readyState)){J();O()}},50);o&&o({moduleName:Q,sessionId:p,subSystem:R,evtGroup:S,millis:(new Date).getTime(),type:Y});o&&o({moduleName:Q,sessionId:p,subSystem:R,evtGroup:Nb,millis:(new Date).getTime(),type:T});n.write(dc)}
|
||||
genex();
|
||||
BIN
common/static/js/capa/genex/images/circles.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
common/static/js/capa/genex/images/circles_ie6.png
Normal file
|
After Width: | Height: | Size: 432 B |
BIN
common/static/js/capa/genex/images/corner.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
common/static/js/capa/genex/images/corner_ie6.png
Normal file
|
After Width: | Height: | Size: 412 B |
BIN
common/static/js/capa/genex/images/hborder.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
common/static/js/capa/genex/images/hborder_ie6.png
Normal file
|
After Width: | Height: | Size: 706 B |
BIN
common/static/js/capa/genex/images/thumb_horz.png
Normal file
|
After Width: | Height: | Size: 222 B |
BIN
common/static/js/capa/genex/images/thumb_vertical.png
Normal file
|
After Width: | Height: | Size: 231 B |
BIN
common/static/js/capa/genex/images/vborder.png
Normal file
|
After Width: | Height: | Size: 298 B |
BIN
common/static/js/capa/genex/images/vborder_ie6.png
Normal file
|
After Width: | Height: | Size: 189 B |
37
common/static/js/vendor/jquery-jvectormap-1.1.1/jquery-jvectormap-1.1.1.css
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
.jvectormap-label {
|
||||
position: absolute;
|
||||
display: none;
|
||||
border: solid 1px #CDCDCD;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
background: #292929;
|
||||
color: white;
|
||||
font-family: sans-serif, Verdana;
|
||||
font-size: smaller;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.jvectormap-zoomin, .jvectormap-zoomout {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
background: #292929;
|
||||
padding: 3px;
|
||||
color: white;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
cursor: pointer;
|
||||
line-height: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.jvectormap-zoomin {
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.jvectormap-zoomout {
|
||||
top: 30px;
|
||||
}
|
||||