source: pro-violet-viettel/sourcecode/assets/js/jquery/jquery.ui.position.js @ 576

Last change on this file since 576 was 289, checked in by dungnv, 11 years ago
File size: 15.3 KB
Line 
1/*!
2 * jQuery UI Position v1.10.0
3 * http://jqueryui.com
4 *
5 * Copyright 2013 jQuery Foundation and other contributors
6 * Released under the MIT license.
7 * http://jquery.org/license
8 *
9 * http://api.jqueryui.com/position/
10 */
11(function( $, undefined ) {
12
13$.ui = $.ui || {};
14
15var cachedScrollbarWidth,
16        max = Math.max,
17        abs = Math.abs,
18        round = Math.round,
19        rhorizontal = /left|center|right/,
20        rvertical = /top|center|bottom/,
21        roffset = /[\+\-]\d+%?/,
22        rposition = /^\w+/,
23        rpercent = /%$/,
24        _position = $.fn.position;
25
26function getOffsets( offsets, width, height ) {
27        return [
28                parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
29                parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
30        ];
31}
32
33function parseCss( element, property ) {
34        return parseInt( $.css( element, property ), 10 ) || 0;
35}
36
37function getDimensions( elem ) {
38        var raw = elem[0];
39        if ( raw.nodeType === 9 ) {
40                return {
41                        width: elem.width(),
42                        height: elem.height(),
43                        offset: { top: 0, left: 0 }
44                };
45        }
46        if ( $.isWindow( raw ) ) {
47                return {
48                        width: elem.width(),
49                        height: elem.height(),
50                        offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
51                };
52        }
53        if ( raw.preventDefault ) {
54                return {
55                        width: 0,
56                        height: 0,
57                        offset: { top: raw.pageY, left: raw.pageX }
58                };
59        }
60        return {
61                width: elem.outerWidth(),
62                height: elem.outerHeight(),
63                offset: elem.offset()
64        };
65}
66
67$.position = {
68        scrollbarWidth: function() {
69                if ( cachedScrollbarWidth !== undefined ) {
70                        return cachedScrollbarWidth;
71                }
72                var w1, w2,
73                        div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
74                        innerDiv = div.children()[0];
75
76                $( "body" ).append( div );
77                w1 = innerDiv.offsetWidth;
78                div.css( "overflow", "scroll" );
79
80                w2 = innerDiv.offsetWidth;
81
82                if ( w1 === w2 ) {
83                        w2 = div[0].clientWidth;
84                }
85
86                div.remove();
87
88                return (cachedScrollbarWidth = w1 - w2);
89        },
90        getScrollInfo: function( within ) {
91                var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
92                        overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
93                        hasOverflowX = overflowX === "scroll" ||
94                                ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
95                        hasOverflowY = overflowY === "scroll" ||
96                                ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
97                return {
98                        width: hasOverflowX ? $.position.scrollbarWidth() : 0,
99                        height: hasOverflowY ? $.position.scrollbarWidth() : 0
100                };
101        },
102        getWithinInfo: function( element ) {
103                var withinElement = $( element || window ),
104                        isWindow = $.isWindow( withinElement[0] );
105                return {
106                        element: withinElement,
107                        isWindow: isWindow,
108                        offset: withinElement.offset() || { left: 0, top: 0 },
109                        scrollLeft: withinElement.scrollLeft(),
110                        scrollTop: withinElement.scrollTop(),
111                        width: isWindow ? withinElement.width() : withinElement.outerWidth(),
112                        height: isWindow ? withinElement.height() : withinElement.outerHeight()
113                };
114        }
115};
116
117$.fn.position = function( options ) {
118        if ( !options || !options.of ) {
119                return _position.apply( this, arguments );
120        }
121
122        // make a copy, we don't want to modify arguments
123        options = $.extend( {}, options );
124
125        var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
126                target = $( options.of ),
127                within = $.position.getWithinInfo( options.within ),
128                scrollInfo = $.position.getScrollInfo( within ),
129                collision = ( options.collision || "flip" ).split( " " ),
130                offsets = {};
131
132        dimensions = getDimensions( target );
133        if ( target[0].preventDefault ) {
134                // force left top to allow flipping
135                options.at = "left top";
136        }
137        targetWidth = dimensions.width;
138        targetHeight = dimensions.height;
139        targetOffset = dimensions.offset;
140        // clone to reuse original targetOffset later
141        basePosition = $.extend( {}, targetOffset );
142
143        // force my and at to have valid horizontal and vertical positions
144        // if a value is missing or invalid, it will be converted to center
145        $.each( [ "my", "at" ], function() {
146                var pos = ( options[ this ] || "" ).split( " " ),
147                        horizontalOffset,
148                        verticalOffset;
149
150                if ( pos.length === 1) {
151                        pos = rhorizontal.test( pos[ 0 ] ) ?
152                                pos.concat( [ "center" ] ) :
153                                rvertical.test( pos[ 0 ] ) ?
154                                        [ "center" ].concat( pos ) :
155                                        [ "center", "center" ];
156                }
157                pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
158                pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
159
160                // calculate offsets
161                horizontalOffset = roffset.exec( pos[ 0 ] );
162                verticalOffset = roffset.exec( pos[ 1 ] );
163                offsets[ this ] = [
164                        horizontalOffset ? horizontalOffset[ 0 ] : 0,
165                        verticalOffset ? verticalOffset[ 0 ] : 0
166                ];
167
168                // reduce to just the positions without the offsets
169                options[ this ] = [
170                        rposition.exec( pos[ 0 ] )[ 0 ],
171                        rposition.exec( pos[ 1 ] )[ 0 ]
172                ];
173        });
174
175        // normalize collision option
176        if ( collision.length === 1 ) {
177                collision[ 1 ] = collision[ 0 ];
178        }
179
180        if ( options.at[ 0 ] === "right" ) {
181                basePosition.left += targetWidth;
182        } else if ( options.at[ 0 ] === "center" ) {
183                basePosition.left += targetWidth / 2;
184        }
185
186        if ( options.at[ 1 ] === "bottom" ) {
187                basePosition.top += targetHeight;
188        } else if ( options.at[ 1 ] === "center" ) {
189                basePosition.top += targetHeight / 2;
190        }
191
192        atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
193        basePosition.left += atOffset[ 0 ];
194        basePosition.top += atOffset[ 1 ];
195
196        return this.each(function() {
197                var collisionPosition, using,
198                        elem = $( this ),
199                        elemWidth = elem.outerWidth(),
200                        elemHeight = elem.outerHeight(),
201                        marginLeft = parseCss( this, "marginLeft" ),
202                        marginTop = parseCss( this, "marginTop" ),
203                        collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
204                        collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
205                        position = $.extend( {}, basePosition ),
206                        myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
207
208                if ( options.my[ 0 ] === "right" ) {
209                        position.left -= elemWidth;
210                } else if ( options.my[ 0 ] === "center" ) {
211                        position.left -= elemWidth / 2;
212                }
213
214                if ( options.my[ 1 ] === "bottom" ) {
215                        position.top -= elemHeight;
216                } else if ( options.my[ 1 ] === "center" ) {
217                        position.top -= elemHeight / 2;
218                }
219
220                position.left += myOffset[ 0 ];
221                position.top += myOffset[ 1 ];
222
223                // if the browser doesn't support fractions, then round for consistent results
224                if ( !$.support.offsetFractions ) {
225                        position.left = round( position.left );
226                        position.top = round( position.top );
227                }
228
229                collisionPosition = {
230                        marginLeft: marginLeft,
231                        marginTop: marginTop
232                };
233
234                $.each( [ "left", "top" ], function( i, dir ) {
235                        if ( $.ui.position[ collision[ i ] ] ) {
236                                $.ui.position[ collision[ i ] ][ dir ]( position, {
237                                        targetWidth: targetWidth,
238                                        targetHeight: targetHeight,
239                                        elemWidth: elemWidth,
240                                        elemHeight: elemHeight,
241                                        collisionPosition: collisionPosition,
242                                        collisionWidth: collisionWidth,
243                                        collisionHeight: collisionHeight,
244                                        offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
245                                        my: options.my,
246                                        at: options.at,
247                                        within: within,
248                                        elem : elem
249                                });
250                        }
251                });
252
253                if ( options.using ) {
254                        // adds feedback as second argument to using callback, if present
255                        using = function( props ) {
256                                var left = targetOffset.left - position.left,
257                                        right = left + targetWidth - elemWidth,
258                                        top = targetOffset.top - position.top,
259                                        bottom = top + targetHeight - elemHeight,
260                                        feedback = {
261                                                target: {
262                                                        element: target,
263                                                        left: targetOffset.left,
264                                                        top: targetOffset.top,
265                                                        width: targetWidth,
266                                                        height: targetHeight
267                                                },
268                                                element: {
269                                                        element: elem,
270                                                        left: position.left,
271                                                        top: position.top,
272                                                        width: elemWidth,
273                                                        height: elemHeight
274                                                },
275                                                horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
276                                                vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
277                                        };
278                                if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
279                                        feedback.horizontal = "center";
280                                }
281                                if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
282                                        feedback.vertical = "middle";
283                                }
284                                if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
285                                        feedback.important = "horizontal";
286                                } else {
287                                        feedback.important = "vertical";
288                                }
289                                options.using.call( this, props, feedback );
290                        };
291                }
292
293                elem.offset( $.extend( position, { using: using } ) );
294        });
295};
296
297$.ui.position = {
298        fit: {
299                left: function( position, data ) {
300                        var within = data.within,
301                                withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
302                                outerWidth = within.width,
303                                collisionPosLeft = position.left - data.collisionPosition.marginLeft,
304                                overLeft = withinOffset - collisionPosLeft,
305                                overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
306                                newOverRight;
307
308                        // element is wider than within
309                        if ( data.collisionWidth > outerWidth ) {
310                                // element is initially over the left side of within
311                                if ( overLeft > 0 && overRight <= 0 ) {
312                                        newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
313                                        position.left += overLeft - newOverRight;
314                                // element is initially over right side of within
315                                } else if ( overRight > 0 && overLeft <= 0 ) {
316                                        position.left = withinOffset;
317                                // element is initially over both left and right sides of within
318                                } else {
319                                        if ( overLeft > overRight ) {
320                                                position.left = withinOffset + outerWidth - data.collisionWidth;
321                                        } else {
322                                                position.left = withinOffset;
323                                        }
324                                }
325                        // too far left -> align with left edge
326                        } else if ( overLeft > 0 ) {
327                                position.left += overLeft;
328                        // too far right -> align with right edge
329                        } else if ( overRight > 0 ) {
330                                position.left -= overRight;
331                        // adjust based on position and margin
332                        } else {
333                                position.left = max( position.left - collisionPosLeft, position.left );
334                        }
335                },
336                top: function( position, data ) {
337                        var within = data.within,
338                                withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
339                                outerHeight = data.within.height,
340                                collisionPosTop = position.top - data.collisionPosition.marginTop,
341                                overTop = withinOffset - collisionPosTop,
342                                overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
343                                newOverBottom;
344
345                        // element is taller than within
346                        if ( data.collisionHeight > outerHeight ) {
347                                // element is initially over the top of within
348                                if ( overTop > 0 && overBottom <= 0 ) {
349                                        newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
350                                        position.top += overTop - newOverBottom;
351                                // element is initially over bottom of within
352                                } else if ( overBottom > 0 && overTop <= 0 ) {
353                                        position.top = withinOffset;
354                                // element is initially over both top and bottom of within
355                                } else {
356                                        if ( overTop > overBottom ) {
357                                                position.top = withinOffset + outerHeight - data.collisionHeight;
358                                        } else {
359                                                position.top = withinOffset;
360                                        }
361                                }
362                        // too far up -> align with top
363                        } else if ( overTop > 0 ) {
364                                position.top += overTop;
365                        // too far down -> align with bottom edge
366                        } else if ( overBottom > 0 ) {
367                                position.top -= overBottom;
368                        // adjust based on position and margin
369                        } else {
370                                position.top = max( position.top - collisionPosTop, position.top );
371                        }
372                }
373        },
374        flip: {
375                left: function( position, data ) {
376                        var within = data.within,
377                                withinOffset = within.offset.left + within.scrollLeft,
378                                outerWidth = within.width,
379                                offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
380                                collisionPosLeft = position.left - data.collisionPosition.marginLeft,
381                                overLeft = collisionPosLeft - offsetLeft,
382                                overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
383                                myOffset = data.my[ 0 ] === "left" ?
384                                        -data.elemWidth :
385                                        data.my[ 0 ] === "right" ?
386                                                data.elemWidth :
387                                                0,
388                                atOffset = data.at[ 0 ] === "left" ?
389                                        data.targetWidth :
390                                        data.at[ 0 ] === "right" ?
391                                                -data.targetWidth :
392                                                0,
393                                offset = -2 * data.offset[ 0 ],
394                                newOverRight,
395                                newOverLeft;
396
397                        if ( overLeft < 0 ) {
398                                newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
399                                if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
400                                        position.left += myOffset + atOffset + offset;
401                                }
402                        }
403                        else if ( overRight > 0 ) {
404                                newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
405                                if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
406                                        position.left += myOffset + atOffset + offset;
407                                }
408                        }
409                },
410                top: function( position, data ) {
411                        var within = data.within,
412                                withinOffset = within.offset.top + within.scrollTop,
413                                outerHeight = within.height,
414                                offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
415                                collisionPosTop = position.top - data.collisionPosition.marginTop,
416                                overTop = collisionPosTop - offsetTop,
417                                overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
418                                top = data.my[ 1 ] === "top",
419                                myOffset = top ?
420                                        -data.elemHeight :
421                                        data.my[ 1 ] === "bottom" ?
422                                                data.elemHeight :
423                                                0,
424                                atOffset = data.at[ 1 ] === "top" ?
425                                        data.targetHeight :
426                                        data.at[ 1 ] === "bottom" ?
427                                                -data.targetHeight :
428                                                0,
429                                offset = -2 * data.offset[ 1 ],
430                                newOverTop,
431                                newOverBottom;
432                        if ( overTop < 0 ) {
433                                newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
434                                if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
435                                        position.top += myOffset + atOffset + offset;
436                                }
437                        }
438                        else if ( overBottom > 0 ) {
439                                newOverTop = position.top -  data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
440                                if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
441                                        position.top += myOffset + atOffset + offset;
442                                }
443                        }
444                }
445        },
446        flipfit: {
447                left: function() {
448                        $.ui.position.flip.left.apply( this, arguments );
449                        $.ui.position.fit.left.apply( this, arguments );
450                },
451                top: function() {
452                        $.ui.position.flip.top.apply( this, arguments );
453                        $.ui.position.fit.top.apply( this, arguments );
454                }
455        }
456};
457
458// fraction support test
459(function () {
460        var testElement, testElementParent, testElementStyle, offsetLeft, i,
461                body = document.getElementsByTagName( "body" )[ 0 ],
462                div = document.createElement( "div" );
463
464        //Create a "fake body" for testing based on method used in jQuery.support
465        testElement = document.createElement( body ? "div" : "body" );
466        testElementStyle = {
467                visibility: "hidden",
468                width: 0,
469                height: 0,
470                border: 0,
471                margin: 0,
472                background: "none"
473        };
474        if ( body ) {
475                $.extend( testElementStyle, {
476                        position: "absolute",
477                        left: "-1000px",
478                        top: "-1000px"
479                });
480        }
481        for ( i in testElementStyle ) {
482                testElement.style[ i ] = testElementStyle[ i ];
483        }
484        testElement.appendChild( div );
485        testElementParent = body || document.documentElement;
486        testElementParent.insertBefore( testElement, testElementParent.firstChild );
487
488        div.style.cssText = "position: absolute; left: 10.7432222px;";
489
490        offsetLeft = $( div ).offset().left;
491        $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
492
493        testElement.innerHTML = "";
494        testElementParent.removeChild( testElement );
495})();
496
497}( jQuery ) );
Note: See TracBrowser for help on using the repository browser.