r2849 - positionTo: complete rewrite

r2849 - positionTo: complete rewrite


Author: scott.gonzalez
Date: Mon Jun 29 19:04:09 2009
New Revision: 2849
Modified:
branches/dev/positionTo/ui/ui.positionTo.js
Log:
positionTo: complete rewrite
- supports jQuery.noConflict()
- supports multiple items
- chainable
- doesn't modify DOM besides changing position-related styles of element(s)
being positioned
- uses proposed .offset() setter for jQuery 1.4
Modified: branches/dev/positionTo/ui/ui.positionTo.js
==============================================================================
--- branches/dev/positionTo/ui/ui.positionTo.js    (original)
+++ branches/dev/positionTo/ui/ui.positionTo.js    Mon Jun 29 19:04:09 2009
@@ -1,5 +1,5 @@
/*
- * jQuery UI / Utils / positionTo @VERSION
+ * jQuery UI positionTo @VERSION
*
* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt)
@@ -7,138 +7,162 @@
*
* TODO: create document page for positionTo and add link here
*/
-$.fn.positionTo = function(options){
+(function($) {
+
+var horizontalPositions = /left|center|right/,
+    horizontalDefault = 'center',
+    verticalPositions = /top|middle|bottom/,
+    verticalDefault = 'middle';
+
+$.fn.positionTo = function(options) {
    options = $.extend({
-        my: 'left top',
-        at: 'left bottom',
-        offset: '0 0',
        collisionDetect: 'flip',
        stackFix: true
    }, options);
-    var $targetElem = $(options.of);
-
-    // if: the specified target selector (of) does not resolve to an element
in the DOM
-    // then: return an error condition
-    if ($targetElem.length <= 0)
-    {
-        return false;
+    var target = $(options.of),
+        targetProps = {
+            offset: target.offset(),
+            width: target.outerWidth(),
+            height: target.outerHeight()
+        },
+
+        offset = options.offset.replace(/px/gi, '').split(' '),
+        position = targetProps.offset;
+
+    $.each(['my', 'at'], function() {
+        var pos = options[this].split(' ');
+        pos = pos.length == 1
+            ? horizontalPositions.test(pos[0])
+                ? pos.concat([verticalDefault])
+                : verticalPositions.test(pos[0])
+                    ? [horizontalDefault].concat(pos)
+                    : [horizontalDefault, verticalDefault]
+            : pos;
+        pos[0] = horizontalPositions.test(pos[0]) ? pos[0] : horizontalDefault;
+        pos[1] = verticalPositions.test(pos[1]) ? pos[1] : verticalDefault;
+        options[this] = pos;
+    });
+
+    switch (options.at[0]) {
+        case 'left':
+            break;
+        case 'right':
+            position.left += targetProps.width;
+            break;
+        default:
+            position.left += targetProps.width / 2;
+            break;
    }
-    var targetPosition = $targetElem.offset();
-
-    // if: a parent node exists for the target node
-    // then: estimate the target node's position by comparing their relative
absolute offsets
-    if ($targetElem.parent().length)
-    {
-        $targetElem.parent().css('position', 'relative');
-
-        var targetParentOffset = $targetElem.parent().offset();
-        targetPosition = {
-            top: targetPosition.top - targetParentOffset.top,
-            left: targetPosition.left - targetParentOffset.left
-        };
+    switch (options.at[1]) {
+        case 'top':
+            break;
+        case 'bottom':
+            position.top += targetProps.height;
+            break;
+        default:
+            position.top += targetProps.height / 2;
+            break;
    }
-    targetPosition.right = targetPosition.left + $targetElem.outerWidth();
-    targetPosition.bottom = targetPosition.top + $targetElem.outerHeight();
+    return this.each(function() {
+        var elem = $(this),
+            elemProps = {
+                width: elem.outerWidth(),
+                height: elem.outerHeight()
+            };
-    $targetElem.after(this);
-
-    // prep this element for being positioned
-    this.css('display', 'block')
-        .css('position', 'absolute');
-
-    var positionableOffset_x = 0,
-        positionableOffset_y = 0,
-        array_positionableAnchor_chunks = options.my.split(' '),
-        array_targetAnchor_chunks = options.at.split(' '),
-        array_offset_chunks = options.offset.replace(/px/gi, '').split(' ');
-
-    if (array_positionableAnchor_chunks.length == 2)
-    {
-        // now, figure out the horizontal positionable offset
-        switch (array_positionableAnchor_chunks[0])
-        {
-            case 'center':
-                positionableOffset_x -= (this.outerWidth() / 2);
+        switch (options.my[0]) {
+            case 'left':
                break;
-
            case 'right':
-                positionableOffset_x -= this.outerWidth();
+                position.left -= elemProps.width;
+                break;
+            default:
+                position.left -= elemProps.width / 2;
                break;
        }
-        // figure out the vertical positionable offset
-        switch(array_positionableAnchor_chunks[1])
-        {
-            case 'middle':
-                positionableOffset_y -= (this.outerHeight() / 2);
+        switch (options.my[1]) {
+            case 'top':
                break;
-                
            case 'bottom':
-            positionableOffset_y -= this.outerHeight();
+                position.top -= elemProps.height;
                break;
-        }
-}
-
-    if (array_targetAnchor_chunks.length == 2)
-    {
-        // figure out the horizontal target offset
-        switch (array_targetAnchor_chunks[0])
-        {
-            case 'center':
-                positionableOffset_x += (targetPosition.right - targetPosition.left) /
2;
-                break;
-
-            case 'right':
-                positionableOffset_x += (targetPosition.right - targetPosition.left);
+            default:
+                position.top -= elemProps.height / 2;
                break;
        }
-        // figure out the vertical target offset
-        switch (array_targetAnchor_chunks[1])
-        {
-            case 'middle':
-                positionableOffset_y += (targetPosition.bottom - targetPosition.top) /
2;
-                break;
+        // TODO: offset option
+        // TODO: collision option
+        // TODO: by option
+        // TODO: stackfix option
-            case 'bottom':
-                positionableOffset_y += (targetPosition.bottom - targetPosition.top);
-                break;
-        }
-    }
+        elem.offset(position);
+    });
+};
-    if (array_offset_chunks.length == 2)
-    {
-        var offset_horizontal_px = parseInt(array_offset_chunks[0]);
-        // if: a valid integer was specified for the horizontal offset
-        // then: apply it to the calculated horizontal offset
-        if (!isNaN(offset_horizontal_px))
-        {
-            positionableOffset_x += offset_horizontal_px;
-        }
-        var offset_vertical_px = parseInt(array_offset_chunks[1]);
-        // if: a valid integer was specified for the vertical offset
-        // then: apply it to the calculated vertical offset
-        if (!isNaN(offset_vertical_px))
-        {
-            positionableOffset_y += offset_vertical_px;
-        }
-    }
-    else if (array_offset_chunks.length == 1)
-    {
-        var offset_px = parseInt(array_offset_chunks[0]);
-        // if: a valid integer was specified for the offset
-        // then: apply it to the calculated horizontal and vertical offsets
-        if (!isNaN(offset_px))
-        {
-            positionableOffset_x += offset_px;
-            positionableOffset_y += offset_px;
-        }
+
+// the following functionality is planned for jQuery 1.4
+// copied from http://plugins.jquery.com/files/offset.js.txt
+$.fn.extend({
+
+    /**
+     * Stores the original version of offset(), so that we don't lose it
+     */
+    _offset : $.fn.offset,
+    
+    /**
+     * Set or get the specific left and top position of the matched
+     * elements, relative the the browser window by calling setXY
+     * @param {Object} newOffset
+     */
+    offset : function(newOffset){
+     return !newOffset ? this._offset() : this.each(function(){
+            var el = this;
+            
+            var hide = false;
+            
+            if($(el).css('display')=='none'){
+                hide = true;
+                $(el).show();
+            };
+            
+            var style_pos = $(el).css('position');
+            
+            // default to relative
+            if (style_pos == 'static') {
+                $(el).css('position','relative');
+                style_pos = 'relative';
+            };
+            
+            var offset = $(el).offset();
+            
+            if (offset){
+                var delta = {
+                    left : parseInt($(el).css('left'), 10),
+                    top: parseInt($(el).css('top'), 10)
+                };
+                
+                // in case of 'auto'
+                if (isNaN(delta.left))
+                    delta.left = (style_pos == 'relative') ? 0 : el.offsetLeft;
+                if (isNaN(delta.top))
+                    delta.top = (style_pos == 'relative') ? 0 : el.offsetTop;
+                
+                if (newOffset.left || newOffset.left===0)
+                    $(el).css('left',newOffset.left - offset.left + delta.left + 'px');
+            
+                if (newOffset.top || newOffset.top===0)
+                    $(el).css('top',newOffset.top - offset.top + delta.top + 'px');
+            };
+            if(hide) $(el).hide();
+        });
    }
-    this.css('left', (targetPosition.left + positionableOffset_x) + 'px')
-        .css('top', (targetPosition.top + positionableOffset_y) + 'px');
-};
+});
+
+})(jQuery);