/* * jQuery UI Position @VERSION * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Position */ (function( $, undefined ) { $.ui = $.ui || {}; var rhorizontal = /left|center|right/, rvertical = /top|center|bottom/, roffset = /[+-]\d+%?/, rposition = /^\w+/, rpercent = /%$/, center = "center", _position = $.fn.position; $.fn.position = function( options ) { if ( !options || !options.of ) { return _position.apply( this, arguments ); } // make a copy, we don't want to modify arguments options = $.extend( {}, options ); var target = $( options.of ), targetElem = target[0], collision = ( options.collision || "flip" ).split( " " ), offsets = {}, atOffset, targetWidth, targetHeight, basePosition; if ( targetElem.nodeType === 9 ) { targetWidth = target.width(); targetHeight = target.height(); basePosition = { top: 0, left: 0 }; } else if ( $.isWindow( targetElem ) ) { targetWidth = target.width(); targetHeight = target.height(); basePosition = { top: target.scrollTop(), left: target.scrollLeft() }; } else if ( targetElem.preventDefault ) { // force left top to allow flipping options.at = "left top"; targetWidth = targetHeight = 0; basePosition = { top: options.of.pageY, left: options.of.pageX }; } else { targetWidth = target.outerWidth(); targetHeight = target.outerHeight(); basePosition = target.offset(); } // 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( " " ), horizontalOffset, verticalOffset; if ( pos.length === 1) { pos = rhorizontal.test( pos[ 0 ] ) ? pos.concat( [ center ] ) : rvertical.test( pos[ 0 ] ) ? [ center ].concat( pos ) : [ center, center ]; } pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : center; pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : center; // 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 if ( collision.length === 1 ) { collision[ 1 ] = collision[ 0 ]; } if ( options.at[ 0 ] === "right" ) { basePosition.left += targetWidth; } else if ( options.at[ 0 ] === center ) { basePosition.left += targetWidth / 2; } if ( options.at[ 1 ] === "bottom" ) { basePosition.top += targetHeight; } else if ( options.at[ 1 ] === center ) { basePosition.top += targetHeight / 2; } 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 ), elemWidth = elem.outerWidth(), elemHeight = elem.outerHeight(), marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0, marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0, collisionWidth = elemWidth + marginLeft + ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ), 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" ) { position.left -= elemWidth; } else if ( options.my[ 0 ] === center ) { position.left -= elemWidth / 2; } if ( options.my[ 1 ] === "bottom" ) { position.top -= elemHeight; } else if ( options.my[ 1 ] === center ) { 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 ); collisionPosition = { left: position.left - marginLeft, top: position.top - marginTop }; $.each( [ "left", "top" ], function( i, dir ) { if ( $.ui.position[ collision[ i ] ] ) { $.ui.position[ collision[ i ] ][ dir ]( position, { targetWidth: targetWidth, targetHeight: targetHeight, elemWidth: elemWidth, elemHeight: elemHeight, collisionPosition: collisionPosition, collisionWidth: collisionWidth, collisionHeight: collisionHeight, offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], my: options.my, at: options.at }); } }); if ( $.fn.bgiframe ) { elem.bgiframe(); } elem.offset( $.extend( position, { using: options.using } ) ); }); }; $.ui.position = { fit: { left: function( position, data ) { var win = $( window ), overLeft = win.scrollLeft() - data.collisionPosition.left, overRight = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(); // element is wider than window or too far left -> align with left edge if ( data.collisionWidth > win.width() || overLeft > 0 ) { position.left = position.left + overLeft; // too far right -> align with right edge } else if ( overRight > 0 ) { position.left = position.left - overRight; // adjust based on position and margin } else { position.left = Math.max( position.left - data.collisionPosition.left, position.left ); } }, top: function( position, data ) { var win = $( window ), overTop = win.scrollTop() - data.collisionPosition.top, overBottom = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(); // element is taller than window or too far up -> align with top edge if ( data.collisionHeight > win.height() || overTop > 0 ) { position.top = position.top + overTop; // too far down -> align with bottom edge } else if ( overBottom > 0 ) { position.top = position.top - overBottom; // adjust based on position and margin } else { position.top = Math.max( position.top - data.collisionPosition.top, position.top ); } } }, flip: { left: function( position, data ) { if ( data.at[ 0 ] === center ) { return; } var win = $( window ), over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(), myOffset = data.my[ 0 ] === "left" ? -data.elemWidth : data.my[ 0 ] === "right" ? data.elemWidth : 0, atOffset = data.at[ 0 ] === "left" ? data.targetWidth : -data.targetWidth, offset = -2 * data.offset[ 0 ]; position.left += data.collisionPosition.left < 0 ? myOffset + atOffset + offset : over > 0 ? myOffset + atOffset + offset : 0; }, top: function( position, data ) { if ( data.at[ 1 ] === center ) { return; } var win = $( window ), over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(), myOffset = data.my[ 1 ] === "top" ? -data.elemHeight : data.my[ 1 ] === "bottom" ? data.elemHeight : 0, atOffset = data.at[ 1 ] === "top" ? data.targetHeight : -data.targetHeight, offset = -2 * data.offset[ 1 ]; position.top += data.collisionPosition.top < 0 ? myOffset + atOffset + offset : over > 0 ? myOffset + atOffset + offset : 0; } } }; // 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 ) );