From ee094ccf4ddc20e75cf0b6c3ed752f1302336eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Scott=20Gonz=C3=A1lez?= Date: Fri, 14 Oct 2011 14:19:04 -0400 Subject: [PATCH] Draggable: Cleanup. --- ui/jquery.ui.draggable.js | 239 +++++++++++++------------------------- 1 file changed, 78 insertions(+), 161 deletions(-) diff --git a/ui/jquery.ui.draggable.js b/ui/jquery.ui.draggable.js index 2fa52cc80..1e9fb4cda 100644 --- a/ui/jquery.ui.draggable.js +++ b/ui/jquery.ui.draggable.js @@ -1,11 +1,11 @@ /* - * jQuery UI Draggable 2.0.0 + * jQuery UI Draggable @VERSION * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * - * http://docs.jquery.com/UI/Draggables + * http://docs.jquery.com/UI/Draggable * * Depends: * jquery.ui.core.js @@ -14,90 +14,59 @@ (function( $, undefined ) { $.widget( "ui.draggable", { - + version: "@VERSION", widgetEventPrefix: "drag", options: { - - scrollSpeed: 20, - scrollSensitivity:20, - helper: false - + helper: false, + scrollSensitivity: 20, + scrollSpeed: 20 }, - // TODO: actually remove data - destroy: function() { - return this; - }, + // 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() { - - // Either initialized element or the helper - this.dragEl = false, - - this.position = {}, - this.offset = {}, - - // Start X/Y coords of mouse before drag - this.startCoords = {}, - - // Start position of element before drag - this.startPosition = {}, - - // Start offset of element before drag - this.startOffset = {}, + // TODO: add these to the base widget + this.doc = $( this.element[0].ownerDocument ); + this.win = $( this.doc[0].defaultView ); this.scrollParent = this.element.scrollParent(); - // Offset of scrollParent, used for auto-scrolling - this.overflowOffset = {}; - - // Height of scrollParent, used for auto-scrolling - this.overflowHeight = 0; - - // Width of scrollParent, used for auto-scrolling - this.overflowWidth = 0; - - // Static position elements can"t be moved with top/left + // Static position elements can't be moved with top/left if ( this.element.css( "position" ) === "static" ) { this.element.css( "position", "relative" ); } - - // Using proxy to avoid anon functions using self to pass "this" along - this.element.bind( "mousedown." + this.widgetName, $.proxy( this._mouseDown, this ) ); + // TODO: use _bind() + this.element.bind( "mousedown." + this.widgetName, $.proxy( this, "_mouseDown" ) ); }, - _usingHelper : function() { - return ( this.options.helper === true || typeof this.options.helper === 'function' ); - }, - - _setPosition: function() { - + // TODO: why is relative handled differently than fixed/absolute? + _getPosition: function() { var left, top, position, - scrollTop = this.scrollParent.scrollTop(), - scrollLeft = this.scrollParent.scrollLeft(); - - // Helper is appended to body so offset of element is all that's needed - if ( this._usingHelper() ) { - return this.element.offset(); - } + scrollTop = this.scrollParent.scrollTop(), + scrollLeft = this.scrollParent.scrollLeft(); // If fixed or absolute if ( this.cssPosition !== "relative" ) { - position = this.dragEl.position(); // Take into account scrollbar - position.top = position.top - scrollTop; - position.left = position.left - scrollLeft + position.top -= scrollTop; + position.left -= scrollLeft return position; - } - /** When using relative, css values are checked **/ - + // When using relative, css values are checked left = this.dragEl.css( "left" ); top = this.dragEl.css( "top" ); @@ -106,64 +75,42 @@ $.widget( "ui.draggable", { top = ( top === "auto" ) ? 0: parseInt( top, 10 ); return { - left: left - scrollLeft, top: top - scrollTop - }; - }, _mouseDown: function( event ) { - - // Stop browser from highlighting, among other things - event.preventDefault(); + // 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" ); - // Helper required, so clone, hide, and set reference - if ( this._usingHelper() ) { - - // If getting a cloned helper + // Helper required + if ( this.options.helper ) { + // clone if ( this.options.helper === true ) { - - this.dragEl = this.element.clone(); - // If source element has an ID, change ID of helper to avoid overlap + this.dragEl = this.element.clone(); if ( this.element.attr( "id" ) ) { - this.dragEl.attr( "id", this.element.attr( "id" ) + "-" + this.widgetName ); - } - } else { - - this.dragEl = this.options.helper(); - - // If function was passed, it should return a DOMElement - if ( typeof this.dragEl.nodeType !== 'number' ) { - throw "Helper function must return a DOMElement"; - } - - this.dragEl = $( this.dragEl ); - + // TODO: figure out the signature for this; see #4957 + this.dragEl = $( this.options.helper() ); } - // Automatically make helper absolute this.dragEl - .css({ - position: "absolute" - }); - - $( "body" ).append( this.dragEl ); - + // TODO: should we move this to the stylesheet and use a class? + .css( "position", "absolute" ) + .appendTo( this.doc[0].body ) + .offset( this.element.offset() ); } // Cache starting absolute and relative positions - this.startPosition = this._setPosition(); + this.startPosition = this._getPosition(); this.startOffset = this.dragEl.offset(); // Cache current position and offset @@ -176,38 +123,28 @@ $.widget( "ui.draggable", { }; // Cache the offset of scrollParent + // TODO: store overflow height/width in a hash instead of separate properties this.overflowOffset = this.scrollParent.offset(); - this.overflowHeight = ( this.scrollParent[0] === document ) ? $(window).height() : this.scrollParent.height(); - this.overflowWidth = ( this.scrollParent[0] === document ) ? $(window).width() : this.scrollParent.width(); + 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(); - this._trigger( "start", event ); - - $(document).bind( "mousemove." + this.widgetName, $.proxy( this._mouseMove, this ) ) - .bind( "mouseup." + this.widgetName, $.proxy( this._mouseUp, this ) ); - - - // Set the helper up by actual element - if ( this._usingHelper() ) { - - // get the absolute position of element so that helper will know where to go - elOffset = this.element.offset(); - - this.dragEl.css({ - display: "block", - top: elOffset.top + "px", - left: elOffset.left + "px" - }); - - } + // 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, - topDiff = event.clientY - this.startCoords.top, - newLeft = leftDiff + this.startPosition.left, - newTop = topDiff + this.startPosition.top; + topDiff = event.clientY - this.startCoords.top, + newLeft = leftDiff + this.startPosition.left, + newTop = topDiff + this.startPosition.top; this.position = { left: newLeft, @@ -218,87 +155,67 @@ $.widget( "ui.draggable", { this.offset.left = this.startOffset.left + newLeft; this.offset.top = this.startOffset.top + newTop; - this._trigger( "drag", event ); + this._trigger( "drag", event, this._uiHash() ); // User overriding left/top so shortcut math is no longer valid if ( newLeft !== this.position.left || newTop !== this.position.top ) { - + // TODO: can we just store the previous offset values + // and not go through .offset()? // refresh offset using slower functions this.offset = this.dragEl.offset(); - } - + newLeft = this.position.left; newTop = this.position.top; - - if ( this.cssPosition !== 'fixed' ) { - + + // 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" - }); - + // Scroll the scrollParent, if needed this._handleScrolling( event ); - }, _handleScrolling: function( event ) { - - var doc = $(document), - scrollTop = doc.scrollTop(), - scrollLeft = doc.scrollLeft(); + var scrollTop = this.doc.scrollTop(), + scrollLeft = this.doc.scrollLeft(); // Handle vertical scrolling if ( ( ( this.overflowHeight + scrollTop ) - event.pageY ) < this.options.scrollSensitivity ) { - doc.scrollTop( scrollTop + this.options.scrollSpeed ); - } - - // Handle horizontal scrolling - if ( ( ( this.overflowWidth + scrollLeft ) - event.pageX ) < this.options.scrollSensitivity ) { - doc.scrollLeft( scrollLeft + this.options.scrollSpeed ); + 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() ); - var doc = $(document); - - this._trigger( "stop", event ); - - this.startCoords = {}; - - if ( this._usingHelper() ) { + if ( this.options.helper ) { this.dragEl.remove(); } - doc.unbind( "mousemove." + this.widgetName ); - doc.unbind( "mouseup." + this.widgetName ); - + this.doc + .unbind( "mousemove." + this.widgetName ) + .unbind( "mouseup." + this.widgetName ); }, - _uiHash: function(event) { - + _uiHash: function( event ) { return { position: this.position, offset: this.offset }; - } - }); -$.extend($.ui.draggable, { - version: "2.0.0" -}); - - -})(jQuery); +})( jQuery );