From 6f051d5d6a8eaf6fcc2a08ff68dbf5378029abc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Scott=20Gonz=C3=A1lez?= Date: Tue, 22 Mar 2011 12:25:25 -0400 Subject: [PATCH] Position: Merged offset option into my and at options and added support for percentage-based offsets. Fixes #6981 - Position: Merge offset option into my and at options. Fixes #7028 - Position: Allow percent-based offsets. --- demos/position/cycler.html | 6 +- tests/unit/position/position_core.js | 36 ++++++++++- ui/jquery.ui.position.js | 90 ++++++++++++++++++++++++---- 3 files changed, 114 insertions(+), 18 deletions(-) diff --git a/demos/position/cycler.html b/demos/position/cycler.html index b52e2272461..521b8d56585 100644 --- a/demos/position/cycler.html +++ b/demos/position/cycler.html @@ -33,16 +33,14 @@ $.fn.left = function( using ) { return this.position2({ my: "right middle", - at: "left middle", - offset: "25 0", + at: "left+25 middle", using: using }); } $.fn.right = function( using ) { return this.position2({ my: "left middle", - at: "right middle", - offset: "-25 0", + at: "right-25 middle", using: using }); } diff --git a/tests/unit/position/position_core.js b/tests/unit/position/position_core.js index 643561c2028..66f7a85049c 100644 --- a/tests/unit/position/position_core.js +++ b/tests/unit/position/position_core.js @@ -207,7 +207,41 @@ test('of', function() { }, 'event - left top, right bottom'); }); -test('offset', function() { +test('offsets', function() { + $('#elx').position({ + my: 'left top', + at: 'left+10 bottom+10', + of: '#parentx', + collision: 'none' + }); + same($('#elx').offset(), { top: 70, left: 50 }, 'offsets in at'); + + $('#elx').position({ + my: 'left+10 top-10', + at: 'left bottom', + of: '#parentx', + collision: 'none' + }); + same($('#elx').offset(), { top: 50, left: 50 }, 'offsets in my'); + + $('#elx').position({ + my: 'left top', + at: 'left+50% bottom-10%', + of: '#parentx', + collision: 'none' + }); + same($('#elx').offset(), { top: 58, left: 50 }, 'percentage offsets in at'); + + $('#elx').position({ + my: 'left-30% top+50%', + at: 'left bottom', + of: '#parentx', + collision: 'none' + }); + same($('#elx').offset(), { top: 65, left: 37 }, 'percentage offsets in my'); +}); + +test('offset - deprecated', function() { $('#elx').position({ my: 'left top', at: 'left bottom', diff --git a/ui/jquery.ui.position.js b/ui/jquery.ui.position.js index 9d436ccf3b7..2108c1d7cd1 100644 --- a/ui/jquery.ui.position.js +++ b/ui/jquery.ui.position.js @@ -13,6 +13,9 @@ $.ui = $.ui || {}; var horizontalPositions = /left|center|right/, verticalPositions = /top|center|bottom/, + roffset = /[+-]\d+%?/, + rposition = /^\w+/, + rpercent = /%$/, center = "center", _position = $.fn.position; @@ -27,7 +30,8 @@ $.fn.position = function( options ) { var target = $( options.of ), targetElem = target[0], collision = ( options.collision || "flip" ).split( " " ), - offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ], + offsets = {}, + atOffset, targetWidth, targetHeight, basePosition; @@ -54,7 +58,10 @@ $.fn.position = function( options ) { // force my and at to have valid horizontal and vertical positions // if a value is missing or invalid, it will be converted to center $.each( [ "my", "at" ], function() { - var pos = ( options[this] || "" ).split( " " ); + var pos = ( options[this] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + if ( pos.length === 1) { pos = horizontalPositions.test( pos[0] ) ? pos.concat( [center] ) : @@ -64,7 +71,20 @@ $.fn.position = function( options ) { } pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center; pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center; - options[ this ] = pos; + + // calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos [ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; }); // normalize collision option @@ -72,13 +92,6 @@ $.fn.position = function( options ) { collision[ 1 ] = collision[ 0 ]; } - // normalize offset option - offset[ 0 ] = parseInt( offset[0], 10 ) || 0; - if ( offset.length === 1 ) { - offset[ 1 ] = offset[ 0 ]; - } - offset[ 1 ] = parseInt( offset[1], 10 ) || 0; - if ( options.at[0] === "right" ) { basePosition.left += targetWidth; } else if ( options.at[0] === center ) { @@ -91,8 +104,14 @@ $.fn.position = function( options ) { basePosition.top += targetHeight / 2; } - basePosition.left += offset[ 0 ]; - basePosition.top += offset[ 1 ]; + atOffset = [ + parseInt( offsets.at[ 0 ], 10 ) * + ( rpercent.test( offsets.at[ 0 ] ) ? targetWidth / 100 : 1 ), + parseInt( offsets.at[ 1 ], 10 ) * + ( rpercent.test( offsets.at[ 1 ] ) ? targetHeight / 100 : 1 ) + ]; + basePosition.left += atOffset[ 0 ], + basePosition.top += atOffset[ 1 ]; return this.each(function() { var elem = $( this ), @@ -105,6 +124,12 @@ $.fn.position = function( options ) { collisionHeight = elemHeight + marginTop + ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ), position = $.extend( {}, basePosition ), + myOffset = [ + parseInt( offsets.my[ 0 ], 10 ) * + ( rpercent.test( offsets.my[ 0 ] ) ? elem.outerWidth() / 100 : 1 ), + parseInt( offsets.my[ 1 ], 10 ) * + ( rpercent.test( offsets.my[ 1 ] ) ? elem.outerHeight() / 100 : 1 ) + ], collisionPosition; if ( options.my[0] === "right" ) { @@ -119,6 +144,9 @@ $.fn.position = function( options ) { position.top -= elemHeight / 2; } + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + // prevent fractions (see #5280) position.left = Math.round( position.left ); position.top = Math.round( position.top ); @@ -138,7 +166,7 @@ $.fn.position = function( options ) { collisionPosition: collisionPosition, collisionWidth: collisionWidth, collisionHeight: collisionHeight, - offset: offset, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], my: options.my, at: options.at }); @@ -212,4 +240,40 @@ $.ui.position = { } }; +// DEPRECATED +if ( $.uiBackCompat !== false ) { + // offset option + (function( $ ) { + var _position = $.fn.position; + $.fn.position = function( options ) { + if ( !options || !( "offset" in options ) ) { + return _position.call( this, options ); + } + var offset = options.offset.split( " " ), + at = options.at.split( " " ); + if ( offset.length === 1 ) { + offset[ 1 ] = offset[ 0 ]; + } + if ( /^\d/.test( offset[ 0 ] ) ) { + offset[ 0 ] = "+" + offset[ 0 ]; + } + if ( /^\d/.test( offset[ 1 ] ) ) { + offset[ 1 ] = "+" + offset[ 1 ]; + } + if ( at.length === 1 ) { + if ( /left|center|right/.test( at[ 0 ] ) ) { + at[ 1 ] = "center"; + } else { + at[ 1 ] = at[ 0 ]; + at[ 0 ] = "center"; + } + } + return _position.call( this, $.extend( options, { + at: at[ 0 ] + offset[ 0 ] + " " + at[ 1 ] + offset[ 1 ], + offset: undefined + } ) ); + } + }( jQuery )); +} + }( jQuery ));