Skip to content

Commit 6f051d5

Browse files
committed
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.
1 parent d4dadd1 commit 6f051d5

File tree

3 files changed

+114
-18
lines changed

3 files changed

+114
-18
lines changed

demos/position/cycler.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,14 @@
3333
$.fn.left = function( using ) {
3434
return this.position2({
3535
my: "right middle",
36-
at: "left middle",
37-
offset: "25 0",
36+
at: "left+25 middle",
3837
using: using
3938
});
4039
}
4140
$.fn.right = function( using ) {
4241
return this.position2({
4342
my: "left middle",
44-
at: "right middle",
45-
offset: "-25 0",
43+
at: "right-25 middle",
4644
using: using
4745
});
4846
}

tests/unit/position/position_core.js

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,41 @@ test('of', function() {
207207
}, 'event - left top, right bottom');
208208
});
209209

210-
test('offset', function() {
210+
test('offsets', function() {
211+
$('#elx').position({
212+
my: 'left top',
213+
at: 'left+10 bottom+10',
214+
of: '#parentx',
215+
collision: 'none'
216+
});
217+
same($('#elx').offset(), { top: 70, left: 50 }, 'offsets in at');
218+
219+
$('#elx').position({
220+
my: 'left+10 top-10',
221+
at: 'left bottom',
222+
of: '#parentx',
223+
collision: 'none'
224+
});
225+
same($('#elx').offset(), { top: 50, left: 50 }, 'offsets in my');
226+
227+
$('#elx').position({
228+
my: 'left top',
229+
at: 'left+50% bottom-10%',
230+
of: '#parentx',
231+
collision: 'none'
232+
});
233+
same($('#elx').offset(), { top: 58, left: 50 }, 'percentage offsets in at');
234+
235+
$('#elx').position({
236+
my: 'left-30% top+50%',
237+
at: 'left bottom',
238+
of: '#parentx',
239+
collision: 'none'
240+
});
241+
same($('#elx').offset(), { top: 65, left: 37 }, 'percentage offsets in my');
242+
});
243+
244+
test('offset - deprecated', function() {
211245
$('#elx').position({
212246
my: 'left top',
213247
at: 'left bottom',

ui/jquery.ui.position.js

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ $.ui = $.ui || {};
1313

1414
var horizontalPositions = /left|center|right/,
1515
verticalPositions = /top|center|bottom/,
16+
roffset = /[+-]\d+%?/,
17+
rposition = /^\w+/,
18+
rpercent = /%$/,
1619
center = "center",
1720
_position = $.fn.position;
1821

@@ -27,7 +30,8 @@ $.fn.position = function( options ) {
2730
var target = $( options.of ),
2831
targetElem = target[0],
2932
collision = ( options.collision || "flip" ).split( " " ),
30-
offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ],
33+
offsets = {},
34+
atOffset,
3135
targetWidth,
3236
targetHeight,
3337
basePosition;
@@ -54,7 +58,10 @@ $.fn.position = function( options ) {
5458
// force my and at to have valid horizontal and vertical positions
5559
// if a value is missing or invalid, it will be converted to center
5660
$.each( [ "my", "at" ], function() {
57-
var pos = ( options[this] || "" ).split( " " );
61+
var pos = ( options[this] || "" ).split( " " ),
62+
horizontalOffset,
63+
verticalOffset;
64+
5865
if ( pos.length === 1) {
5966
pos = horizontalPositions.test( pos[0] ) ?
6067
pos.concat( [center] ) :
@@ -64,21 +71,27 @@ $.fn.position = function( options ) {
6471
}
6572
pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center;
6673
pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center;
67-
options[ this ] = pos;
74+
75+
// calculate offsets
76+
horizontalOffset = roffset.exec( pos[ 0 ] );
77+
verticalOffset = roffset.exec( pos [ 1 ] );
78+
offsets[ this ] = [
79+
horizontalOffset ? horizontalOffset[ 0 ] : 0,
80+
verticalOffset ? verticalOffset[ 0 ] : 0
81+
];
82+
83+
// reduce to just the positions without the offsets
84+
options[ this ] = [
85+
rposition.exec( pos[ 0 ] )[ 0 ],
86+
rposition.exec( pos[ 1 ] )[ 0 ]
87+
];
6888
});
6989

7090
// normalize collision option
7191
if ( collision.length === 1 ) {
7292
collision[ 1 ] = collision[ 0 ];
7393
}
7494

75-
// normalize offset option
76-
offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
77-
if ( offset.length === 1 ) {
78-
offset[ 1 ] = offset[ 0 ];
79-
}
80-
offset[ 1 ] = parseInt( offset[1], 10 ) || 0;
81-
8295
if ( options.at[0] === "right" ) {
8396
basePosition.left += targetWidth;
8497
} else if ( options.at[0] === center ) {
@@ -91,8 +104,14 @@ $.fn.position = function( options ) {
91104
basePosition.top += targetHeight / 2;
92105
}
93106

94-
basePosition.left += offset[ 0 ];
95-
basePosition.top += offset[ 1 ];
107+
atOffset = [
108+
parseInt( offsets.at[ 0 ], 10 ) *
109+
( rpercent.test( offsets.at[ 0 ] ) ? targetWidth / 100 : 1 ),
110+
parseInt( offsets.at[ 1 ], 10 ) *
111+
( rpercent.test( offsets.at[ 1 ] ) ? targetHeight / 100 : 1 )
112+
];
113+
basePosition.left += atOffset[ 0 ],
114+
basePosition.top += atOffset[ 1 ];
96115

97116
return this.each(function() {
98117
var elem = $( this ),
@@ -105,6 +124,12 @@ $.fn.position = function( options ) {
105124
collisionHeight = elemHeight + marginTop +
106125
( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ),
107126
position = $.extend( {}, basePosition ),
127+
myOffset = [
128+
parseInt( offsets.my[ 0 ], 10 ) *
129+
( rpercent.test( offsets.my[ 0 ] ) ? elem.outerWidth() / 100 : 1 ),
130+
parseInt( offsets.my[ 1 ], 10 ) *
131+
( rpercent.test( offsets.my[ 1 ] ) ? elem.outerHeight() / 100 : 1 )
132+
],
108133
collisionPosition;
109134

110135
if ( options.my[0] === "right" ) {
@@ -119,6 +144,9 @@ $.fn.position = function( options ) {
119144
position.top -= elemHeight / 2;
120145
}
121146

147+
position.left += myOffset[ 0 ];
148+
position.top += myOffset[ 1 ];
149+
122150
// prevent fractions (see #5280)
123151
position.left = Math.round( position.left );
124152
position.top = Math.round( position.top );
@@ -138,7 +166,7 @@ $.fn.position = function( options ) {
138166
collisionPosition: collisionPosition,
139167
collisionWidth: collisionWidth,
140168
collisionHeight: collisionHeight,
141-
offset: offset,
169+
offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
142170
my: options.my,
143171
at: options.at
144172
});
@@ -212,4 +240,40 @@ $.ui.position = {
212240
}
213241
};
214242

243+
// DEPRECATED
244+
if ( $.uiBackCompat !== false ) {
245+
// offset option
246+
(function( $ ) {
247+
var _position = $.fn.position;
248+
$.fn.position = function( options ) {
249+
if ( !options || !( "offset" in options ) ) {
250+
return _position.call( this, options );
251+
}
252+
var offset = options.offset.split( " " ),
253+
at = options.at.split( " " );
254+
if ( offset.length === 1 ) {
255+
offset[ 1 ] = offset[ 0 ];
256+
}
257+
if ( /^\d/.test( offset[ 0 ] ) ) {
258+
offset[ 0 ] = "+" + offset[ 0 ];
259+
}
260+
if ( /^\d/.test( offset[ 1 ] ) ) {
261+
offset[ 1 ] = "+" + offset[ 1 ];
262+
}
263+
if ( at.length === 1 ) {
264+
if ( /left|center|right/.test( at[ 0 ] ) ) {
265+
at[ 1 ] = "center";
266+
} else {
267+
at[ 1 ] = at[ 0 ];
268+
at[ 0 ] = "center";
269+
}
270+
}
271+
return _position.call( this, $.extend( options, {
272+
at: at[ 0 ] + offset[ 0 ] + " " + at[ 1 ] + offset[ 1 ],
273+
offset: undefined
274+
} ) );
275+
}
276+
}( jQuery ));
277+
}
278+
215279
}( jQuery ));

0 commit comments

Comments
 (0)