Squashed commit of the following:

Draggable:
 Fixed when cssPosition is being set.
 Scrolling handles non-doc overflow.
 _handleScrolling handles scrolling up and left now
 Made window, doc, and window part of base widget
 All parts of drag may be stopped via stopPropagation
 User can now override position of draggable on start, drag, and stop
 Whitespace fix
 Moved overflowWidth and overflowHeight into overflow.width and overflow.height
This commit is contained in:
= 2011-10-25 21:54:03 -04:00
parent bc921df349
commit 1337573adc
2 changed files with 133 additions and 44 deletions

View File

@ -24,20 +24,16 @@ $.widget( "ui.draggable", {
}, },
// dragEl: element being dragged (original or helper) // dragEl: element being dragged (original or helper)
// position: CSS position of dragEl // position: final CSS position of dragEl
// offset: offset of dragEl // offset: offset of dragEl
// startCoords: clientX/Y of the mousedown (offset of pointer) // startCoords: clientX/Y of the mousedown (offset of pointer)
// startPosition: CSS position prior to drag start // startPosition: CSS position prior to drag start
// startOffset: offset prior to drag start // startOffset: offset prior to drag start
// tempPosition: overridable CSS position of dragEl
// overflowOffset: offset of scroll parent // overflowOffset: offset of scroll parent
// overflowHeight: height of scroll parent // overflow: object containing width and height keys of scroll parent
// overflowWidth: width of scroll parent
_create: function() { _create: function() {
// TODO: add these to the base widget
this.doc = $( this.element[0].ownerDocument );
this.win = $( this.doc[0].defaultView );
this.scrollParent = this.element.scrollParent(); this.scrollParent = this.element.scrollParent();
// Static position elements can't be moved with top/left // Static position elements can't be moved with top/left
@ -79,13 +75,62 @@ $.widget( "ui.draggable", {
}; };
}, },
_handleScrolling: function( event ) {
// TODO: what is expected behavior of absolute/fixed draggable inside a div having overflow:scroll?
var scrollTop = this.scrollParent.scrollTop(),
scrollLeft = this.scrollParent.scrollLeft();
// overflowOffset is only set when scrollParent is not doc/html
if ( !this.overflowOffset ) {
// Handle vertical scrolling
if ( ( ( this.overflow.height + scrollTop ) - event.pageY ) < this.options.scrollSensitivity ) {
this.scrollParent.scrollTop( scrollTop + this.options.scrollSpeed );
}
else if ( event.pageY < ( scrollTop + this.options.scrollSensitivity ) ) {
this.scrollParent.scrollTop( scrollTop - this.options.scrollSpeed );
}
// Handle horizontal scrolling
if ( ( ( this.overflow.width + scrollLeft ) - event.pageX ) < this.options.scrollSensitivity ) {
this.scrollParent.scrollLeft( scrollLeft + this.options.scrollSpeed );
}
else if ( event.pageX < ( scrollLeft + this.options.scrollSensitivity ) ) {
this.scrollParent.scrollLeft( scrollLeft - this.options.scrollSpeed );
}
} else {
// Handle vertical scrolling
if ( ( event.pageY + this.options.scrollSensitivity ) > ( this.overflow.height + this.overflowOffset.top ) ) {
this.scrollParent.scrollTop( scrollTop + this.options.scrollSpeed );
}
else if ( ( event.pageY - this.options.scrollSensitivity ) < this.overflowOffset.top ) {
this.scrollParent.scrollTop( scrollTop - this.options.scrollSpeed );
}
// Handle horizontal scrolling
if ( ( event.pageX + this.options.scrollSensitivity ) > ( this.overflow.width + this.overflowOffset.left ) ) {
this.scrollParent.scrollLeft( scrollLeft + this.options.scrollSpeed );
}
else if ( ( event.pageX - this.options.scrollSensitivity ) < this.overflowOffset.left ) {
this.scrollParent.scrollLeft( scrollLeft - this.options.scrollSpeed );
}
}
},
_mouseDown: function( event ) { _mouseDown: function( event ) {
var newLeft, newTop;
// Prevent text selection, among other things // Prevent text selection, among other things
event.preventDefault(); event.preventDefault();
// The actual dragging element, should always be a jQuery object // The actual dragging element, should always be a jQuery object
this.dragEl = this.element; this.dragEl = this.element;
this.cssPosition = this.dragEl.css( "position" );
// Helper required // Helper required
if ( this.options.helper ) { if ( this.options.helper ) {
@ -108,6 +153,8 @@ $.widget( "ui.draggable", {
.offset( this.element.offset() ); .offset( this.element.offset() );
} }
this.cssPosition = this.dragEl.css( "position" );
// Cache starting absolute and relative positions // Cache starting absolute and relative positions
this.startPosition = this._getPosition(); this.startPosition = this._getPosition();
this.startOffset = this.dragEl.offset(); this.startOffset = this.dragEl.offset();
@ -121,17 +168,32 @@ $.widget( "ui.draggable", {
top: event.clientY top: event.clientY
}; };
// Cache the offset of scrollParent // Cache the offset of scrollParent, if required for _handleScrolling
// TODO: store overflow height/width in a hash instead of separate properties if ( this.scrollParent[0] != this.doc[0] && this.scrollParent[0].tagName != 'HTML') {
this.overflowOffset = this.scrollParent.offset(); this.overflowOffset = this.scrollParent.offset();
this.overflowHeight = ( this.scrollParent[0] === this.doc[0] ) ? }
this.overflow = {};
this.overflow.height = ( this.scrollParent[0] === this.doc[0] ) ?
this.win.height() : this.scrollParent.height(); this.win.height() : this.scrollParent.height();
this.overflowWidth = ( this.scrollParent[0] === this.doc[0] ) ?
this.overflow.width = ( this.scrollParent[0] === this.doc[0] ) ?
this.win.width() : this.scrollParent.width(); this.win.width() : this.scrollParent.width();
// TODO: allow modifying position, just like during drag this._preparePosition( event );
this._trigger( "start", event, this._uiHash() ); this._trigger( "start", event, this._uiHash() );
// TODO: should user be able to change position of draggable, if event stopped?
// If user stops propagation, leave helper there ( if there's one ), disallow any CSS changes
if ( event.cancelBubble === true ) {
this.doc.unbind( "." + this.widgetName );
return;
}
this._setCss( event );
this._bind( this.doc, { this._bind( this.doc, {
mousemove: "_mouseMove", mousemove: "_mouseMove",
mouseup: "_mouseUp" mouseup: "_mouseUp"
@ -139,24 +201,76 @@ $.widget( "ui.draggable", {
}, },
_mouseMove: function( event ) { _mouseMove: function( event ) {
var newLeft, newTop;
this._preparePosition( event );
this._trigger( "drag", event, this._uiHash() );
// TODO: should user be able to change position of draggable, if event stopped?
// If user stops propagation, leave helper there ( if there's one ), disallow any CSS changes
if ( event.cancelBubble === true ) {
this.doc.unbind( "." + this.widgetName );
return;
}
this._setCss( event );
// Scroll the scrollParent, if needed
this._handleScrolling( event );
},
_mouseUp: function( event ) {
this._preparePosition( event );
this._trigger( "stop", event, this._uiHash() );
// TODO: should user be able to change position of draggable, if event stopped?
// If user stops propagation, leave helper there, disallow any CSS changes
if ( event.cancelBubble !== true ) {
this._setCss( event );
if ( this.options.helper ) {
this.dragEl.remove();
}
}
this.doc.unbind( "." + this.widgetName );
},
// Uses event to determine new position of draggable, before any override from callbacks
_preparePosition: function( event ) {
var leftDiff = event.clientX - this.startCoords.left, var leftDiff = event.clientX - this.startCoords.left,
topDiff = event.clientY - this.startCoords.top, topDiff = event.clientY - this.startCoords.top,
newLeft = leftDiff + this.startPosition.left, newLeft = leftDiff + this.startPosition.left,
newTop = topDiff + this.startPosition.top; newTop = topDiff + this.startPosition.top;
// Save off new values for .css() in various callbacks using this function
this.position = { this.position = {
left: newLeft, left: newLeft,
top: newTop top: newTop
}; };
// Save off values to compare user override against automatic coordinates
this.tempPosition = {
left: newLeft,
top: newTop
}
// Refresh offset cache with new positions // Refresh offset cache with new positions
this.offset.left = this.startOffset.left + newLeft; this.offset.left = this.startOffset.left + newLeft;
this.offset.top = this.startOffset.top + newTop; this.offset.top = this.startOffset.top + newTop;
},
this._trigger( "drag", event, this._uiHash() ); // Places draggable where mouse or user from callback indicates
_setCss: function( event ) {
var newLeft, newTop;
// User overriding left/top so shortcut math is no longer valid // User overriding left/top so shortcut math is no longer valid
if ( newLeft !== this.position.left || newTop !== this.position.top ) { if ( this.tempPosition.left !== this.position.left || this.tempPosition.top !== this.position.top ) {
// TODO: can we just store the previous offset values // TODO: can we just store the previous offset values
// and not go through .offset()? // and not go through .offset()?
// refresh offset using slower functions // refresh offset using slower functions
@ -176,34 +290,6 @@ $.widget( "ui.draggable", {
left: newLeft + "px", left: newLeft + "px",
top: newTop + "px" top: newTop + "px"
}); });
// Scroll the scrollParent, if needed
this._handleScrolling( event );
},
_handleScrolling: function( event ) {
var scrollTop = this.doc.scrollTop(),
scrollLeft = this.doc.scrollLeft();
// Handle vertical scrolling
if ( ( ( this.overflowHeight + scrollTop ) - event.pageY ) < this.options.scrollSensitivity ) {
this.doc.scrollTop( scrollTop + this.options.scrollSpeed );
}
// Handle horizontal scrolling
if ( ( ( this.overflowWidth + scrollLeft ) - event.pageX ) < this.options.scrollSensitivity ) {
this.doc.scrollLeft( scrollLeft + this.options.scrollSpeed );
}
},
_mouseUp: function( event ) {
this._trigger( "stop", event, this._uiHash() );
if ( this.options.helper ) {
this.dragEl.remove();
}
this.doc.unbind( "." + this.widgetName );
}, },
_uiHash: function( event ) { _uiHash: function( event ) {

View File

@ -183,6 +183,9 @@ $.Widget.prototype = {
_createWidget: function( options, element ) { _createWidget: function( options, element ) {
element = $( element || this.defaultElement || this )[ 0 ]; element = $( element || this.defaultElement || this )[ 0 ];
this.element = $( element ); this.element = $( element );
this.doc = $( this.element[0].ownerDocument );
this.win = $( this.doc[0].defaultView );
this.body = this.doc.body;
this.options = $.widget.extend( {}, this.options = $.widget.extend( {},
this.options, this.options,
this._getCreateOptions(), this._getCreateOptions(),