jquery-ui/ui/jquery.ui.draggable.js

222 lines
6.2 KiB
JavaScript
Raw Normal View History

2008-06-04 02:34:33 +00:00
/*
2011-10-14 18:19:04 +00:00
* jQuery UI Draggable @VERSION
2008-06-04 02:34:33 +00:00
*
2011-01-17 14:13:18 +00:00
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
2011-10-14 18:19:04 +00:00
* http://docs.jquery.com/UI/Draggable
2008-06-04 02:34:33 +00:00
*
* Depends:
* jquery.ui.core.js
* jquery.ui.widget.js
2008-06-04 02:34:33 +00:00
*/
(function( $, undefined ) {
2008-06-04 02:34:33 +00:00
2011-09-28 02:02:07 +00:00
$.widget( "ui.draggable", {
2011-10-14 18:19:04 +00:00
version: "@VERSION",
widgetEventPrefix: "drag",
options: {
2011-10-14 18:19:04 +00:00
helper: false,
scrollSensitivity: 20,
scrollSpeed: 20
},
2011-10-14 18:19:04 +00:00
// dragEl: element being dragged (original or helper)
// position: CSS position of dragEl
// offset: offset of dragEl
// startCoords: clientX/Y of the mousedown (offset of pointer)
// startPosition: CSS position prior to drag start
// startOffset: offset prior to drag start
// overflowOffset: offset of scroll parent
// overflowHeight: height of scroll parent
// overflowWidth: width of scroll parent
_create: function() {
2011-10-14 18:19:04 +00:00
// TODO: add these to the base widget
this.doc = $( this.element[0].ownerDocument );
this.win = $( this.doc[0].defaultView );
this.scrollParent = this.element.scrollParent();
2011-10-14 18:19:04 +00:00
// Static position elements can't be moved with top/left
if ( this.element.css( "position" ) === "static" ) {
this.element.css( "position", "relative" );
}
2011-10-14 18:19:04 +00:00
// TODO: use _bind()
this.element.bind( "mousedown." + this.widgetName, $.proxy( this, "_mouseDown" ) );
},
2011-10-14 18:19:04 +00:00
// TODO: why is relative handled differently than fixed/absolute?
_getPosition: function() {
var left, top, position,
2011-10-14 18:19:04 +00:00
scrollTop = this.scrollParent.scrollTop(),
scrollLeft = this.scrollParent.scrollLeft();
2008-11-28 15:43:32 +00:00
// If fixed or absolute
if ( this.cssPosition !== "relative" ) {
position = this.dragEl.position();
2008-11-28 15:43:32 +00:00
// Take into account scrollbar
2011-10-14 18:19:04 +00:00
position.top -= scrollTop;
position.left -= scrollLeft
return position;
}
2011-10-14 18:19:04 +00:00
// When using relative, css values are checked
left = this.dragEl.css( "left" );
top = this.dragEl.css( "top" );
// Webkit will give back auto if there is nothing inline yet
left = ( left === "auto" ) ? 0: parseInt( left, 10 );
top = ( top === "auto" ) ? 0: parseInt( top, 10 );
return {
left: left - scrollLeft,
top: top - scrollTop
};
},
_mouseDown: function( event ) {
2011-10-14 18:19:04 +00:00
// Prevent text selection, among other things
event.preventDefault();
// The actual dragging element, should always be a jQuery object
this.dragEl = this.element;
this.cssPosition = this.dragEl.css( "position" );
2011-10-14 18:19:04 +00:00
// Helper required
if ( this.options.helper ) {
// clone
if ( this.options.helper === true ) {
// If source element has an ID, change ID of helper to avoid overlap
2011-10-14 18:19:04 +00:00
this.dragEl = this.element.clone();
if ( this.element.attr( "id" ) ) {
this.dragEl.attr( "id", this.element.attr( "id" ) + "-" + this.widgetName );
}
} else {
2011-10-14 18:19:04 +00:00
// TODO: figure out the signature for this; see #4957
this.dragEl = $( this.options.helper() );
}
this.dragEl
2011-10-14 18:19:04 +00:00
// TODO: should we move this to the stylesheet and use a class?
.css( "position", "absolute" )
.appendTo( this.doc[0].body )
.offset( this.element.offset() );
}
2008-06-04 02:34:33 +00:00
// Cache starting absolute and relative positions
2011-10-14 18:19:04 +00:00
this.startPosition = this._getPosition();
this.startOffset = this.dragEl.offset();
// Cache current position and offset
this.position = $.extend( {}, this.startPosition );
this.offset = $.extend( {}, this.startOffset );
2009-01-22 13:10:18 +00:00
this.startCoords = {
left: event.clientX,
top: event.clientY
};
2009-01-22 13:10:18 +00:00
// Cache the offset of scrollParent
2011-10-14 18:19:04 +00:00
// TODO: store overflow height/width in a hash instead of separate properties
this.overflowOffset = this.scrollParent.offset();
2011-10-14 18:19:04 +00:00
this.overflowHeight = ( this.scrollParent[0] === this.doc[0] ) ?
this.win.height() : this.scrollParent.height();
this.overflowWidth = ( this.scrollParent[0] === this.doc[0] ) ?
this.win.width() : this.scrollParent.width();
// TODO: allow modifying position, just like during drag
this._trigger( "start", event, this._uiHash() );
// TODO: use ._bind()
// TODO: rename _bind() to _on(); add _off()
this.doc
.bind( "mousemove." + this.widgetName, $.proxy( this, "_mouseMove" ) )
.bind( "mouseup." + this.widgetName, $.proxy( this, "_mouseUp" ) );
},
_mouseMove: function( event ) {
var leftDiff = event.clientX - this.startCoords.left,
2011-10-14 18:19:04 +00:00
topDiff = event.clientY - this.startCoords.top,
newLeft = leftDiff + this.startPosition.left,
newTop = topDiff + this.startPosition.top;
this.position = {
left: newLeft,
top: newTop
};
// Refresh offset cache with new positions
this.offset.left = this.startOffset.left + newLeft;
this.offset.top = this.startOffset.top + newTop;
2008-06-04 02:34:33 +00:00
2011-10-14 18:19:04 +00:00
this._trigger( "drag", event, this._uiHash() );
2008-06-04 02:34:33 +00:00
// User overriding left/top so shortcut math is no longer valid
if ( newLeft !== this.position.left || newTop !== this.position.top ) {
2011-10-14 18:19:04 +00:00
// TODO: can we just store the previous offset values
// and not go through .offset()?
// refresh offset using slower functions
this.offset = this.dragEl.offset();
}
2011-10-14 18:19:04 +00:00
newLeft = this.position.left;
newTop = this.position.top;
2011-10-14 18:19:04 +00:00
// TODO: does this work with nested scrollable parents?
if ( this.cssPosition !== "fixed" ) {
newLeft = newLeft + this.scrollParent.scrollLeft();
newTop = newTop + this.scrollParent.scrollTop();
}
this.dragEl.css({
left: newLeft + "px",
top: newTop + "px"
});
2011-10-14 18:19:04 +00:00
// Scroll the scrollParent, if needed
this._handleScrolling( event );
},
_handleScrolling: function( event ) {
2011-10-14 18:19:04 +00:00
var scrollTop = this.doc.scrollTop(),
scrollLeft = this.doc.scrollLeft();
// Handle vertical scrolling
if ( ( ( this.overflowHeight + scrollTop ) - event.pageY ) < this.options.scrollSensitivity ) {
2011-10-14 18:19:04 +00:00
this.doc.scrollTop( scrollTop + this.options.scrollSpeed );
}
2011-10-14 18:19:04 +00:00
// Handle horizontal scrolling
if ( ( ( this.overflowWidth + scrollLeft ) - event.pageX ) < this.options.scrollSensitivity ) {
2011-10-14 18:19:04 +00:00
this.doc.scrollLeft( scrollLeft + this.options.scrollSpeed );
}
},
2009-01-24 01:36:22 +00:00
_mouseUp: function( event ) {
2011-10-14 18:19:04 +00:00
this._trigger( "stop", event, this._uiHash() );
2009-01-24 01:36:22 +00:00
2011-10-14 18:19:04 +00:00
if ( this.options.helper ) {
this.dragEl.remove();
}
2011-10-14 18:19:04 +00:00
this.doc
.unbind( "mousemove." + this.widgetName )
.unbind( "mouseup." + this.widgetName );
},
2011-10-14 18:19:04 +00:00
_uiHash: function( event ) {
return {
position: this.position,
offset: this.offset
2008-06-04 02:34:33 +00:00
};
}
2008-06-04 02:34:33 +00:00
});
2011-10-14 18:19:04 +00:00
})( jQuery );