- Created complete documentation in docs/ directory - Added PROJECT_OVERVIEW.md with feature highlights and getting started guide - Added ARCHITECTURE.md with system design and technical details - Added SECURITY.md with comprehensive security implementation guide - Added DEVELOPMENT.md with development workflows and best practices - Added DEPLOYMENT.md with production deployment instructions - Added API.md with complete REST API documentation - Added CONTRIBUTING.md with contribution guidelines - Added CHANGELOG.md with version history and migration notes - Reorganized all documentation files into docs/ directory for better organization - Updated README.md with proper documentation links and quick navigation - Enhanced project structure with professional documentation standards
588 lines
19 KiB
JavaScript
588 lines
19 KiB
JavaScript
/*jshint camelcase:true, plusplus:true, forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true, curly:true, browser:true, devel:true, maxerr:100, white:false, onevar:false */
|
|
/*global jQuery:true $:true */
|
|
|
|
/* jQuery Simulate Drag-n-Drop Plugin 1.3.0
|
|
* http://github.com/j-ulrich/jquery-simulate-ext
|
|
*
|
|
* Copyright (c) 2014 Jochen Ulrich
|
|
* Licensed under the MIT license (MIT-LICENSE.txt).
|
|
*/
|
|
|
|
;(function($, undefined) {
|
|
"use strict";
|
|
|
|
/* Overwrite the $.fn.simulate function to reduce the jQuery set to the first element for the
|
|
* drag-n-drop interactions.
|
|
*/
|
|
$.fn.simulate = function( type, options ) {
|
|
switch (type) {
|
|
case "drag":
|
|
case "drop":
|
|
case "drag-n-drop":
|
|
var ele = this.first();
|
|
new $.simulate( ele[0], type, options);
|
|
return ele;
|
|
default:
|
|
return this.each(function() {
|
|
new $.simulate( this, type, options );
|
|
});
|
|
}
|
|
};
|
|
|
|
var now = Date.now || function() { return new Date().getTime(); };
|
|
|
|
var rdocument = /\[object (?:HTML)?Document\]/;
|
|
/**
|
|
* Tests whether an object is an (HTML) document object.
|
|
* @param {DOM Element} elem - the object/element to be tested
|
|
* @returns {Boolean} <code>true</code> if <i>elem</i> is an (HTML) document object.
|
|
* @private
|
|
* @author julrich
|
|
* @since 1.1
|
|
*/
|
|
function isDocument( elem ) {
|
|
return rdocument.test(Object.prototype.toString.call($(elem)[0]));
|
|
}
|
|
|
|
/**
|
|
* Selects the first match from an array.
|
|
* @param {Array} array - Array of objects to be be tested
|
|
* @param {Function} check - Callback function that accepts one argument (which will be one element
|
|
* from the <i>array</i>) and returns a boolean.
|
|
* @returns {Boolean|null} the first element in <i>array</i> for which <i>check</i> returns <code>true</code>.
|
|
* If none of the elements in <i>array</i> passes <i>check</i>, <code>null</code> is returned.
|
|
* @private
|
|
* @author julrich
|
|
* @since 1.1
|
|
*/
|
|
function selectFirstMatch(array, check) {
|
|
var i;
|
|
if ($.isFunction(check)) {
|
|
for (i=0; i < array.length; i+=1) {
|
|
if (check(array[i])) {
|
|
return array[i];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
else {
|
|
for (i=0; i < array.length; i+=1) {
|
|
if (array[i]) {
|
|
return array[i];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Based on the findCenter function from jquery.simulate.js
|
|
/**
|
|
* Calculates the position of the center of an DOM element.
|
|
* @param {DOM Element} elem - the element whose center should be calculated.
|
|
* @returns {Object} an object with the properties <code>x</code> and <code>y</code>
|
|
* representing the position of the center of <i>elem</i> in page relative coordinates
|
|
* (i.e. independent of any scrolling).
|
|
* @private
|
|
* @author julrich
|
|
* @since 1.0
|
|
*/
|
|
function findCenter( elem ) {
|
|
var offset,
|
|
$elem = $( elem );
|
|
if ( isDocument($elem[0]) ) {
|
|
offset = {left: 0, top: 0};
|
|
}
|
|
else {
|
|
offset = $elem.offset();
|
|
}
|
|
|
|
return {
|
|
x: offset.left + $elem.outerWidth() / 2,
|
|
y: offset.top + $elem.outerHeight() / 2
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Converts page relative coordinates into client relative coordinates.
|
|
* @param {Numeric|Object} x - Either the x coordinate of the page relative coordinates or
|
|
* an object with the properties <code>pageX</code> and <code>pageY</code> representing page
|
|
* relative coordinates.
|
|
* @param {Numeric} [y] - If <i>x</i> is numeric (i.e. the x coordinate of page relative coordinates),
|
|
* then this is the y coordinate. If <i>x</i> is an object, this parameter is skipped.
|
|
* @param {DOM Document} [docRel] - Optional DOM document object used to calculate the client relative
|
|
* coordinates. The page relative coordinates are interpreted as being relative to that document and
|
|
* the scroll position of that document is used to calculate the client relative coordinates.
|
|
* By default, <code>document</code> is used.
|
|
* @returns {Object} an object representing the client relative coordinates corresponding to the
|
|
* given page relative coordinates. The object either provides the properties <code>x</code> and
|
|
* <code>y</code> when <i>x</i> and <i>y</i> were given as arguments, or <code>clientX</code>
|
|
* and <code>clientY</code> when the parameter <i>x</i> was given as an object (see above).
|
|
* @private
|
|
* @author julrich
|
|
* @since 1.0
|
|
*/
|
|
function pageToClientPos(x, y, docRel) {
|
|
var $document;
|
|
if ( isDocument(y) ) {
|
|
$document = $(y);
|
|
} else {
|
|
$document = $(docRel || document);
|
|
}
|
|
|
|
if (typeof x === "number" && typeof y === "number") {
|
|
return {
|
|
x: x - $document.scrollLeft(),
|
|
y: y - $document.scrollTop()
|
|
};
|
|
}
|
|
else if (typeof x === "object" && x.pageX && x.pageY) {
|
|
return {
|
|
clientX: x.pageX - $document.scrollLeft(),
|
|
clientY: x.pageY - $document.scrollTop()
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Browser-independent implementation of <code>document.elementFromPoint()</code>.
|
|
*
|
|
* When run for the first time on a scrolled page, this function performs a check on how
|
|
* <code>document.elementFromPoint()</code> is implemented in the current browser. It stores
|
|
* the results in two static variables so that the check can be skipped for successive calls.
|
|
*
|
|
* @param {Numeric|Object} x - Either the x coordinate of client relative coordinates or an object
|
|
* with the properties <code>x</code> and <code>y</code> representing client relative coordinates.
|
|
* @param {Numeric} [y] - If <i>x</i> is numeric (i.e. the x coordinate of client relative coordinates),
|
|
* this is the y coordinate. If <i>x</i> is an object, this parameter is skipped.
|
|
* @param {DOM Document} [docRel] - Optional DOM document object
|
|
* @returns {DOM Element|Null}
|
|
* @private
|
|
* @author Nicolas Zeh (Basic idea), julrich
|
|
* @see http://www.zehnet.de/2010/11/19/document-elementfrompoint-a-jquery-solution/
|
|
* @since 1.0
|
|
*/
|
|
function elementAtPosition(x, y, docRel) {
|
|
var doc;
|
|
if ( isDocument(y) ) {
|
|
doc = y;
|
|
} else {
|
|
doc = docRel || document;
|
|
}
|
|
|
|
if(!doc.elementFromPoint) {
|
|
return null;
|
|
}
|
|
|
|
var clientX = x, clientY = y;
|
|
if (typeof x === "object" && (x.clientX || x.clientY)) {
|
|
clientX = x.clientX || 0 ;
|
|
clientY = x.clientY || 0;
|
|
}
|
|
|
|
if(elementAtPosition.prototype.check)
|
|
{
|
|
var sl, ele;
|
|
if ((sl = $(doc).scrollTop()) >0)
|
|
{
|
|
ele = doc.elementFromPoint(0, sl + $(window).height() -1);
|
|
if ( ele !== null && ele.tagName.toUpperCase() === 'HTML' ) { ele = null; }
|
|
elementAtPosition.prototype.nativeUsesRelative = ( ele === null );
|
|
}
|
|
else if((sl = $(doc).scrollLeft()) >0)
|
|
{
|
|
ele = doc.elementFromPoint(sl + $(window).width() -1, 0);
|
|
if ( ele !== null && ele.tagName.toUpperCase() === 'HTML' ) { ele = null; }
|
|
elementAtPosition.prototype.nativeUsesRelative = ( ele === null );
|
|
}
|
|
elementAtPosition.prototype.check = (sl<=0); // Check was not meaningful because we were at scroll position 0
|
|
}
|
|
|
|
if(!elementAtPosition.prototype.nativeUsesRelative)
|
|
{
|
|
clientX += $(doc).scrollLeft();
|
|
clientY += $(doc).scrollTop();
|
|
}
|
|
|
|
return doc.elementFromPoint(clientX,clientY);
|
|
}
|
|
// Default values for the check variables
|
|
elementAtPosition.prototype.check = true;
|
|
elementAtPosition.prototype.nativeUsesRelative = true;
|
|
|
|
/**
|
|
* Informs the rest of the world that the drag is finished.
|
|
* @param {DOM Element} ele - The element which was dragged.
|
|
* @param {Object} [options] - The drag options.
|
|
* @fires simulate-drag
|
|
* @private
|
|
* @author julrich
|
|
* @since 1.0
|
|
*/
|
|
function dragFinished(ele, options) {
|
|
var opts = options || {};
|
|
$(ele).trigger({type: "simulate-drag"});
|
|
if ($.isFunction(opts.callback)) {
|
|
opts.callback.apply(ele);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates a series of <code>mousemove</code> events for a drag.
|
|
* @param {Object} self - The simulate object.
|
|
* @param {DOM Element} ele - The element which is dragged.
|
|
* @param {Object} start - The start coordinates of the drag, represented using the properties
|
|
* <code>x</code> and <code>y</code>.
|
|
* @param {Object} drag - The distance to be dragged, represented using the properties <code>dx</code>
|
|
* and <code>dy</code>.
|
|
* @param {Object} options - The drag options. Must have the property <code>interpolation</code>
|
|
* containing the interpolation options (<code>stepWidth</code>, <code>stepCount</code>, etc.).
|
|
* @requires eventTarget
|
|
* @requires now()
|
|
* @private
|
|
* @author julrich
|
|
* @since 1.0
|
|
*/
|
|
function interpolatedEvents(self, ele, start, drag, options) {
|
|
var targetDoc = selectFirstMatch([ele, ele.ownerDocument], isDocument) || document,
|
|
interpolOptions = options.interpolation,
|
|
dragDistance = Math.sqrt(Math.pow(drag.dx,2) + Math.pow(drag.dy,2)), // sqrt(a^2 + b^2)
|
|
stepWidth, stepCount, stepVector;
|
|
|
|
if (interpolOptions.stepWidth) {
|
|
stepWidth = parseInt(interpolOptions.stepWidth, 10);
|
|
stepCount = Math.floor(dragDistance / stepWidth)-1;
|
|
var stepScale = stepWidth / dragDistance;
|
|
stepVector = {x: drag.dx*stepScale, y: drag.dy*stepScale };
|
|
}
|
|
else {
|
|
stepCount = parseInt(interpolOptions.stepCount, 10);
|
|
stepWidth = dragDistance / (stepCount+1);
|
|
stepVector = {x: drag.dx/(stepCount+1), y: drag.dy/(stepCount+1)};
|
|
}
|
|
|
|
|
|
var coords = $.extend({},start);
|
|
|
|
/**
|
|
* Calculates the effective coordinates for one <code>mousemove</code> event and fires the event.
|
|
* @requires eventTarget
|
|
* @requires targetDoc
|
|
* @requires coords
|
|
* @requires stepVector
|
|
* @requires interpolOptions
|
|
* @fires mousemove
|
|
* @inner
|
|
* @author julrich
|
|
* @since 1.0
|
|
*/
|
|
function interpolationStep() {
|
|
coords.x += stepVector.x;
|
|
coords.y += stepVector.y;
|
|
var effectiveCoords = {pageX: coords.x, pageY: coords.y};
|
|
if (interpolOptions.shaky && (interpolOptions.shaky === true || !isNaN(parseInt(interpolOptions.shaky,10)) )) {
|
|
var amplitude = (interpolOptions.shaky === true)? 1 : parseInt(interpolOptions.shaky,10);
|
|
effectiveCoords.pageX += Math.floor(Math.random()*(2*amplitude+1)-amplitude);
|
|
effectiveCoords.pageY += Math.floor(Math.random()*(2*amplitude+1)-amplitude);
|
|
}
|
|
var clientCoord = pageToClientPos(effectiveCoords, targetDoc),
|
|
eventTarget = elementAtPosition(clientCoord, targetDoc) || ele;
|
|
self.simulateEvent( eventTarget, "mousemove", {pageX: Math.round(effectiveCoords.pageX), pageY: Math.round(effectiveCoords.pageY)});
|
|
}
|
|
|
|
|
|
var lastTime;
|
|
|
|
/**
|
|
* Performs one interpolation step (i.e. cares about firing the event) and then sleeps for
|
|
* <code>stepDelay</code> milliseconds.
|
|
* @requires lastTime
|
|
* @requires stepDelay
|
|
* @requires step
|
|
* @requires ele
|
|
* @requires eventTarget
|
|
* @reuiqre targetDoc
|
|
* @requires start
|
|
* @requires drag
|
|
* @requires now()
|
|
* @inner
|
|
* @author julrich
|
|
* @since 1.0
|
|
*/
|
|
function stepAndSleep() {
|
|
var timeElapsed = now() - lastTime; // Work-around for Firefox & IE "bug": setTimeout can fire before the timeout
|
|
if (timeElapsed >= stepDelay) {
|
|
if (step < stepCount) {
|
|
interpolationStep();
|
|
step += 1;
|
|
lastTime = now();
|
|
setTimeout(stepAndSleep, stepDelay);
|
|
}
|
|
else {
|
|
var pageCoord = {pageX: Math.round(start.x+drag.dx), pageY: Math.round(start.y+drag.dy)},
|
|
clientCoord = pageToClientPos(pageCoord, targetDoc),
|
|
eventTarget = elementAtPosition(clientCoord, targetDoc) || ele;
|
|
self.simulateEvent( eventTarget, "mousemove", pageCoord);
|
|
dragFinished(ele, options);
|
|
}
|
|
}
|
|
else {
|
|
setTimeout(stepAndSleep, stepDelay - timeElapsed);
|
|
}
|
|
|
|
}
|
|
|
|
if ( (!interpolOptions.stepDelay && !interpolOptions.duration) || ((interpolOptions.stepDelay <= 0) && (interpolOptions.duration <= 0)) ) {
|
|
// Trigger as fast as possible
|
|
for (var i=0; i < stepCount; i+=1) {
|
|
interpolationStep();
|
|
}
|
|
var pageCoord = {pageX: Math.round(start.x+drag.dx), pageY: Math.round(start.y+drag.dy)},
|
|
clientCoord = pageToClientPos(pageCoord, targetDoc),
|
|
eventTarget = elementAtPosition(clientCoord, targetDoc) || ele;
|
|
self.simulateEvent( eventTarget, "mousemove", pageCoord);
|
|
dragFinished(ele, options);
|
|
}
|
|
else {
|
|
var stepDelay = parseInt(interpolOptions.stepDelay,10) || Math.ceil(parseInt(interpolOptions.duration,10) / (stepCount+1));
|
|
var step = 0;
|
|
|
|
lastTime = now();
|
|
setTimeout(stepAndSleep, stepDelay);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* @returns {Object|undefined} an object containing information about the currently active drag
|
|
* or <code>undefined</code> when there is no active drag.
|
|
* The returned object contains the following properties:
|
|
* <ul>
|
|
* <li><code>dragElement</code>: the dragged element</li>
|
|
* <li><code>dragStart</code>: object with the properties <code>x</code> and <code>y</code>
|
|
* representing the page relative start coordinates of the drag</li>
|
|
* <li><code>dragDistance</code>: object with the properties <code>x</code> and <code>y</code>
|
|
* representing the distance of the drag in x and y direction</li>
|
|
* </ul>
|
|
* @public
|
|
* @author julrich
|
|
* @since 1.0
|
|
*/
|
|
$.simulate.activeDrag = function() {
|
|
if (!$.simulate._activeDrag) {
|
|
return undefined;
|
|
}
|
|
return $.extend(true,{},$.simulate._activeDrag);
|
|
};
|
|
|
|
$.extend( $.simulate.prototype,
|
|
|
|
/**
|
|
* @lends $.simulate.prototype
|
|
*/
|
|
{
|
|
|
|
|
|
/**
|
|
* Simulates a drag.
|
|
*
|
|
* @see https://github.com/j-ulrich/jquery-simulate-ext/blob/master/doc/drag-n-drop.md
|
|
* @public
|
|
* @author julrich
|
|
* @since 1.0
|
|
*/
|
|
simulateDrag: function() {
|
|
var self = this,
|
|
ele = self.target,
|
|
options = $.extend({
|
|
dx: 0,
|
|
dy: 0,
|
|
dragTarget: undefined,
|
|
clickToDrag: false,
|
|
eventProps: {},
|
|
interpolation: {
|
|
stepWidth: 0,
|
|
stepCount: 0,
|
|
stepDelay: 0,
|
|
duration: 0,
|
|
shaky: false
|
|
},
|
|
callback: undefined
|
|
}, this.options);
|
|
|
|
var start,
|
|
continueDrag = ($.simulate._activeDrag && $.simulate._activeDrag.dragElement === ele);
|
|
|
|
if (continueDrag) {
|
|
start = $.simulate._activeDrag.dragStart;
|
|
}
|
|
else {
|
|
start = findCenter( ele );
|
|
}
|
|
|
|
var x = Math.round( start.x ),
|
|
y = Math.round( start.y ),
|
|
coord = { pageX: x, pageY: y },
|
|
dx,
|
|
dy;
|
|
|
|
if (options.dragTarget) {
|
|
var end = findCenter(options.dragTarget);
|
|
dx = Math.round(end.x - start.x);
|
|
dy = Math.round(end.y - start.y);
|
|
}
|
|
else {
|
|
dx = options.dx || 0;
|
|
dy = options.dy || 0;
|
|
}
|
|
|
|
if (continueDrag) {
|
|
// We just continue to move the dragged element
|
|
$.simulate._activeDrag.dragDistance.x += dx;
|
|
$.simulate._activeDrag.dragDistance.y += dy;
|
|
coord = { pageX: Math.round(x + $.simulate._activeDrag.dragDistance.x) , pageY: Math.round(y + $.simulate._activeDrag.dragDistance.y) };
|
|
}
|
|
else {
|
|
if ($.simulate._activeDrag) {
|
|
// Drop before starting a new drag
|
|
$($.simulate._activeDrag.dragElement).simulate( "drop" );
|
|
}
|
|
|
|
// We start a new drag
|
|
$.extend(options.eventProps, coord);
|
|
self.simulateEvent( ele, "mousedown", options.eventProps );
|
|
if (options.clickToDrag === true) {
|
|
self.simulateEvent( ele, "mouseup", options.eventProps );
|
|
self.simulateEvent( ele, "click", options.eventProps );
|
|
}
|
|
$(ele).add(ele.ownerDocument).one('mouseup', function() {
|
|
$.simulate._activeDrag = undefined;
|
|
});
|
|
|
|
$.extend($.simulate, {
|
|
_activeDrag: {
|
|
dragElement: ele,
|
|
dragStart: { x: x, y: y },
|
|
dragDistance: { x: dx, y: dy }
|
|
}
|
|
});
|
|
coord = { pageX: Math.round(x + dx), pageY: Math.round(y + dy) };
|
|
}
|
|
|
|
if (dx !== 0 || dy !== 0) {
|
|
|
|
if ( options.interpolation && (options.interpolation.stepCount || options.interpolation.stepWidth) ) {
|
|
interpolatedEvents(self, ele, {x: x, y: y}, {dx: dx, dy: dy}, options);
|
|
}
|
|
else {
|
|
var targetDoc = selectFirstMatch([ele, ele.ownerDocument], isDocument) || document,
|
|
clientCoord = pageToClientPos(coord, targetDoc),
|
|
eventTarget = elementAtPosition(clientCoord, targetDoc) || ele;
|
|
|
|
$.extend(options.eventProps, coord);
|
|
self.simulateEvent( eventTarget, "mousemove", options.eventProps );
|
|
dragFinished(ele, options);
|
|
}
|
|
}
|
|
else {
|
|
dragFinished(ele, options);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Simulates a drop.
|
|
*
|
|
* @see https://github.com/j-ulrich/jquery-simulate-ext/blob/master/doc/drag-n-drop.md
|
|
* @public
|
|
* @author julrich
|
|
* @since 1.0
|
|
*/
|
|
simulateDrop: function() {
|
|
var self = this,
|
|
ele = this.target,
|
|
activeDrag = $.simulate._activeDrag,
|
|
options = $.extend({
|
|
clickToDrop: false,
|
|
eventProps: {},
|
|
callback: undefined
|
|
}, self.options),
|
|
moveBeforeDrop = true,
|
|
center = findCenter( ele ),
|
|
x = Math.round( center.x ),
|
|
y = Math.round( center.y ),
|
|
coord = { pageX: x, pageY: y },
|
|
targetDoc = ( (activeDrag)? selectFirstMatch([activeDrag.dragElement, activeDrag.dragElement.ownerDocument], isDocument) : selectFirstMatch([ele, ele.ownerDocument], isDocument) ) || document,
|
|
clientCoord = pageToClientPos(coord, targetDoc),
|
|
eventTarget = elementAtPosition(clientCoord, targetDoc);
|
|
|
|
if (activeDrag && (activeDrag.dragElement === ele || isDocument(ele))) {
|
|
// We already moved the mouse during the drag so we just simulate the drop on the end position
|
|
x = Math.round(activeDrag.dragStart.x + activeDrag.dragDistance.x);
|
|
y = Math.round(activeDrag.dragStart.y + activeDrag.dragDistance.y);
|
|
coord = { pageX: x, pageY: y };
|
|
clientCoord = pageToClientPos(coord, targetDoc);
|
|
eventTarget = elementAtPosition(clientCoord, targetDoc);
|
|
moveBeforeDrop = false;
|
|
}
|
|
|
|
if (!eventTarget) {
|
|
eventTarget = (activeDrag)? activeDrag.dragElement : ele;
|
|
}
|
|
|
|
$.extend(options.eventProps, coord);
|
|
|
|
if (moveBeforeDrop === true) {
|
|
// Else we assume the drop should happen on target, so we move there
|
|
self.simulateEvent( eventTarget, "mousemove", options.eventProps );
|
|
}
|
|
|
|
if (options.clickToDrop) {
|
|
self.simulateEvent( eventTarget, "mousedown", options.eventProps );
|
|
}
|
|
this.simulateEvent( eventTarget, "mouseup", options.eventProps );
|
|
if (options.clickToDrop) {
|
|
self.simulateEvent( eventTarget, "click", options.eventProps );
|
|
}
|
|
|
|
$.simulate._activeDrag = undefined;
|
|
$(eventTarget).trigger({type: "simulate-drop"});
|
|
if ($.isFunction(options.callback)) {
|
|
options.callback.apply(eventTarget);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Simulates a drag followed by drop.
|
|
*
|
|
* @see https://github.com/j-ulrich/jquery-simulate-ext/blob/master/doc/drag-n-drop.md
|
|
* @public
|
|
* @author julrich
|
|
* @since 1.0
|
|
*/
|
|
simulateDragNDrop: function() {
|
|
var self = this,
|
|
ele = this.target,
|
|
options = $.extend({
|
|
dragTarget: undefined,
|
|
dropTarget: undefined
|
|
}, self.options),
|
|
// If there is a dragTarget or dx/dy, then we drag there and simulate an independent drop on dropTarget or ele
|
|
dropEle = ((options.dragTarget || options.dx || options.dy)? options.dropTarget : ele) || ele;
|
|
/*
|
|
dx = (options.dropTarget)? 0 : (options.dx || 0),
|
|
dy = (options.dropTarget)? 0 : (options.dy || 0),
|
|
dragDistance = { dx: dx, dy: dy };
|
|
|
|
$.extend(options, dragDistance);
|
|
*/
|
|
$(ele).simulate( "drag", $.extend({},options,{
|
|
// If there is no dragTarget, no dx and no dy, we drag onto the dropTarget directly
|
|
dragTarget: options.dragTarget || ((options.dx || options.dy)?undefined:options.dropTarget),
|
|
callback: function() {
|
|
$(dropEle).simulate( "drop", options );
|
|
}
|
|
}));
|
|
|
|
}
|
|
});
|
|
|
|
}(jQuery)); |