| /* |
| * positionBy 1.0.7 (2008-01-29) |
| * |
| * Copyright (c) 2006,2007 Jonathan Sharp (http://jdsharp.us) |
| * Dual licensed under the MIT (MIT-LICENSE.txt) |
| * and GPL (GPL-LICENSE.txt) licenses. |
| * |
| * http://jdsharp.us/ |
| * |
| * Built upon jQuery 1.2.2 (http://jquery.com) |
| * This also requires the jQuery dimensions plugin |
| */ |
| (function($){ |
| /** |
| * This function centers an absolutely positioned element |
| */ |
| /* |
| $.fn.positionCenter = function(offsetLeft, offsetTop) { |
| var offsetLeft = offsetLeft || 1; |
| var offsetTop = offsetTop || 1; |
| |
| var ww = $(window).width(); |
| var wh = $(window).height(); |
| var sl = $(window).scrollLeft(); |
| var st = $(window).scrollTop(); |
| |
| return this.each(function() { |
| var $t = $(this); |
| |
| // If we are not visible we have to display our element (with a negative position offscreen) |
| |
| var left = Math.round( ( ww - $t.outerWidth() ) / 2 ); |
| if ( left < 0 ) { |
| left = 0; |
| } else { |
| left *= offsetLeft; |
| } |
| left += sl; |
| var top = Math.round( ( wh - $t.outerHeight() ) / 2 ); |
| if ( top < 0 ) { |
| top = 0; |
| } else { |
| top *= offsetTop; |
| } |
| top += st; |
| |
| $(this).parents().each(function() { |
| var $this = $(this); |
| if ( $this.css('position') != 'static' ) { |
| var o = $this.offset(); |
| left += -o.left; |
| top += -o.top; |
| return false; |
| } |
| }); |
| |
| $t.css({left: left, top: top}); |
| }); |
| }; |
| */ |
| |
| // Our range object is used in calculating positions |
| var Range = function(x1, y1, x2, y2) { |
| this.x1 = x1; this.x2 = x2; |
| this.y1 = y1; this.y2 = y2; |
| }; |
| Range.prototype.contains = function(range) { |
| return (this.x1 <= range.x1 && range.x2 <= this.x2) |
| && |
| (this.y1 <= range.y1 && range.y2 <= this.y2); |
| }; |
| Range.prototype.transform = function(x, y) { |
| return new Range(this.x1 + x, this.y1 + y, this.x2 + x, this.y2 + y); |
| }; |
| |
| $.fn.positionBy = function(args) { |
| var date1 = new Date(); |
| if ( this.length == 0 ) { |
| return this; |
| } |
| |
| var args = $.extend({ // The target element to position us relative to |
| target: null, |
| // The target's corner, possible values 0-3 |
| targetPos: null, |
| // The element's corner, possible values 0-3 |
| elementPos: null, |
| |
| // A raw x,y coordinate |
| x: null, |
| y: null, |
| |
| // Pass in an array of positions that are valid 0-15 |
| positions: null, |
| |
| // Add the final position class to the element (eg. positionBy0 through positionBy3, positionBy15) |
| addClass: false, |
| |
| // Force our element to be at the location we specified (don't try to auto position it) |
| force: false, |
| |
| // The element that we will make sure our element doesn't go outside of |
| container: window, |
| |
| // Should the element be hidden after positioning? |
| hideAfterPosition: false |
| }, args); |
| |
| if ( args.x != null ) { |
| var tLeft = args.x; |
| var tTop = args.y; |
| var tWidth = 0; |
| var tHeight = 0; |
| |
| // Position in relation to an element |
| } else { |
| var $target = $( $( args.target )[0] ); |
| var tWidth = $target.outerWidth(); |
| var tHeight = $target.outerHeight(); |
| var tOffset = $target.offset(); |
| var tLeft = tOffset.left; |
| var tTop = tOffset.top; |
| } |
| |
| // Our target right, bottom coord |
| var tRight = tLeft + tWidth; |
| var tBottom = tTop + tHeight; |
| |
| return this.each(function() { |
| var $element = $( this ); |
| |
| // Position our element in the top left so we can grab its width without triggering scrollbars |
| if ( !$element.is(':visible') ) { |
| $element.css({ left: -3000, |
| top: -3000 |
| }) |
| .show(); |
| } |
| |
| var eWidth = $element.outerWidth(); |
| var eHeight = $element.outerHeight(); |
| |
| // Holds x1,y1,x2,y2 coordinates for a position in relation to our target element |
| var position = []; |
| // Holds a list of alternate positions to try if this one is not in the browser viewport |
| var next = []; |
| |
| // Our Positions via ASCII ART |
| /* |
| 8 9 10 11 |
| +------------+ |
| 7 | 15 12 | 0 |
| | | |
| 6 | 14 13 | 1 |
| +------------+ |
| 5 4 3 2 |
| |
| */ |
| |
| position[0] = new Range(tRight, tTop, tRight + eWidth, tTop + eHeight); |
| next[0] = [1,7,4]; |
| |
| position[1] = new Range(tRight, tBottom - eHeight, tRight + eWidth, tBottom); |
| next[1] = [0,6,4]; |
| |
| position[2] = new Range(tRight, tBottom, tRight + eWidth, tBottom + eHeight); |
| next[2] = [1,3,10]; |
| |
| position[3] = new Range(tRight - eWidth, tBottom, tRight, tBottom + eHeight); |
| next[3] = [1,6,10]; |
| |
| position[4] = new Range(tLeft, tBottom, tLeft + eWidth, tBottom + eHeight); |
| next[4] = [1,6,9]; |
| |
| position[5] = new Range(tLeft - eWidth, tBottom, tLeft, tBottom + eHeight); |
| next[5] = [6,4,9]; |
| |
| position[6] = new Range(tLeft - eWidth, tBottom - eHeight, tLeft, tBottom); |
| next[6] = [7,1,4]; |
| |
| position[7] = new Range(tLeft - eWidth, tTop, tLeft, tTop + eHeight); |
| next[7] = [6,0,4]; |
| |
| position[8] = new Range(tLeft - eWidth, tTop - eHeight, tLeft, tTop); |
| next[8] = [7,9,4]; |
| |
| position[9] = new Range(tLeft, tTop - eHeight, tLeft + eWidth, tTop); |
| next[9] = [0,7,4]; |
| |
| position[10]= new Range(tRight - eWidth, tTop - eHeight, tRight, tTop); |
| next[10] = [0,7,3]; |
| |
| position[11]= new Range(tRight, tTop - eHeight, tRight + eWidth, tTop); |
| next[11] = [0,10,3]; |
| |
| position[12]= new Range(tRight - eWidth, tTop, tRight, tTop + eHeight); |
| next[12] = [13,7,10]; |
| |
| position[13]= new Range(tRight - eWidth, tBottom - eHeight, tRight, tBottom); |
| next[13] = [12,6,3]; |
| |
| position[14]= new Range(tLeft, tBottom - eHeight, tLeft + eWidth, tBottom); |
| next[14] = [15,1,4]; |
| |
| position[15]= new Range(tLeft, tTop, tLeft + eWidth, tTop + eHeight); |
| next[15] = [14,0,9]; |
| |
| if ( args.positions !== null ) { |
| var pos = args.positions[0]; |
| } else if ( args.targetPos != null && args.elementPos != null ) { |
| var pos = []; |
| pos[0] = []; |
| pos[0][0] = 15; |
| pos[0][1] = 7; |
| pos[0][2] = 8; |
| pos[0][3] = 9; |
| pos[1] = []; |
| pos[1][0] = 0; |
| pos[1][1] = 12; |
| pos[1][2] = 10; |
| pos[1][3] = 11; |
| pos[2] = []; |
| pos[2][0] = 2; |
| pos[2][1] = 3; |
| pos[2][2] = 13; |
| pos[2][3] = 1; |
| pos[3] = []; |
| pos[3][0] = 4; |
| pos[3][1] = 5; |
| pos[3][2] = 6; |
| pos[3][3] = 14; |
| |
| var pos = pos[args.targetPos][args.elementPos]; |
| } |
| var ePos = position[pos]; |
| var fPos = pos; |
| |
| if ( !args.force ) { |
| // TODO: Do the args.container |
| // window width & scroll offset |
| $window = $( window ); |
| var sx = $window.scrollLeft(); |
| var sy = $window.scrollTop(); |
| |
| // TODO: Look at innerWidth & innerHeight |
| var container = new Range( sx, sy, sx + $window.width(), sy + $window.height() ); |
| |
| // If we are outside of our viewport, see if we are outside vertically or horizontally and push onto the stack |
| var stack; |
| if ( args.positions ) { |
| stack = args.positions; |
| } else { |
| stack = [pos]; |
| } |
| var test = []; // Keeps track of our positions we already tried |
| |
| while ( stack.length > 0 ) { |
| var p = stack.shift(); |
| if ( test[p] ) { |
| continue; |
| } |
| test[p] = true; |
| |
| // If our current position is not within the viewport (eg. window) |
| // add the next suggested position |
| if ( !container.contains(position[p]) ) { |
| if ( args.positions === null ) { |
| stack = jQuery.merge( stack, next[p] ); |
| } |
| } else { |
| ePos = position[p]; |
| break; |
| } |
| } |
| } |
| |
| // + TODO: Determine if we are going to use absolute left, top, bottom, right |
| // positions relative to our target |
| |
| // Take into account any absolute or fixed positioning |
| // to 'normalize' our coordinates |
| $element.parents().each(function() { |
| var $this = $(this); |
| if ( $this.css('position') != 'static' ) { |
| var abs = $this.offset(); |
| ePos = ePos.transform( -abs.left, -abs.top ); |
| return false; |
| } |
| }); |
| |
| // Finally position our element |
| var css = { left: ePos.x1, top: ePos.y1 }; |
| if ( args.hideAfterPosition ) { |
| css['display'] = 'none'; |
| } |
| $element.css( css ); |
| |
| if ( args.addClass ) { |
| $element.removeClass( 'positionBy0 positionBy1 positionBy2 positionBy3 positionBy4 positionBy5 ' |
| + 'positionBy6 positionBy7 positionBy8 positionBy9 positionBy10 positionBy11 ' |
| + 'positionBy12 positionBy13 positionBy14 positionBy15') |
| .addClass('positionBy' + p); |
| } |
| }); |
| }; |
| })(jQuery); |