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