(function(requirejs, require, define) { define(['js/capa/drag_and_drop/update_input', 'js/capa/drag_and_drop/targets'], function(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; }, 'toggleTargets': function(isEnabled) { var effect = isEnabled ? 'move' : null; this.state.baseImageEl.attr('aria-dropeffect', effect); $.each(this.state.targets, function(index, target) { target.targetEl.attr('aria-dropeffect', effect); }); }, '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(['update_input', 'targets'], function (updateInput, Targets) { }(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {