diff --git a/portamento.js b/portamento.js index fd43bb4..feed81a 100755 --- a/portamento.js +++ b/portamento.js @@ -1,73 +1,73 @@ /*! - * + * * Portamento v1.1.1 - 2011-09-02 * http://simianstudios.com/portamento - * + * * Copyright 2011 Kris Noble except where noted. - * - * Dual-licensed under the GPLv3 and Apache 2.0 licenses: + * + * Dual-licensed under the GPLv3 and Apache 2.0 licenses: * http://www.gnu.org/licenses/gpl-3.0.html * http://www.apache.org/licenses/LICENSE-2.0 - * + * */ /** - * + * * Creates a sliding panel that respects the boundaries of * a given wrapper, and also has sensible behaviour if the * viewport is too small to display the whole panel. - * + * * Full documentation at http://simianstudios.com/portamento - * + * * ---- - * + * * Uses the viewportOffset plugin by Ben Alman aka Cowboy: * http://benalman.com/projects/jquery-misc-plugins/#viewportoffset - * + * * Uses a portion of CFT by Juriy Zaytsev aka Kangax: * http://kangax.github.com/cft/#IS_POSITION_FIXED_SUPPORTED - * + * * Uses code by Matthew Eernisse: * http://www.fleegix.org/articles/2006-05-30-getting-the-scrollbar-width-in-pixels - * + * * Builds on work by Remy Sharp: * http://jqueryfordesigners.com/fixed-floating-elements/ - * + * */ (function($){ - + $.fn.portamento = function(options) { - + // we'll use the window and document objects a lot, so // saving them as variables now saves a lot of function calls var thisWindow = $(window); var thisDocument = $(document); - + /** * NOTE by Kris - included here so as to avoid namespace clashes. - * + * * jQuery viewportOffset - v0.3 - 2/3/2010 * http://benalman.com/projects/jquery-misc-plugins/ - * + * * Copyright (c) 2010 "Cowboy" Ben Alman * Dual licensed under the MIT and GPL licenses. * http://benalman.com/about/license/ - */ + */ $.fn.viewportOffset = function() { var win = $(window); var offset = $(this).offset(); - + return { left: offset.left - win.scrollLeft(), top: offset.top - win.scrollTop() }; }; - + /** - * + * * A test to see if position:fixed is supported. * Taken from CFT by Kangax - http://kangax.github.com/cft/#IS_POSITION_FIXED_SUPPORTED * Included here so as to avoid namespace clashes. - * + * */ function positionFixedSupported () { var container = document.body; @@ -91,20 +91,20 @@ } return null; } - + /** - * + * * Get the scrollbar width by Matthew Eernisse. * http://www.fleegix.org/articles/2006-05-30-getting-the-scrollbar-width-in-pixels * Included here so as to avoid namespace clashes. - * + * */ function getScrollerWidth() { var scr = null; var inn = null; var wNoScroll = 0; var wScroll = 0; - + // Outer scrolling div scr = document.createElement('div'); scr.style.position = 'absolute'; @@ -114,54 +114,54 @@ scr.style.height = '50px'; // Start with no scrollbar scr.style.overflow = 'hidden'; - + // Inner content div inn = document.createElement('div'); inn.style.width = '100%'; inn.style.height = '200px'; - + // Put the inner div in the scrolling div scr.appendChild(inn); // Append the scrolling div to the doc document.body.appendChild(scr); - + // Width of the inner div sans scrollbar wNoScroll = inn.offsetWidth; // Add the scrollbar scr.style.overflow = 'auto'; // Width of the inner div width scrollbar wScroll = inn.offsetWidth; - + // Remove the scrolling div from the doc document.body.removeChild(document.body.lastChild); - + // Pixel width of the scroller return (wNoScroll - wScroll); } - + // --------------------------------------------------------------------------------------------------- - + // get the definitive options var opts = $.extend({}, $.fn.portamento.defaults, options); - + // setup the vars accordingly var panel = this; var wrapper = opts.wrapper; var gap = opts.gap; - var disableWorkaround = opts.disableWorkaround; + var disableWorkaround = opts.disableWorkaround; var fullyCapableBrowser = positionFixedSupported(); - + if(panel.length != 1) { - // die gracefully if the user has tried to pass multiple elements + // die gracefully if the user has tried to pass multiple elements // (multiple element support is on the TODO list!) or no elements... return this; } - + if(!fullyCapableBrowser && disableWorkaround) { // just stop here, as the dev doesn't want to use the workaround return this; } - + // wrap the floating panel in a div, then set a sensible min-height and width panel.wrap('
'); var float_container = $('#portamento_container'); @@ -169,46 +169,54 @@ 'min-height': panel.outerHeight(), 'width': panel.outerWidth() }); - + // calculate the upper scrolling boundary var panelOffset = panel.offset().top; var panelMargin = parseFloat(panel.css('marginTop').replace(/auto/, 0)); var realPanelOffset = panelOffset - panelMargin; var topScrollBoundary = realPanelOffset - gap; - + // a couple of numbers to account for margins and padding on the relevant elements var wrapperPaddingFix = parseFloat(wrapper.css('paddingTop').replace(/auto/, 0)); var containerMarginFix = parseFloat(float_container.css('marginTop').replace(/auto/, 0)); - + // do some work to fix IE misreporting the document width var ieFix = 0; - + var isMSIE = /*@cc_on!@*/0; - + if (isMSIE) { ieFix = getScrollerWidth() + 4; - } - + } + // --------------------------------------------------------------------------------------------------- - + thisWindow.bind("scroll.portamento", function () { - + if(thisWindow.height() > panel.outerHeight() && thisWindow.width() >= (thisDocument.width() - ieFix)) { // don't scroll if the window isn't big enough - + var y = thisDocument.scrollTop(); // current scroll position of the document - + if (y >= (topScrollBoundary)) { // if we're at or past the upper scrolling boundary if((panel.innerHeight() - wrapper.viewportOffset().top) - wrapperPaddingFix + gap >= wrapper.height()) { // if we're at or past the bottom scrolling boundary if(panel.hasClass('fixed') || thisWindow.height() >= panel.outerHeight()) { // check that there's work to do panel.removeClass('fixed'); - panel.css('top', (wrapper.height() - panel.innerHeight()) + 'px'); + + // Calculate the height of any elements appearing BEFORE the panel. + var previousElementsHeight = 0; + var previousElements = panel.parent().prevAll(); + previousElements.each(function() { + previousElementsHeight += $(this).outerHeight(); + }); + + panel.css('top', (wrapper.innerHeight() - panel.innerHeight() - previousElementsHeight) + 'px'); } } else { // if we're somewhere in the middle panel.addClass('fixed'); - + if(fullyCapableBrowser) { // supports position:fixed panel.css('top', gap + 'px'); // to keep the gap - } else { + } else { panel.clearQueue(); panel.css('position', 'absolute').animate({top: (0 - float_container.viewportOffset().top + gap)}); } @@ -222,42 +230,42 @@ panel.removeClass('fixed'); } }); - + // --------------------------------------------------------------------------------------------------- - - thisWindow.bind("resize.portamento", function () { + + thisWindow.bind("resize.portamento", function () { // stop users getting undesirable behaviour if they resize the window too small - if(thisWindow.height() <= panel.outerHeight() || thisWindow.width() < thisDocument.width()) { + if(thisWindow.height() <= panel.outerHeight() || thisWindow.width() < thisDocument.width()) { if(panel.hasClass('fixed')) { panel.removeClass('fixed'); panel.css('top', '0'); - } + } } else { thisWindow.trigger('scroll.portamento'); // trigger the scroll event to place the panel correctly } }); - + // --------------------------------------------------------------------------------------------------- - + thisWindow.bind("orientationchange.portamento", function () { // if device orientation changes, trigger the resize event - thisWindow.trigger('resize.portamento'); + thisWindow.trigger('resize.portamento'); }); - + // --------------------------------------------------------------------------------------------------- - + // trigger the scroll event immediately so that the panel is positioned correctly if the page loads anywhere other than the top. thisWindow.trigger('scroll.portamento'); - + // return this to maintain chainability - return this; + return this; }; - + // set some sensible defaults $.fn.portamento.defaults = { 'wrapper' : $('body'), // the element that will act as the sliding panel's boundaries 'gap' : 10, // the gap (in pixels) left between the top of the viewport and the top of the panel - 'disableWorkaround' : false // option to disable the workaround for not-quite capable browsers + 'disableWorkaround' : false // option to disable the workaround for not-quite capable browsers }; - -})(jQuery); \ No newline at end of file + +})(jQuery);