core.js | |
---|---|
(function ($) {
if (!$.event.special.move) {
$.event.reverse('move');
} | |
modify live steal the live handler .... | var bind = function (object, method) {
var args = Array.prototype.slice.call(arguments, 2);
return function () {
var args2 = [this].concat(args, $.makeArray(arguments));
return method.apply(object, args2);
};
},
event = $.event, |
function to clear the window selection if there is one | clearSelection = window.getSelection ?
function () {
window.getSelection().removeAllRanges()
} : function () {},
supportTouch = "ontouchend" in document, |
Use touch events or map it to mouse events | startEvent = supportTouch ? "touchstart" : "mousedown",
stopEvent = supportTouch ? "touchend" : "mouseup",
moveEvent = supportTouch ? "touchmove" : "mousemove", |
On touchmove events the default (scrolling) event has to be prevented | preventTouchScroll = function (ev) {
ev.preventDefault();
};
$.Drag = function () {};
$.extend($.Drag, {
lowerName: "drag",
current: null,
distance: 0,
mousedown: function (ev, element) {
var isLeftButton = ev.button === 0 || ev.button == 1,
doEvent = isLeftButton || supportTouch;
if (!doEvent || this.current) {
return;
} |
create Drag | var drag = new $.Drag(),
delegate = ev.delegateTarget || element,
selector = ev.handleObj.selector,
self = this;
this.current = drag;
drag.setup({
element: element,
delegate: ev.delegateTarget || element,
selector: ev.handleObj.selector,
moved: false,
_distance: this.distance,
callbacks: {
dragdown: event.find(delegate, ["dragdown"], selector),
draginit: event.find(delegate, ["draginit"], selector),
dragover: event.find(delegate, ["dragover"], selector),
dragmove: event.find(delegate, ["dragmove"], selector),
dragout: event.find(delegate, ["dragout"], selector),
dragend: event.find(delegate, ["dragend"], selector),
dragcleanup: event.find(delegate, ["dragcleanup"], selector)
},
destroyed: function () {
self.current = null;
}
}, ev);
}
});
$.extend($.Drag.prototype, {
setup: function (options, ev) {
$.extend(this, options);
this.element = $(this.element);
this.event = ev;
this.moved = false;
this.allowOtherDrags = false;
var mousemove = bind(this, this.mousemove),
mouseup = bind(this, this.mouseup);
this._mousemove = mousemove;
this._mouseup = mouseup;
this._distance = options.distance ? options.distance : 0; |
where the mouse is located | this.mouseStartPosition = ev.vector();
$(document).bind(moveEvent, mousemove);
$(document).bind(stopEvent, mouseup);
if (supportTouch) { |
On touch devices we want to disable scrolling | $(document).bind(moveEvent, preventTouchScroll);
}
if (!this.callEvents('down', this.element, ev)) {
this.noSelection(this.delegate); |
this is for firefox | clearSelection();
}
},
destroy: function () { |
Unbind the mouse handlers attached for dragging | $(document).unbind(moveEvent, this._mousemove);
$(document).unbind(stopEvent, this._mouseup);
if (supportTouch) { |
Enable scrolling again for touch devices when the drag is done | $(document).unbind(moveEvent, preventTouchScroll);
}
if (!this.moved) {
this.event = this.element = null;
}
if (!supportTouch) {
this.selection(this.delegate);
}
this.destroyed();
},
mousemove: function (docEl, ev) {
if (!this.moved) {
var dist = Math.sqrt(Math.pow(ev.pageX - this.event.pageX, 2) + Math.pow(ev.pageY - this.event.pageY, 2)); |
Don't initialize the drag if it hasn't been moved the minimum distance | if (dist < this._distance) {
return false;
} |
Otherwise call init and indicate that the drag has moved | this.init(this.element, ev);
this.moved = true;
}
this.element.trigger('move', this);
var pointer = ev.vector();
if (this._start_position && this._start_position.equals(pointer)) {
return;
}
this.draw(pointer, ev);
},
mouseup: function (docEl, event) { |
if there is a current, we should call its dragstop | if (this.moved) {
this.end(event);
}
this.destroy();
},
noSelection: function (elm) {
elm = elm || this.delegate
document.documentElement.onselectstart = function () { |
Disables selection | return false;
};
document.documentElement.unselectable = "on";
this.selectionDisabled = (this.selectionDisabled ? this.selectionDisabled.add(elm) : $(elm));
this.selectionDisabled.css('-moz-user-select', '-moz-none');
},
selection: function () {
if (this.selectionDisabled) {
document.documentElement.onselectstart = function () {};
document.documentElement.unselectable = "off";
this.selectionDisabled.css('-moz-user-select', '');
}
},
init: function (element, event) {
element = $(element); |
the element that has been clicked on | var startElement = (this.movingElement = (this.element = $(element))); |
if a mousemove has come after the click if the drag has been cancelled | this._cancelled = false;
this.event = event;
this.mouseElementPosition = this.mouseStartPosition.minus(this.element.offsetv()); //where the mouse is on the Element
this.callEvents('init', element, event); |
Check what they have set and respond accordingly if they canceled | if (this._cancelled === true) {
return;
} |
if they set something else as the element | this.startPosition = startElement != this.movingElement ? this.movingElement.offsetv() : this.currentDelta();
this.makePositioned(this.movingElement); |
Adjust the drag elements z-index to a high value | this.oldZIndex = this.movingElement.css('zIndex');
this.movingElement.css('zIndex', 1000);
if (!this._only && this.constructor.responder) { |
calls $.Drop.prototype.compile if there is a drop element | this.constructor.responder.compile(event, this);
}
},
makePositioned: function (that) {
var style, pos = that.css('position'); |
Position properly, set top and left to 0px for Opera | if (!pos || pos == 'static') {
style = {
position: 'relative'
};
if (window.opera) {
style.top = '0px';
style.left = '0px';
}
that.css(style);
}
},
callEvents: function (type, element, event, drop) {
var i, cbs = this.callbacks[this.constructor.lowerName + type];
for (i = 0; i < cbs.length; i++) {
cbs[i].call(element, event, this, drop);
}
return cbs.length;
},
currentDelta: function () {
return new $.Vector(parseInt(this.movingElement.css('left'), 10) || 0, parseInt(this.movingElement.css('top'), 10) || 0);
}, |
draws the position of the dragmove object | draw: function (pointer, event) { |
only drag if we haven't been cancelled; | if (this._cancelled) {
return;
}
clearSelection(); |
the offset between the mouse pointer and the representative that the user asked for | this.location = pointer.minus(this.mouseElementPosition); |
call move events | this.move(event);
if (this._cancelled) {
return;
}
if (!event.isDefaultPrevented()) {
this.position(this.location);
} |
fill in | if (!this._only && this.constructor.responder) {
this.constructor.responder.show(pointer, this, event);
}
},
position: function (newOffsetv) { //should draw it on the page
var style, dragged_element_css_offset = this.currentDelta(), |
the drag element's current left + top css attributes the vector between the movingElement's page and css positions this can be thought of as the original offset | dragged_element_position_vector = this.movingElement.offsetv().minus(dragged_element_css_offset);
this.required_css_position = newOffsetv.minus(dragged_element_position_vector);
this.offsetv = newOffsetv;
style = this.movingElement[0].style;
if (!this._cancelled && !this._horizontal) {
style.top = this.required_css_position.top() + "px";
}
if (!this._cancelled && !this._vertical) {
style.left = this.required_css_position.left() + "px";
}
},
move: function (event) {
this.callEvents('move', this.element, event);
},
over: function (event, drop) {
this.callEvents('over', this.element, event, drop);
},
out: function (event, drop) {
this.callEvents('out', this.element, event, drop);
},
end: function (event) { |
If canceled do nothing | if (this._cancelled) {
return;
} |
notify the responder - usually a $.Drop instance | if (!this._only && this.constructor.responder) {
this.constructor.responder.end(event, this);
}
this.callEvents('end', this.element, event);
if (this._revert) {
var self = this; |
animate moving back to original position | this.movingElement.animate({
top: this.startPosition.top() + "px",
left: this.startPosition.left() + "px"
}, function () {
self.cleanup.apply(self, arguments);
});
}
else {
this.cleanup(event);
}
this.event = null;
},
cleanup: function (event) {
this.movingElement.css({
zIndex: this.oldZIndex
});
if (this.movingElement[0] !== this.element[0] && !this.movingElement.has(this.element[0]).length && !this.element.has(this.movingElement[0]).length) {
this.movingElement.css({
display: 'none'
});
}
if (this._removeMovingElement) { |
Remove the element when using drag.ghost() | this.movingElement.remove();
}
if (event) {
this.callEvents('cleanup', this.element, event);
}
this.movingElement = this.element = this.event = null;
},
cancel: function () {
this._cancelled = true;
if (!this._only && this.constructor.responder) { |
clear the drops | this.constructor.responder.clear(this.event.vector(), this, this.event);
}
this.destroy();
},
ghost: function (parent) { |
create a ghost by cloning the source element and attach the clone to the dom after the source element | var ghost = this.movingElement.clone().css('position', 'absolute');
if (parent) {
$(parent).append(ghost);
} else {
$(this.movingElement).after(ghost)
}
ghost.width(this.movingElement.width()).height(this.movingElement.height()); |
put the ghost in the right location ... | ghost.offset(this.movingElement.offset()) |
store the original element and make the ghost the dragged element | this.movingElement = ghost;
this.noSelection(ghost)
this._removeMovingElement = true;
return ghost;
},
representative: function (element, offsetX, offsetY) {
this._offsetX = offsetX || 0;
this._offsetY = offsetY || 0;
var p = this.mouseStartPosition; |
Just set the representative as the drag element | this.movingElement = $(element);
this.movingElement.css({
top: (p.y() - this._offsetY) + "px",
left: (p.x() - this._offsetX) + "px",
display: 'block',
position: 'absolute'
}).show();
this.noSelection(this.movingElement)
this.mouseElementPosition = new $.Vector(this._offsetX, this._offsetY);
return this;
},
revert: function (val) {
this._revert = val === undefined ? true : val;
return this;
},
vertical: function () {
this._vertical = true;
return this;
},
horizontal: function () {
this._horizontal = true;
return this;
},
only: function (only) {
return (this._only = (only === undefined ? true : only));
},
distance: function (val) {
if (val !== undefined) {
this._distance = val;
return this;
} else {
return this._distance
}
}
});
event.setupHelper([
'dragdown',
'draginit',
'dragover',
'dragmove',
'dragout',
'dragend',
'dragcleanup'], startEvent, function (e) {
$.Drag.mousedown.call($.Drag, e, this);
});
return $;
})(jQuery);
|