r1005 - trunk/ui

r1005 - trunk/ui


Author: paul.bakaus
Date: Tue Nov 25 01:57:41 2008
New Revision: 1005
Modified:
trunk/ui/ui.sortable.js
Log:
sortable:
- merged back all position and scroll fixed from draggables
- renamed accurate to accurateIntersection and set it to true by default
- refactored intersection code (no change in logic)
- added forceHelperSize option (default: false), a forced helper size is
also triggered when the generated helper doesn't have any styles set for
width/height, so this option won't be needed in most cases
Modified: trunk/ui/ui.sortable.js
==============================================================================
--- trunk/ui/ui.sortable.js    (original)
+++ trunk/ui/ui.sortable.js    Tue Nov 25 01:57:41 2008
@@ -87,59 +87,58 @@
        this.refreshPositions();
        //Create and append the visible helper
-        this.helper = this.createHelper(event);
+        this.helper = this._createHelper(event);
+        
+        //Cache the helper size
+        this._cacheHelperProportions();
        /*
         * - Position generation -
         * This block generates everything position related - it's the core of
draggables.
         */
-        this.margins = {                                                                                //Cache the margins
-            left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
-            top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
-        };
-
-        this.offset = this.currentItem.offset();                                                        //The element's
absolute position on the page
-        this.offset = {                                                                                    //Substract the margins from the
element's absolute offset
+        //Cache the margins of the original element
+        this._cacheMargins();
+        
+        //Store the helper's css position
+        this.cssPosition = this.helper.css("position");
+        this.scrollParent = this.helper.scrollParent();
+        
+        //The element's absolute position on the page minus margins
+        this.offset = this.currentItem.offset();                                                        
+        this.offset = {
            top: this.offset.top - this.margins.top,
            left: this.offset.left - this.margins.left
        };
+        
+        $.extend(this.offset, {
+            click: { //Where the click happened, relative to the element
+                left: event.pageX - this.offset.left,
+                top: event.pageY - this.offset.top
+            },
+            parent: this._getParentOffset(),
+            relative: this._getRelativeOffset() //This is a relative to absolute
position minus the actual position calculation - only used for relative
positioned helper
+        });
-        this.offset.click = {                                                                            //Where the click happened,
relative to the element
-            left: event.pageX - this.offset.left,
-            top: event.pageY - this.offset.top
-        };
-
-        this.offsetParent = this.helper.offsetParent();                                                    //Get the
offsetParent and cache its position
-        var po = this.offsetParent.offset();
-
-        this.offsetParentBorders = {
-            top: (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
-            left: (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
-        };
-
-        this.offset.parent = {                                                                            //Store its position plus border
-            top: po.top + this.offsetParentBorders.top,
-            left: po.left + this.offsetParentBorders.left
-        };
-
-        this.originalPosition = this._generatePosition(event);                //Generate the
original position
-        this.domPosition = { prev: this.currentItem.prev()[0], parent:
this.currentItem.parent()[0] }; //Cache the former DOM position
-
-        //If o.placeholder is used, create a new element at the given position
with the class
-        this.helperProportions = { width: this.helper.outerWidth(), height:
this.helper.outerHeight() };//Cache the helper size
-
-        if(o.helper == "original") {
-            this._storedCSS = { position: this.currentItem.css("position"), top:
this.currentItem.css("top"), left: this.currentItem.css("left"), clear:
this.currentItem.css("clear") };
-        } else {
-            this.currentItem.hide(); //Hide the original, won't cause anything bad
this way
+        //Adjust the mouse offset relative to the helper if 'cursorAt' is
supplied
+        if(o.cursorAt)
+            this._adjustOffsetFromHelper(o.cursorAt);    
+
+        //Generate the original position
+        this.originalPosition = this._generatePosition(event);
+
+        //Cache the former DOM position
+        this.domPosition = { prev: this.currentItem.prev()[0], parent:
this.currentItem.parent()[0] };
+        
+        //Set a containment if given in the options
+        if(o.containment)
+            this._setContainment();
+
+        //If the helper is not the original, hide the original so it's not
playing any role during the drag, won't cause anything bad this way
+        if(this.helper[0] != this.currentItem[0]) {
+            this.currentItem.hide();
        }
-        //Position it absolutely and add a helper class
-        this.helper
-            .css({ position: 'absolute', clear: 'both' })
-            .addClass('ui-sortable-helper');
-
        //Create the placeholder
        this._createPlaceholder();
@@ -148,42 +147,8 @@
        //Recache the helper size
        if(!this._preserveHelperProportions)
-            this.helperProportions = { width: this.helper.outerWidth(), height:
this.helper.outerHeight() };
-
-        if(o.cursorAt) {
-            if(o.cursorAt.left != undefined) this.offset.click.left =
o.cursorAt.left;
-            if(o.cursorAt.right != undefined) this.offset.click.left =
this.helperProportions.width - o.cursorAt.right;
-            if(o.cursorAt.top != undefined) this.offset.click.top = o.cursorAt.top;
-            if(o.cursorAt.bottom != undefined) this.offset.click.top =
this.helperProportions.height - o.cursorAt.bottom;
-        }
-
-        /*
-         * - Position constraining -
-         * Here we prepare position constraining like grid and containment.
-         */
+            this._cacheHelperProportions();
-        if(o.containment) {
-            if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
-            if(o.containment == 'document' || o.containment == 'window')
this.containment = [
-                0 - this.offset.parent.left,
-                0 - this.offset.parent.top,
-                $(o.containment == 'document' ? document : window).width() -
this.offset.parent.left - this.helperProportions.width - this.margins.left
- (parseInt(this.element.css("marginRight"),10) || 0),
-                ($(o.containment == 'document' ? document : window).height() ||
document.body.parentNode.scrollHeight) - this.offset.parent.top -
this.helperProportions.height - this.margins.top -
(parseInt(this.element.css("marginBottom"),10) || 0)
-            ];
-
-            if(!(/^(document|window|parent)$/).test(o.containment)) {
-                var ce = $(o.containment)[0];
-                var co = $(o.containment).offset();
-                var over = ($(ce).css("overflow") != 'hidden');
-
-                this.containment = [
-                    co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) -
this.offset.parent.left,
-                    co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) -
this.offset.parent.top,
-                    co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) :
ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) -
this.offset.parent.left - this.helperProportions.width - this.margins.left
- (parseInt(this.currentItem.css("marginRight"),10) || 0),
-                    co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) :
ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) -
this.offset.parent.top - this.helperProportions.height - this.margins.top -
(parseInt(this.currentItem.css("marginBottom"),10) || 0)
-                ];
-            }
-        }
        //Post 'activate' events to possible containers
        if(!noActivation) {
@@ -199,12 +164,14 @@
        this.dragging = true;
+        this.helper.addClass('ui-sortable-helper');
        this._mouseDrag(event); //Execute the drag once - this causes the helper
not to be visible before getting its correct position
        return true;
    },
    _mouseDrag: function(event) {
+        
        //Compute the helpers position
        this.position = this._generatePosition(event);
        this.positionAbs = this._convertPositionTo("absolute");
@@ -219,32 +186,26 @@
        //Regenerate the absolute position used for position checks
        this.positionAbs = this._convertPositionTo("absolute");
-        //Set the helper's position
-        if (this.helper) {
-            this.helper[0].style.left = this.position.left+'px';
-            this.helper[0].style.top = this.position.top+'px';
-        }
+        //Set the helper position
+        if(!this.options.axis || this.options.axis != "y")
this.helper[0].style.left = this.position.left+'px';
+        if(!this.options.axis || this.options.axis != "x")
this.helper[0].style.top = this.position.top+'px';
+        
        //Rearrange
        for (var i = this.items.length - 1; i >= 0; i--) {
-            var item = this.items[i], intersection =
this._intersectsWithPointer(item);
-
+            //Cache variables and intersection, continue if no intersection
+            var item = this.items[i], itemElement = item.item[0], intersection =
this._intersectsWithPointer(item);
            if (!intersection) continue;
-            var itemChecked = this.items[i].item[0];
-
-            if(itemChecked != this.currentItem[0] //cannot intersect with itself
-                &&    this.placeholder[intersection == 1 ? "next" : "prev"]()[0] !=
itemChecked //no useless actions that have been done before
-                &&    !$.ui.contains(this.placeholder[0], itemChecked) //no action if the
item moved is the parent of the item checked
-                && (this.options.type
== 'semi-dynamic' ? !$.ui.contains(this.element[0], itemChecked) : true)
+            if(itemElement != this.currentItem[0] //cannot intersect with itself
+                &&    this.placeholder[intersection == 1 ? "next" : "prev"]()[0] !=
itemElement //no useless actions that have been done before
+                &&    !$.ui.contains(this.placeholder[0], itemElement) //no action if the
item moved is the parent of the item checked
+                && (this.options.type
== 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)
            ) {
                this.direction = intersection == 1 ? "down" : "up";
-                if (this.options.tolerance == "pointer") {
-                    this.options.sortIndicator.call(this, event, item);
-                }
-                else if (this.options.tolerance == "guess" &&
this._intersectsGuess(item)) {
+                if (this.options.tolerance == "pointer" || (this.options.tolerance
== "guess" && this._intersectsGuess(item))) {
                    this.options.sortIndicator.call(this, event, item);
                }
@@ -260,10 +221,9 @@
        if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
        //Call callbacks
-        this.element.triggerHandler("sort", [event, this._ui()],
this.options["sort"]);
+        this._trigger('sort', event, this._ui());
        this.lastPositionAbs = this.positionAbs;
-
        return false;
    },
@@ -365,15 +325,26 @@
    /* Be careful with the following core functions */
    _intersectsWith: function(item) {
-        var x1 = this.positionAbs.left, x2 = x1 + this.helperProportions.width,
-        y1 = this.positionAbs.top, y2 = y1 + this.helperProportions.height;
-        var l = item.left, r = l + item.width,
-        t = item.top, b = t + item.height;
-
-        var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
+        
+        var x1 = this.positionAbs.left,
+            x2 = x1 + this.helperProportions.width,
+            y1 = this.positionAbs.top,
+            y2 = y1 + this.helperProportions.height;
+            
+        var l = item.left,
+            r = l + item.width,
+            t = item.top,
+            b = t + item.height;
+
+        var dyClick = this.offset.click.top,
+            dxClick = this.offset.click.left;
+        
        var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 +
dxClick) > l && (x1 + dxClick) < r;
-        if(this.options.tolerance == "pointer" ||
this.options.forcePointerForContainers || (this.options.tolerance
== "guess" && this.helperProportions[this.floating ? 'width' : 'height'] >
item[this.floating ? 'width' : 'height'])) {
+        if(     this.options.tolerance == "pointer"
+            || this.options.forcePointerForContainers
+            || (this.options.tolerance == "guess" &&
this.helperProportions[this.floating ? 'width' : 'height'] >
item[this.floating ? 'width' : 'height'])
+        ) {
            return isOverElement;
        } else {
@@ -386,110 +357,45 @@
    },
    _intersectsWithPointer: function(item) {
-        var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
-        var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
-        var itemHeight = item.height, itemWidth = item.width;
-        var itemTop = item.top, itemLeft = item.left;
-
-        if (this.cancelIntersection) {
-            return false;
-        }
-
-        var isOverElementHeight = $.ui.isOverAxis(helperTop + dyClick, itemTop,
itemHeight);
-        var isOverElementWidth = $.ui.isOverAxis(helperLeft + dxClick, itemLeft,
itemWidth);
-        var isOverElement = isOverElementHeight && isOverElementWidth;
-        var verticalDirection = this._getDragVerticalDirection();
-        var horizontalDirection = this._getDragHorizontalDirection();
-
-        if (!isOverElement) return false;
-
-        if (this.floating) {
-            if (!horizontalDirection) {
-                return verticalDirection == "down" ? 2 : 1;
-            }
-
-            return horizontalDirection == "right" ? 2 : 1;
-        }
-        else {
+        var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top +
this.offset.click.top, item.top, item.height),
+            isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left +
this.offset.click.left, item.left, item.width),
+            isOverElement = isOverElementHeight && isOverElementWidth,
+            verticalDirection = this._getDragVerticalDirection(),
+            horizontalDirection = this._getDragHorizontalDirection();
-            if (!verticalDirection) {
-                return false;
-            }
+        if (!isOverElement)
+            return false;
-            return verticalDirection == "down" ? 2 : 1;
-        }
+        return this.floating ?
+            ( ((horizontalDirection && horizontalDirection == "right") ||
verticalDirection == "down") ? 2 : 1 )
+            : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
-        return false;
    },
    _intersectsGuess: function(item) {
-        var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
-        var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
-        var itemHeight = item.height, itemWidth = item.width;
-        var itemTop = item.top, itemLeft = item.left;
-
-        var isOverBottomHalf = $.ui.isOverAxis(helperTop + dyClick, itemTop +
(itemHeight/2), itemHeight);
-        var isOverTopHalf = !isOverBottomHalf;
-        var isOverRightHalf = $.ui.isOverAxis(helperLeft + dxClick, itemLeft +
(itemWidth/2), itemWidth);
-        var isOverLeftHalf = !isOverRightHalf;
-        var verticalDirection = this._getDragVerticalDirection();
-        var horizontalDirection = this._getDragHorizontalDirection();
-
-        var verticalIntersection = function() {
-            if (!verticalDirection) {
-                return false;
-            }
-            if (verticalDirection == "down" && isOverBottomHalf ||
-                verticalDirection == "up" && isOverTopHalf) {
-                return true;
-            }
-        };
+        
+        var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top +
this.offset.click.top, item.top + (item.height/2), item.height),
+            isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left +
this.offset.click.left, item.left + (item.width/2), item.width),
+            verticalDirection = this._getDragVerticalDirection(),
+            horizontalDirection = this._getDragHorizontalDirection();
-        var horizontalIntersection = function() {
-            if (!horizontalDirection) {
-                return verticalIntersection();
-            }
-            if (horizontalDirection == "left" && isOverLeftHalf ||
-                horizontalDirection == "right" && isOverRightHalf) {
-                return true;
-            }
-        };
-
-        if (this.floating) {
-            return horizontalIntersection();
-        }
-        else {
-            return verticalIntersection();
+        if (this.floating && horizontalDirection) {
+            return ((horizontalDirection == "right" && isOverRightHalf) ||
(horizontalDirection == "left" && !isOverRightHalf));
+        } else {
+            return verticalDirection && ((verticalDirection == "down" &&
isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
        }
-        return false;
    },
    _getDragVerticalDirection: function() {
-        var helperTop = this.positionAbs.top;
-        var lastTop = this.lastPositionAbs.top;
-        var delta = helperTop - lastTop;
-
-        if (delta == 0) {
-            return false;
-        }
-
-        var direction = delta > 0 ? "down" : "up";
-        return direction;
+        var delta = this.positionAbs.top - this.lastPositionAbs.top;
+        return delta != 0 && (delta > 0 ? "down" : "up");
    },
    _getDragHorizontalDirection: function() {
-        var helperLeft = this.positionAbs.left;
-        var lastLeft = this.lastPositionAbs.left;
-        var delta = helperLeft - lastLeft;
-
-        if (delta == 0) {
-            return false;
-        }
-
-        var direction = delta > 0 ? "right" : "left";
-        return direction;
+        var delta = this.positionAbs.left - this.lastPositionAbs.left;
+        return delta != 0 && (delta > 0 ? "right" : "left");
    },
    refresh: function(event) {
@@ -586,9 +492,8 @@
    refreshPositions: function(fast) {
        //This has to be redone because due to the item being moved out/into the
offsetParent, the offsetParent's position will change
-        if(this.offsetParent) {
-            var po = this.offsetParent.offset();
-            this.offset.parent = { top: po.top + th