Tizen 2.1 base
[platform/framework/web/web-ui-fw.git] / libs / js / jquery.ui.position.git+dfe75e1.js
1 /*
2  * jQuery UI Position @ dfe75e1
3  *
4  * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5  * Dual licensed under the MIT or GPL Version 2 licenses.
6  * http://jquery.org/license
7  *
8  * http://docs.jquery.com/UI/Position
9  */
10 (function( $, undefined ) {
11
12 $.ui = $.ui || {};
13
14 var rhorizontal = /left|center|right/,
15         rvertical = /top|center|bottom/,
16         roffset = /[+-]\d+%?/,
17         rposition = /^\w+/,
18         rpercent = /%$/,
19         center = "center",
20         _position = $.fn.position;
21
22 $.position = {
23         scrollbarWidth: function() {
24                 var w1, w2,
25                         div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
26                         innerDiv = div.children()[0];
27
28                 $( "body" ).append( div );
29                 w1 = innerDiv.offsetWidth;
30                 div.css( "overflow", "scroll" );
31
32                 w2 = innerDiv.offsetWidth;
33
34                 if ( w1 === w2 ) {
35                         w2 = div[0].clientWidth;
36                 }
37
38                 div.remove();
39
40                 return w1 - w2;
41         },
42         getScrollInfo: function(within) {
43                 var notWindow = within[0] !== window,
44                         overflowX = notWindow ? within.css( "overflow-x" ) : "",
45                         overflowY = notWindow ? within.css( "overflow-y" ) : "",
46                         scrollbarWidth = overflowX === "auto" || overflowX === "scroll" ? $.position.scrollbarWidth() : 0,
47                         scrollbarHeight = overflowY === "auto" || overflowY === "scroll" ? $.position.scrollbarWidth() : 0;
48
49                 return {
50                         height: within.height() < within[0].scrollHeight ? scrollbarHeight : 0,
51                         width: within.width() < within[0].scrollWidth ? scrollbarWidth : 0
52                 };
53         }
54 };
55
56 $.fn.position = function( options ) {
57         if ( !options || !options.of ) {
58                 return _position.apply( this, arguments );
59         }
60
61         // make a copy, we don't want to modify arguments
62         options = $.extend( {}, options );
63
64         var target = $( options.of ),
65                 within  = $( options.within || window ),
66                 targetElem = target[0],
67                 collision = ( options.collision || "flip" ).split( " " ),
68                 offsets = {},
69                 atOffset,
70                 targetWidth,
71                 targetHeight,
72                 basePosition;
73
74         if ( targetElem.nodeType === 9 ) {
75                 targetWidth = target.width();
76                 targetHeight = target.height();
77                 basePosition = { top: 0, left: 0 };
78         } else if ( $.isWindow( targetElem ) ) {
79                 targetWidth = target.width();
80                 targetHeight = target.height();
81                 basePosition = { top: target.scrollTop(), left: target.scrollLeft() };
82         } else if ( targetElem.preventDefault ) {
83                 // force left top to allow flipping
84                 options.at = "left top";
85                 targetWidth = targetHeight = 0;
86                 basePosition = { top: options.of.pageY, left: options.of.pageX };
87         } else {
88                 targetWidth = target.outerWidth();
89                 targetHeight = target.outerHeight();
90                 basePosition = target.offset();
91         }
92
93         // force my and at to have valid horizontal and vertical positions
94         // if a value is missing or invalid, it will be converted to center
95         $.each( [ "my", "at" ], function() {
96                 var pos = ( options[ this ] || "" ).split( " " ),
97                         horizontalOffset,
98                         verticalOffset;
99
100                 if ( pos.length === 1) {
101                         pos = rhorizontal.test( pos[ 0 ] ) ?
102                                 pos.concat( [ center ] ) :
103                                 rvertical.test( pos[ 0 ] ) ?
104                                         [ center ].concat( pos ) :
105                                         [ center, center ];
106                 }
107                 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : center;
108                 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : center;
109
110                 // calculate offsets
111                 horizontalOffset = roffset.exec( pos[ 0 ] );
112                 verticalOffset = roffset.exec( pos[ 1 ] );
113                 offsets[ this ] = [
114                         horizontalOffset ? horizontalOffset[ 0 ] : 0,
115                         verticalOffset ? verticalOffset[ 0 ] : 0
116                 ];
117
118                 // reduce to just the positions without the offsets
119                 options[ this ] = [
120                         rposition.exec( pos[ 0 ] )[ 0 ],
121                         rposition.exec( pos[ 1 ] )[ 0 ]
122                 ];
123         });
124
125         // normalize collision option
126         if ( collision.length === 1 ) {
127                 collision[ 1 ] = collision[ 0 ];
128         }
129
130         if ( options.at[ 0 ] === "right" ) {
131                 basePosition.left += targetWidth;
132         } else if ( options.at[ 0 ] === center ) {
133                 basePosition.left += targetWidth / 2;
134         }
135
136         if ( options.at[ 1 ] === "bottom" ) {
137                 basePosition.top += targetHeight;
138         } else if ( options.at[ 1 ] === center ) {
139                 basePosition.top += targetHeight / 2;
140         }
141
142         atOffset = [
143                 parseInt( offsets.at[ 0 ], 10 ) *
144                         ( rpercent.test( offsets.at[ 0 ] ) ? targetWidth / 100 : 1 ),
145                 parseInt( offsets.at[ 1 ], 10 ) *
146                         ( rpercent.test( offsets.at[ 1 ] ) ? targetHeight / 100 : 1 )
147         ];
148         basePosition.left += atOffset[ 0 ];
149         basePosition.top += atOffset[ 1 ];
150
151         return this.each(function() {
152                 var elem = $( this ),
153                         elemWidth = elem.outerWidth(),
154                         elemHeight = elem.outerHeight(),
155                         marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0,
156                         marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0,
157                         scrollInfo = $.position.getScrollInfo( within ),
158                         collisionWidth = elemWidth + marginLeft +
159                                 ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ) + scrollInfo.width,
160                         collisionHeight = elemHeight + marginTop +
161                                 ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ) + scrollInfo.height,
162                         position = $.extend( {}, basePosition ),
163                         myOffset = [
164                                 parseInt( offsets.my[ 0 ], 10 ) *
165                                         ( rpercent.test( offsets.my[ 0 ] ) ? elem.outerWidth() / 100 : 1 ),
166                                 parseInt( offsets.my[ 1 ], 10 ) *
167                                         ( rpercent.test( offsets.my[ 1 ] ) ? elem.outerHeight() / 100 : 1 )
168                         ],
169                         collisionPosition;
170
171                 if ( options.my[ 0 ] === "right" ) {
172                         position.left -= elemWidth;
173                 } else if ( options.my[ 0 ] === center ) {
174                         position.left -= elemWidth / 2;
175                 }
176
177                 if ( options.my[ 1 ] === "bottom" ) {
178                         position.top -= elemHeight;
179                 } else if ( options.my[ 1 ] === center ) {
180                         position.top -= elemHeight / 2;
181                 }
182
183                 position.left += myOffset[ 0 ];
184                 position.top += myOffset[ 1 ];
185
186                 collisionPosition = {
187                         marginLeft: marginLeft,
188                         marginTop: marginTop
189                 };
190
191                 $.each( [ "left", "top" ], function( i, dir ) {
192                         if ( $.ui.position[ collision[ i ] ] ) {
193                                 $.ui.position[ collision[ i ] ][ dir ]( position, {
194                                         targetWidth: targetWidth,
195                                         targetHeight: targetHeight,
196                                         elemWidth: elemWidth,
197                                         elemHeight: elemHeight,
198                                         collisionPosition: collisionPosition,
199                                         collisionWidth: collisionWidth,
200                                         collisionHeight: collisionHeight,
201                                         offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
202                                         my: options.my,
203                                         at: options.at,
204                                         within: within,
205                                         elem : elem
206                                 });
207                         }
208                 });
209
210                 if ( $.fn.bgiframe ) {
211                         elem.bgiframe();
212                 }
213                 elem.offset( $.extend( position, { using: options.using } ) );
214         });
215 };
216
217 $.ui.position = {
218         fit: {
219                 left: function( position, data ) {
220                         var within = data.within,
221                                 win = $( window ),
222                                 isWindow = $.isWindow( data.within[0] ),
223                                 withinOffset = isWindow ? win.scrollLeft() : within.offset().left,
224                                 outerWidth = isWindow ? win.width() : within.outerWidth(),
225                                 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
226                                 overLeft = withinOffset - collisionPosLeft,
227                                 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
228                                 newOverRight,
229                                 newOverLeft;
230
231                         // element is wider than within
232                         if ( data.collisionWidth > outerWidth ) {
233                                 // element is initially over the left side of within
234                                 if ( overLeft > 0 && overRight <= 0 ) {
235                                         newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
236                                         position.left += overLeft - newOverRight;
237                                 // element is initially over right side of within
238                                 } else if ( overRight > 0 && overLeft <= 0 ) {
239                                         position.left = withinOffset;
240                                 // element is initially over both left and right sides of within
241                                 } else {
242                                         if ( overLeft > overRight ) {
243                                                 position.left = withinOffset + outerWidth - data.collisionWidth;
244                                         } else {
245                                                 position.left = withinOffset;
246                                         }
247                                 }
248                         // too far left -> align with left edge
249                         } else if ( overLeft > 0 ) {
250                                 position.left += overLeft;
251                         // too far right -> align with right edge
252                         } else if ( overRight > 0 ) {
253                                 position.left -= overRight;
254                         // adjust based on position and margin
255                         } else {
256                                 position.left = Math.max( position.left - collisionPosLeft, position.left );
257                         }
258                 },
259                 top: function( position, data ) {
260                         var within = data.within,
261                                 win = $( window ),
262                                 isWindow = $.isWindow( data.within[0] ),
263                                 withinOffset = isWindow ? win.scrollTop() : within.offset().top,
264                                 outerHeight = isWindow ? win.height() : within.outerHeight(),
265                                 collisionPosTop = position.top - data.collisionPosition.marginTop,
266                                 overTop = withinOffset - collisionPosTop,
267                                 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
268                                 newOverTop,
269                                 newOverBottom;
270
271                         // element is taller than within
272                         if ( data.collisionHeight > outerHeight ) {
273                                 // element is initially over the top of within
274                                 if ( overTop > 0 && overBottom <= 0 ) {
275                                         newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
276                                         position.top += overTop - newOverBottom;
277                                 // element is initially over bottom of within
278                                 } else if ( overBottom > 0 && overTop <= 0 ) {
279                                         position.top = withinOffset;
280                                 // element is initially over both top and bottom of within
281                                 } else {
282                                         if ( overTop > overBottom ) {
283                                                 position.top = withinOffset + outerHeight - data.collisionHeight;
284                                         } else {
285                                                 position.top = withinOffset;
286                                         }
287                                 }
288                         // too far up -> align with top
289                         } else if ( overTop > 0 ) {
290                                 position.top += overTop;
291                         // too far down -> align with bottom edge
292                         } else if ( overBottom > 0 ) {
293                                 position.top -= overBottom;
294                         // adjust based on position and margin
295                         } else {
296                                 position.top = Math.max( position.top - collisionPosTop, position.top );
297                         }
298                 }
299         },
300         flip: {
301                 left: function( position, data ) {
302                         if ( data.at[ 0 ] === center ) {
303                                 return;
304                         }
305
306                         data.elem
307                                 .removeClass( "ui-flipped-left ui-flipped-right" );
308
309                         var within = data.within,
310                                 win = $( window ),
311                                 isWindow = $.isWindow( data.within[0] ),
312                                 withinOffset = ( isWindow ? 0 : within.offset().left ) + within.scrollLeft(),
313                                 outerWidth = isWindow ? within.width() : within.outerWidth(),
314                                 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
315                                 overLeft = collisionPosLeft - withinOffset,
316                                 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
317                                 left = data.my[ 0 ] === "left",
318                                 myOffset = data.my[ 0 ] === "left" ?
319                                         -data.elemWidth :
320                                         data.my[ 0 ] === "right" ?
321                                                 data.elemWidth :
322                                                 0,
323                                 atOffset = data.at[ 0 ] === "left" ?
324                                         data.targetWidth :
325                                         -data.targetWidth,
326                                 offset = -2 * data.offset[ 0 ],
327                                 newOverRight,
328                                 newOverLeft;
329
330                         if ( overLeft < 0 ) {
331                                 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
332                                 if ( newOverRight < 0 || newOverRight < Math.abs( overLeft ) ) {
333                                         data.elem
334                                                 .addClass( "ui-flipped-right" );
335
336                                         position.left += myOffset + atOffset + offset;
337                                 }
338                         }
339                         else if ( overRight > 0 ) {
340                                 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - withinOffset;
341                                 if ( newOverLeft > 0 || Math.abs( newOverLeft ) < overRight ) {
342                                         data.elem
343                                                 .addClass( "ui-flipped-left" );
344
345                                         position.left += myOffset + atOffset + offset;
346                                 }
347                         }
348                 },
349                 top: function( position, data ) {
350                         if ( data.at[ 1 ] === center ) {
351                                 return;
352                         }
353
354                         data.elem
355                                 .removeClass( "ui-flipped-top ui-flipped-bottom" );
356
357                         var within = data.within,
358                                 win = $( window ),
359                                 isWindow = $.isWindow( data.within[0] ),
360                                 withinOffset = ( isWindow ? 0 : within.offset().top ) + within.scrollTop(),
361                                 outerHeight = isWindow ? within.height() : within.outerHeight(),
362                                 collisionPosTop = position.top - data.collisionPosition.marginTop,
363                                 overTop = collisionPosTop - withinOffset,
364                                 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
365                                 top = data.my[ 1 ] === "top",
366                                 myOffset = top ?
367                                         -data.elemHeight :
368                                         data.my[ 1 ] === "bottom" ?
369                                                 data.elemHeight :
370                                                 0,
371                                 atOffset = data.at[ 1 ] === "top" ?
372                                         data.targetHeight :
373                                         -data.targetHeight,
374                                 offset = -2 * data.offset[ 1 ],
375                                 newOverTop,
376                                 newOverBottom;
377                         if ( overTop < 0 ) {
378                                 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
379                                 if ( newOverBottom < 0 || newOverBottom < Math.abs( overTop ) ) {
380                                         data.elem
381                                                 .addClass( "ui-flipped-bottom" );
382
383                                         position.top += myOffset + atOffset + offset;
384                                 }
385                         }
386                         else if ( overBottom > 0 ) {
387                                 newOverTop = position.top -  data.collisionPosition.marginTop + myOffset + atOffset + offset - withinOffset;
388                                 if ( newOverTop > 0 || Math.abs( newOverTop ) < overBottom ) {
389                                         data.elem
390                                                 .addClass( "ui-flipped-top" );
391
392                                         position.top += myOffset + atOffset + offset;
393                                 }
394                         }
395                 }
396         },
397         flipfit: {
398                 left: function() {
399                         $.ui.position.flip.left.apply( this, arguments );
400                         $.ui.position.fit.left.apply( this, arguments );
401                 },
402                 top: function() {
403                         $.ui.position.flip.top.apply( this, arguments );
404                         $.ui.position.fit.top.apply( this, arguments );
405                 }
406         }
407 };
408
409 // DEPRECATED
410 if ( $.uiBackCompat !== false ) {
411         // offset option
412         (function( $ ) {
413                 var _position = $.fn.position;
414                 $.fn.position = function( options ) {
415                         if ( !options || !options.offset ) {
416                                 return _position.call( this, options );
417                         }
418                         var offset = options.offset.split( " " ),
419                                 at = options.at.split( " " );
420                         if ( offset.length === 1 ) {
421                                 offset[ 1 ] = offset[ 0 ];
422                         }
423                         if ( /^\d/.test( offset[ 0 ] ) ) {
424                                 offset[ 0 ] = "+" + offset[ 0 ];
425                         }
426                         if ( /^\d/.test( offset[ 1 ] ) ) {
427                                 offset[ 1 ] = "+" + offset[ 1 ];
428                         }
429                         if ( at.length === 1 ) {
430                                 if ( /left|center|right/.test( at[ 0 ] ) ) {
431                                         at[ 1 ] = "center";
432                                 } else {
433                                         at[ 1 ] = at[ 0 ];
434                                         at[ 0 ] = "center";
435                                 }
436                         }
437                         return _position.call( this, $.extend( options, {
438                                 at: at[ 0 ] + offset[ 0 ] + " " + at[ 1 ] + offset[ 1 ],
439                                 offset: undefined
440                         } ) );
441                 }
442         }( jQuery ) );
443 }
444
445 }( jQuery ) );