diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 38eae26..2e3c40e 100755 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,3 +1,10 @@ +### Version 2.2.11 - July 11, 2017 + +- **Sticky** - Fix issue where sticky would cause page to shift when `context` height was determined by sticky's height in `position: static;` [#3430](https://github.com/Semantic-Org/Semantic-UI/issues/3430) +- **Sticky** - Sticky now includes a new setting `setSize` to determine whether it should set content size on stick to the size before sticking (fixed content uses different positioning system) [#4360](https://github.com/Semantic-Org/Semantic-UI/issues/4360) +- **Sticky** - Fixed edge case where using `offset` setting, sticky element would not internally scroll if the rail contents (without the offset setting) would fit on screen +- **Sticky** - Fixed an issue where `ui sticky` used with a percentage based width would not resize properly if the content size of container changed when "stuck" [#4360](https://github.com/Semantic-Org/Semantic-UI/issues/4360) + ### Version 2.2.5 - October, 27, 2016 - **Sticky** - Adds `container` setting. This can be used to specify the offsetParent of the sticky element and avoid having to calculate on initialization (improving performance) diff --git a/composer.json b/composer.json index 296e9e4..d867155 100755 --- a/composer.json +++ b/composer.json @@ -15,5 +15,5 @@ "framework" ], "license": "MIT", - "version": "2.2.10" + "version": "2.2.11" } \ No newline at end of file diff --git a/index.js b/index.js index d2e4b2f..290309c 100755 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ /*! - * # Semantic UI 2.2.10 - Sticky + * # Semantic UI 2.2.11 - Sticky * http://github.com/semantic-org/semantic-ui/ * * @@ -287,7 +287,8 @@ module.exports = function(parameters) { context.offset.left += scrollContext.left; } module.cache = { - fits : ( element.height < scrollContext.height ), + fits : ( (element.height + settings.offset) <= scrollContext.height), + sameHeight : (element.height == context.height), scrollContext : { height : scrollContext.height }, @@ -306,7 +307,7 @@ module.exports = function(parameters) { } }; module.set.containerSize(); - module.set.size(); + module.stick(); module.debug('Caching element positions', module.cache); } @@ -375,6 +376,11 @@ module.exports = function(parameters) { elementScroll: function(scroll) { delete module.elementScroll; }, + minimumSize: function() { + $container + .css('min-height', '') + ; + }, offset: function() { $module.css('margin-top', ''); } @@ -468,6 +474,7 @@ module.exports = function(parameters) { cachedPosition = scroll || $scroll.scrollTop(), cache = module.cache, fits = cache.fits, + sameHeight = cache.sameHeight, element = cache.element, scrollContext = cache.scrollContext, context = cache.context, @@ -487,8 +494,7 @@ module.exports = function(parameters) { doesntFit = !fits, elementVisible = (element.height !== 0) ; - - if(elementVisible) { + if(elementVisible && !sameHeight) { if( module.is.initialPosition() ) { if(scroll.top >= context.bottom) { @@ -615,6 +621,9 @@ module.exports = function(parameters) { fixTop: function() { module.debug('Fixing element to top of page'); + if(settings.setSize) { + module.set.size(); + } module.set.minimumSize(); module.set.offset(); $module @@ -633,6 +642,9 @@ module.exports = function(parameters) { fixBottom: function() { module.debug('Sticking element to bottom of page'); + if(settings.setSize) { + module.set.size(); + } module.set.minimumSize(); module.set.offset(); $module @@ -664,6 +676,7 @@ module.exports = function(parameters) { unfix: function() { if( module.is.fixed() ) { module.debug('Removing fixed position on element'); + module.remove.minimumSize(); module.remove.offset(); $module .removeClass(className.fixed) @@ -899,7 +912,11 @@ _module.exports.settings = { // Offset to adjust scroll when attached to bottom of screen bottomOffset : 0, - jitter : 5, // will only set container height if difference between context and container is larger than this number + // will only set container height if difference between context and container is larger than this number + jitter : 5, + + // set width of sticky element when it is fixed to page (used to make sure 100% width is maintained if no fixed size set) + setSize : true, // Whether to automatically observe changes with Mutation Observers observeChanges : false, diff --git a/package.json b/package.json index af9c087..3e430fe 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "semantic-ui-sticky", - "version": "2.2.10", + "version": "2.2.11", "title": "Semantic UI - Sticky", "description": "Single component release of sticky", "homepage": "http://www.semantic-ui.com", diff --git a/sticky.css b/sticky.css index 3b996c4..d6f756e 100755 --- a/sticky.css +++ b/sticky.css @@ -1,5 +1,5 @@ /*! - * # Semantic UI 2.2.10 - Sticky + * # Semantic UI 2.2.11 - Sticky * http://github.com/semantic-org/semantic-ui/ * * diff --git a/sticky.js b/sticky.js index 6d02f3e..1322843 100755 --- a/sticky.js +++ b/sticky.js @@ -1,5 +1,5 @@ /*! - * # Semantic UI 2.2.10 - Sticky + * # Semantic UI 2.2.11 - Sticky * http://github.com/semantic-org/semantic-ui/ * * @@ -286,7 +286,8 @@ $.fn.sticky = function(parameters) { context.offset.left += scrollContext.left; } module.cache = { - fits : ( element.height < scrollContext.height ), + fits : ( (element.height + settings.offset) <= scrollContext.height), + sameHeight : (element.height == context.height), scrollContext : { height : scrollContext.height }, @@ -305,7 +306,7 @@ $.fn.sticky = function(parameters) { } }; module.set.containerSize(); - module.set.size(); + module.stick(); module.debug('Caching element positions', module.cache); } @@ -374,6 +375,11 @@ $.fn.sticky = function(parameters) { elementScroll: function(scroll) { delete module.elementScroll; }, + minimumSize: function() { + $container + .css('min-height', '') + ; + }, offset: function() { $module.css('margin-top', ''); } @@ -467,6 +473,7 @@ $.fn.sticky = function(parameters) { cachedPosition = scroll || $scroll.scrollTop(), cache = module.cache, fits = cache.fits, + sameHeight = cache.sameHeight, element = cache.element, scrollContext = cache.scrollContext, context = cache.context, @@ -486,8 +493,7 @@ $.fn.sticky = function(parameters) { doesntFit = !fits, elementVisible = (element.height !== 0) ; - - if(elementVisible) { + if(elementVisible && !sameHeight) { if( module.is.initialPosition() ) { if(scroll.top >= context.bottom) { @@ -614,6 +620,9 @@ $.fn.sticky = function(parameters) { fixTop: function() { module.debug('Fixing element to top of page'); + if(settings.setSize) { + module.set.size(); + } module.set.minimumSize(); module.set.offset(); $module @@ -632,6 +641,9 @@ $.fn.sticky = function(parameters) { fixBottom: function() { module.debug('Sticking element to bottom of page'); + if(settings.setSize) { + module.set.size(); + } module.set.minimumSize(); module.set.offset(); $module @@ -663,6 +675,7 @@ $.fn.sticky = function(parameters) { unfix: function() { if( module.is.fixed() ) { module.debug('Removing fixed position on element'); + module.remove.minimumSize(); module.remove.offset(); $module .removeClass(className.fixed) @@ -898,7 +911,11 @@ $.fn.sticky.settings = { // Offset to adjust scroll when attached to bottom of screen bottomOffset : 0, - jitter : 5, // will only set container height if difference between context and container is larger than this number + // will only set container height if difference between context and container is larger than this number + jitter : 5, + + // set width of sticky element when it is fixed to page (used to make sure 100% width is maintained if no fixed size set) + setSize : true, // Whether to automatically observe changes with Mutation Observers observeChanges : false, diff --git a/sticky.min.css b/sticky.min.css index ed4f608..0591f45 100755 --- a/sticky.min.css +++ b/sticky.min.css @@ -1,5 +1,5 @@ /*! - * # Semantic UI 2.2.10 - Sticky + * # Semantic UI 2.2.11 - Sticky * http://github.com/semantic-org/semantic-ui/ * * diff --git a/sticky.min.js b/sticky.min.js index bb72b55..9a3e9bf 100755 --- a/sticky.min.js +++ b/sticky.min.js @@ -1,5 +1,5 @@ /*! - * # Semantic UI 2.2.10 - Sticky + * # Semantic UI 2.2.11 - Sticky * http://github.com/semantic-org/semantic-ui/ * * @@ -7,4 +7,4 @@ * http://opensource.org/licenses/MIT * */ -!function(e,t,o,n){"use strict";t="undefined"!=typeof t&&t.Math==Math?t:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")(),e.fn.sticky=function(i){var s,r=e(this),c=r.selector||"",l=(new Date).getTime(),a=[],f=arguments[0],m="string"==typeof f,u=[].slice.call(arguments,1);return r.each(function(){var r,d,h,g,p,b=e.isPlainObject(i)?e.extend(!0,{},e.fn.sticky.settings,i):e.extend({},e.fn.sticky.settings),v=b.className,x=b.namespace,C=b.error,S="."+x,y="module-"+x,k=e(this),T=e(t),w=e(b.scrollContext),z=(k.selector||"",k.data(y)),B=t.requestAnimationFrame||t.mozRequestAnimationFrame||t.webkitRequestAnimationFrame||t.msRequestAnimationFrame||function(e){setTimeout(e,0)},P=this;p={initialize:function(){p.determineContainer(),p.determineContext(),p.verbose("Initializing sticky",b,r),p.save.positions(),p.checkErrors(),p.bind.events(),b.observeChanges&&p.observeChanges(),p.instantiate()},instantiate:function(){p.verbose("Storing instance of module",p),z=p,k.data(y,p)},destroy:function(){p.verbose("Destroying previous instance"),p.reset(),h&&h.disconnect(),g&&g.disconnect(),T.off("load"+S,p.event.load).off("resize"+S,p.event.resize),w.off("scrollchange"+S,p.event.scrollchange),k.removeData(y)},observeChanges:function(){"MutationObserver"in t&&(h=new MutationObserver(p.event.documentChanged),g=new MutationObserver(p.event.changed),h.observe(o,{childList:!0,subtree:!0}),g.observe(P,{childList:!0,subtree:!0}),g.observe(d[0],{childList:!0,subtree:!0}),p.debug("Setting up mutation observer",g))},determineContainer:function(){r=b.container?e(b.container):k.offsetParent()},determineContext:function(){return d=b.context?e(b.context):r,0===d.length?void p.error(C.invalidContext,b.context,k):void 0},checkErrors:function(){return p.is.hidden()&&p.error(C.visible,k),p.cache.element.height>p.cache.context.height?(p.reset(),void p.error(C.elementSize,k)):void 0},bind:{events:function(){T.on("load"+S,p.event.load).on("resize"+S,p.event.resize),w.off("scroll"+S).on("scroll"+S,p.event.scroll).on("scrollchange"+S,p.event.scrollchange)}},event:{changed:function(e){clearTimeout(p.timer),p.timer=setTimeout(function(){p.verbose("DOM tree modified, updating sticky menu",e),p.refresh()},100)},documentChanged:function(t){[].forEach.call(t,function(t){t.removedNodes&&[].forEach.call(t.removedNodes,function(t){(t==P||e(t).find(P).length>0)&&(p.debug("Element removed from DOM, tearing down events"),p.destroy())})})},load:function(){p.verbose("Page contents finished loading"),B(p.refresh)},resize:function(){p.verbose("Window resized"),B(p.refresh)},scroll:function(){B(function(){w.triggerHandler("scrollchange"+S,w.scrollTop())})},scrollchange:function(e,t){p.stick(t),b.onScroll.call(P)}},refresh:function(e){p.reset(),b.context||p.determineContext(),e&&p.determineContainer(),p.save.positions(),p.stick(),b.onReposition.call(P)},supports:{sticky:function(){var t=e("
");t[0];return t.addClass(v.supported),t.css("position").match("sticky")}},save:{lastScroll:function(e){p.lastScroll=e},elementScroll:function(e){p.elementScroll=e},positions:function(){var e={height:w.height()},t={margin:{top:parseInt(k.css("margin-top"),10),bottom:parseInt(k.css("margin-bottom"),10)},offset:k.offset(),width:k.outerWidth(),height:k.outerHeight()},o={offset:d.offset(),height:d.outerHeight()};({height:r.outerHeight()});p.is.standardScroll()||(p.debug("Non-standard scroll. Removing scroll offset from element offset"),e.top=w.scrollTop(),e.left=w.scrollLeft(),t.offset.top+=e.top,o.offset.top+=e.top,t.offset.left+=e.left,o.offset.left+=e.left),p.cache={fits:t.heighte&&(t="up")),t},scrollChange:function(e){return e=e||w.scrollTop(),p.lastScroll?e-p.lastScroll:0},currentElementScroll:function(){return p.elementScroll?p.elementScroll:p.is.top()?Math.abs(parseInt(k.css("top"),10))||0:Math.abs(parseInt(k.css("bottom"),10))||0},elementScroll:function(e){e=e||w.scrollTop();var t=p.cache.element,o=p.cache.scrollContext,n=p.get.scrollChange(e),i=t.height-o.height+b.offset,s=p.get.currentElementScroll(),r=s+n;return s=p.cache.fits||0>r?0:r>i?i:r}},remove:{lastScroll:function(){delete p.lastScroll},elementScroll:function(e){delete p.elementScroll},offset:function(){k.css("margin-top","")}},set:{offset:function(){p.verbose("Setting offset on element",b.offset),k.css("margin-top",b.offset)},containerSize:function(){var e=r.get(0).tagName;"HTML"===e||"body"==e?p.determineContainer():Math.abs(r.outerHeight()-p.cache.context.height)>b.jitter&&(p.debug("Context has padding, specifying exact height for container",p.cache.context.height),r.css({height:p.cache.context.height}))},minimumSize:function(){var e=p.cache.element;r.css("min-height",e.height)},scroll:function(e){p.debug("Setting scroll on element",e),p.elementScroll!=e&&(p.is.top()&&k.css("bottom","").css("top",-e),p.is.bottom()&&k.css("top","").css("bottom",e))},size:function(){0!==p.cache.element.height&&0!==p.cache.element.width&&(P.style.setProperty("width",p.cache.element.width+"px","important"),P.style.setProperty("height",p.cache.element.height+"px","important"))}},is:{standardScroll:function(){return w[0]==t},top:function(){return k.hasClass(v.top)},bottom:function(){return k.hasClass(v.bottom)},initialPosition:function(){return!p.is.fixed()&&!p.is.bound()},hidden:function(){return!k.is(":visible")},bound:function(){return k.hasClass(v.bound)},fixed:function(){return k.hasClass(v.fixed)}},stick:function(e){var t=e||w.scrollTop(),o=p.cache,n=o.fits,i=o.element,s=o.scrollContext,r=o.context,c=p.is.bottom()&&b.pushing?b.bottomOffset:b.offset,e={top:t+c,bottom:t+c+s.height},l=(p.get.direction(e.top),n?0:p.get.elementScroll(e.top)),a=!n,f=0!==i.height;f&&(p.is.initialPosition()?e.top>=r.bottom?(p.debug("Initial element position is bottom of container"),p.bindBottom()):e.top>i.top&&(i.height+e.top-l>=r.bottom?(p.debug("Initial element position is bottom of container"),p.bindBottom()):(p.debug("Initial element position is fixed"),p.fixTop())):p.is.fixed()?p.is.top()?e.top<=i.top?(p.debug("Fixed element reached top of container"),p.setInitialPosition()):i.height+e.top-l>=r.bottom?(p.debug("Fixed element reached bottom of container"),p.bindBottom()):a&&(p.set.scroll(l),p.save.lastScroll(e.top),p.save.elementScroll(l)):p.is.bottom()&&(e.bottom-i.height<=i.top?(p.debug("Bottom fixed rail has reached top of container"),p.setInitialPosition()):e.bottom>=r.bottom?(p.debug("Bottom fixed rail has reached bottom of container"),p.bindBottom()):a&&(p.set.scroll(l),p.save.lastScroll(e.top),p.save.elementScroll(l))):p.is.bottom()&&(e.top<=i.top?(p.debug("Jumped from bottom fixed to top fixed, most likely used home/end button"),p.setInitialPosition()):b.pushing?p.is.bound()&&e.bottom<=r.bottom&&(p.debug("Fixing bottom attached element to bottom of browser."),p.fixBottom()):p.is.bound()&&e.top<=r.bottom-i.height&&(p.debug("Fixing bottom attached element to top of browser."),p.fixTop())))},bindTop:function(){p.debug("Binding element to top of parent container"),p.remove.offset(),k.css({left:"",top:"",marginBottom:""}).removeClass(v.fixed).removeClass(v.bottom).addClass(v.bound).addClass(v.top),b.onTop.call(P),b.onUnstick.call(P)},bindBottom:function(){p.debug("Binding element to bottom of parent container"),p.remove.offset(),k.css({left:"",top:""}).removeClass(v.fixed).removeClass(v.top).addClass(v.bound).addClass(v.bottom),b.onBottom.call(P),b.onUnstick.call(P)},setInitialPosition:function(){p.debug("Returning to initial position"),p.unfix(),p.unbind()},fixTop:function(){p.debug("Fixing element to top of page"),p.set.minimumSize(),p.set.offset(),k.css({left:p.cache.element.left,bottom:"",marginBottom:""}).removeClass(v.bound).removeClass(v.bottom).addClass(v.fixed).addClass(v.top),b.onStick.call(P)},fixBottom:function(){p.debug("Sticking element to bottom of page"),p.set.minimumSize(),p.set.offset(),k.css({left:p.cache.element.left,bottom:"",marginBottom:""}).removeClass(v.bound).removeClass(v.top).addClass(v.fixed).addClass(v.bottom),b.onStick.call(P)},unbind:function(){p.is.bound()&&(p.debug("Removing container bound position on element"),p.remove.offset(),k.removeClass(v.bound).removeClass(v.top).removeClass(v.bottom))},unfix:function(){p.is.fixed()&&(p.debug("Removing fixed position on element"),p.remove.offset(),k.removeClass(v.fixed).removeClass(v.top).removeClass(v.bottom),b.onUnstick.call(P))},reset:function(){p.debug("Resetting elements position"),p.unbind(),p.unfix(),p.resetCSS(),p.remove.offset(),p.remove.lastScroll()},resetCSS:function(){k.css({width:"",height:""}),r.css({height:""})},setting:function(t,o){if(e.isPlainObject(t))e.extend(!0,b,t);else{if(o===n)return b[t];b[t]=o}},internal:function(t,o){if(e.isPlainObject(t))e.extend(!0,p,t);else{if(o===n)return p[t];p[t]=o}},debug:function(){!b.silent&&b.debug&&(b.performance?p.performance.log(arguments):(p.debug=Function.prototype.bind.call(console.info,console,b.name+":"),p.debug.apply(console,arguments)))},verbose:function(){!b.silent&&b.verbose&&b.debug&&(b.performance?p.performance.log(arguments):(p.verbose=Function.prototype.bind.call(console.info,console,b.name+":"),p.verbose.apply(console,arguments)))},error:function(){b.silent||(p.error=Function.prototype.bind.call(console.error,console,b.name+":"),p.error.apply(console,arguments))},performance:{log:function(e){var t,o,n;b.performance&&(t=(new Date).getTime(),n=l||t,o=t-n,l=t,a.push({Name:e[0],Arguments:[].slice.call(e,1)||"",Element:P,"Execution Time":o})),clearTimeout(p.performance.timer),p.performance.timer=setTimeout(p.performance.display,0)},display:function(){var t=b.name+":",o=0;l=!1,clearTimeout(p.performance.timer),e.each(a,function(e,t){o+=t["Execution Time"]}),t+=" "+o+"ms",c&&(t+=" '"+c+"'"),(console.group!==n||console.table!==n)&&a.length>0&&(console.groupCollapsed(t),console.table?console.table(a):e.each(a,function(e,t){console.log(t.Name+": "+t["Execution Time"]+"ms")}),console.groupEnd()),a=[]}},invoke:function(t,o,i){var r,c,l,a=z;return o=o||u,i=P||i,"string"==typeof t&&a!==n&&(t=t.split(/[\. ]/),r=t.length-1,e.each(t,function(o,i){var s=o!=r?i+t[o+1].charAt(0).toUpperCase()+t[o+1].slice(1):t;if(e.isPlainObject(a[s])&&o!=r)a=a[s];else{if(a[s]!==n)return c=a[s],!1;if(!e.isPlainObject(a[i])||o==r)return a[i]!==n?(c=a[i],!1):!1;a=a[i]}})),e.isFunction(c)?l=c.apply(i,o):c!==n&&(l=c),e.isArray(s)?s.push(l):s!==n?s=[s,l]:l!==n&&(s=l),c}},m?(z===n&&p.initialize(),p.invoke(f)):(z!==n&&z.invoke("destroy"),p.initialize())}),s!==n?s:this},e.fn.sticky.settings={name:"Sticky",namespace:"sticky",silent:!1,debug:!1,verbose:!0,performance:!0,pushing:!1,context:!1,container:!1,scrollContext:t,offset:0,bottomOffset:0,jitter:5,observeChanges:!1,onReposition:function(){},onScroll:function(){},onStick:function(){},onUnstick:function(){},onTop:function(){},onBottom:function(){},error:{container:"Sticky element must be inside a relative container",visible:"Element is hidden, you must call refresh after element becomes visible. Use silent setting to surpress this warning in production.",method:"The method you called is not defined.",invalidContext:"Context specified does not exist",elementSize:"Sticky element is larger than its container, cannot create sticky."},className:{bound:"bound",fixed:"fixed",supported:"native",top:"top",bottom:"bottom"}}}(jQuery,window,document); \ No newline at end of file +!function(e,t,o,n){"use strict";t=void 0!==t&&t.Math==Math?t:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")(),e.fn.sticky=function(n){var i,s=e(this),r=s.selector||"",c=(new Date).getTime(),l=[],a=arguments[0],f="string"==typeof a,m=[].slice.call(arguments,1);return s.each(function(){var s,d,u,h,g,p=e.isPlainObject(n)?e.extend(!0,{},e.fn.sticky.settings,n):e.extend({},e.fn.sticky.settings),b=p.className,v=p.namespace,x=p.error,C="."+v,S="module-"+v,y=e(this),k=e(t),z=e(p.scrollContext),T=(y.selector,y.data(S)),w=t.requestAnimationFrame||t.mozRequestAnimationFrame||t.webkitRequestAnimationFrame||t.msRequestAnimationFrame||function(e){setTimeout(e,0)},B=this;g={initialize:function(){g.determineContainer(),g.determineContext(),g.verbose("Initializing sticky",p,s),g.save.positions(),g.checkErrors(),g.bind.events(),p.observeChanges&&g.observeChanges(),g.instantiate()},instantiate:function(){g.verbose("Storing instance of module",g),T=g,y.data(S,g)},destroy:function(){g.verbose("Destroying previous instance"),g.reset(),u&&u.disconnect(),h&&h.disconnect(),k.off("load"+C,g.event.load).off("resize"+C,g.event.resize),z.off("scrollchange"+C,g.event.scrollchange),y.removeData(S)},observeChanges:function(){"MutationObserver"in t&&(u=new MutationObserver(g.event.documentChanged),h=new MutationObserver(g.event.changed),u.observe(o,{childList:!0,subtree:!0}),h.observe(B,{childList:!0,subtree:!0}),h.observe(d[0],{childList:!0,subtree:!0}),g.debug("Setting up mutation observer",h))},determineContainer:function(){s=p.container?e(p.container):y.offsetParent()},determineContext:function(){if(d=p.context?e(p.context):s,0===d.length)return void g.error(x.invalidContext,p.context,y)},checkErrors:function(){if(g.is.hidden()&&g.error(x.visible,y),g.cache.element.height>g.cache.context.height)return g.reset(),void g.error(x.elementSize,y)},bind:{events:function(){k.on("load"+C,g.event.load).on("resize"+C,g.event.resize),z.off("scroll"+C).on("scroll"+C,g.event.scroll).on("scrollchange"+C,g.event.scrollchange)}},event:{changed:function(e){clearTimeout(g.timer),g.timer=setTimeout(function(){g.verbose("DOM tree modified, updating sticky menu",e),g.refresh()},100)},documentChanged:function(t){[].forEach.call(t,function(t){t.removedNodes&&[].forEach.call(t.removedNodes,function(t){(t==B||e(t).find(B).length>0)&&(g.debug("Element removed from DOM, tearing down events"),g.destroy())})})},load:function(){g.verbose("Page contents finished loading"),w(g.refresh)},resize:function(){g.verbose("Window resized"),w(g.refresh)},scroll:function(){w(function(){z.triggerHandler("scrollchange"+C,z.scrollTop())})},scrollchange:function(e,t){g.stick(t),p.onScroll.call(B)}},refresh:function(e){g.reset(),p.context||g.determineContext(),e&&g.determineContainer(),g.save.positions(),g.stick(),p.onReposition.call(B)},supports:{sticky:function(){var t=e("
");t[0];return t.addClass(b.supported),t.css("position").match("sticky")}},save:{lastScroll:function(e){g.lastScroll=e},elementScroll:function(e){g.elementScroll=e},positions:function(){var e={height:z.height()},t={margin:{top:parseInt(y.css("margin-top"),10),bottom:parseInt(y.css("margin-bottom"),10)},offset:y.offset(),width:y.outerWidth(),height:y.outerHeight()},o={offset:d.offset(),height:d.outerHeight()};s.outerHeight();g.is.standardScroll()||(g.debug("Non-standard scroll. Removing scroll offset from element offset"),e.top=z.scrollTop(),e.left=z.scrollLeft(),t.offset.top+=e.top,o.offset.top+=e.top,t.offset.left+=e.left,o.offset.left+=e.left),g.cache={fits:t.height+p.offset<=e.height,sameHeight:t.height==o.height,scrollContext:{height:e.height},element:{margin:t.margin,top:t.offset.top-t.margin.top,left:t.offset.left,width:t.width,height:t.height,bottom:t.offset.top+t.height},context:{top:o.offset.top,height:o.height,bottom:o.offset.top+o.height}},g.set.containerSize(),g.stick(),g.debug("Caching element positions",g.cache)}},get:{direction:function(e){var t="down";return e=e||z.scrollTop(),void 0!==g.lastScroll&&(g.lastScrolle&&(t="up")),t},scrollChange:function(e){return e=e||z.scrollTop(),g.lastScroll?e-g.lastScroll:0},currentElementScroll:function(){return g.elementScroll?g.elementScroll:g.is.top()?Math.abs(parseInt(y.css("top"),10))||0:Math.abs(parseInt(y.css("bottom"),10))||0},elementScroll:function(e){e=e||z.scrollTop();var t=g.cache.element,o=g.cache.scrollContext,n=g.get.scrollChange(e),i=t.height-o.height+p.offset,s=g.get.currentElementScroll(),r=s+n;return s=g.cache.fits||r<0?0:r>i?i:r}},remove:{lastScroll:function(){delete g.lastScroll},elementScroll:function(e){delete g.elementScroll},minimumSize:function(){s.css("min-height","")},offset:function(){y.css("margin-top","")}},set:{offset:function(){g.verbose("Setting offset on element",p.offset),y.css("margin-top",p.offset)},containerSize:function(){var e=s.get(0).tagName;"HTML"===e||"body"==e?g.determineContainer():Math.abs(s.outerHeight()-g.cache.context.height)>p.jitter&&(g.debug("Context has padding, specifying exact height for container",g.cache.context.height),s.css({height:g.cache.context.height}))},minimumSize:function(){var e=g.cache.element;s.css("min-height",e.height)},scroll:function(e){g.debug("Setting scroll on element",e),g.elementScroll!=e&&(g.is.top()&&y.css("bottom","").css("top",-e),g.is.bottom()&&y.css("top","").css("bottom",e))},size:function(){0!==g.cache.element.height&&0!==g.cache.element.width&&(B.style.setProperty("width",g.cache.element.width+"px","important"),B.style.setProperty("height",g.cache.element.height+"px","important"))}},is:{standardScroll:function(){return z[0]==t},top:function(){return y.hasClass(b.top)},bottom:function(){return y.hasClass(b.bottom)},initialPosition:function(){return!g.is.fixed()&&!g.is.bound()},hidden:function(){return!y.is(":visible")},bound:function(){return y.hasClass(b.bound)},fixed:function(){return y.hasClass(b.fixed)}},stick:function(e){var t=e||z.scrollTop(),o=g.cache,n=o.fits,i=o.sameHeight,s=o.element,r=o.scrollContext,c=o.context,l=g.is.bottom()&&p.pushing?p.bottomOffset:p.offset,e={top:t+l,bottom:t+l+r.height},a=(g.get.direction(e.top),n?0:g.get.elementScroll(e.top)),f=!n;0!==s.height&&!i&&(g.is.initialPosition()?e.top>=c.bottom?(g.debug("Initial element position is bottom of container"),g.bindBottom()):e.top>s.top&&(s.height+e.top-a>=c.bottom?(g.debug("Initial element position is bottom of container"),g.bindBottom()):(g.debug("Initial element position is fixed"),g.fixTop())):g.is.fixed()?g.is.top()?e.top<=s.top?(g.debug("Fixed element reached top of container"),g.setInitialPosition()):s.height+e.top-a>=c.bottom?(g.debug("Fixed element reached bottom of container"),g.bindBottom()):f&&(g.set.scroll(a),g.save.lastScroll(e.top),g.save.elementScroll(a)):g.is.bottom()&&(e.bottom-s.height<=s.top?(g.debug("Bottom fixed rail has reached top of container"),g.setInitialPosition()):e.bottom>=c.bottom?(g.debug("Bottom fixed rail has reached bottom of container"),g.bindBottom()):f&&(g.set.scroll(a),g.save.lastScroll(e.top),g.save.elementScroll(a))):g.is.bottom()&&(e.top<=s.top?(g.debug("Jumped from bottom fixed to top fixed, most likely used home/end button"),g.setInitialPosition()):p.pushing?g.is.bound()&&e.bottom<=c.bottom&&(g.debug("Fixing bottom attached element to bottom of browser."),g.fixBottom()):g.is.bound()&&e.top<=c.bottom-s.height&&(g.debug("Fixing bottom attached element to top of browser."),g.fixTop())))},bindTop:function(){g.debug("Binding element to top of parent container"),g.remove.offset(),y.css({left:"",top:"",marginBottom:""}).removeClass(b.fixed).removeClass(b.bottom).addClass(b.bound).addClass(b.top),p.onTop.call(B),p.onUnstick.call(B)},bindBottom:function(){g.debug("Binding element to bottom of parent container"),g.remove.offset(),y.css({left:"",top:""}).removeClass(b.fixed).removeClass(b.top).addClass(b.bound).addClass(b.bottom),p.onBottom.call(B),p.onUnstick.call(B)},setInitialPosition:function(){g.debug("Returning to initial position"),g.unfix(),g.unbind()},fixTop:function(){g.debug("Fixing element to top of page"),p.setSize&&g.set.size(),g.set.minimumSize(),g.set.offset(),y.css({left:g.cache.element.left,bottom:"",marginBottom:""}).removeClass(b.bound).removeClass(b.bottom).addClass(b.fixed).addClass(b.top),p.onStick.call(B)},fixBottom:function(){g.debug("Sticking element to bottom of page"),p.setSize&&g.set.size(),g.set.minimumSize(),g.set.offset(),y.css({left:g.cache.element.left,bottom:"",marginBottom:""}).removeClass(b.bound).removeClass(b.top).addClass(b.fixed).addClass(b.bottom),p.onStick.call(B)},unbind:function(){g.is.bound()&&(g.debug("Removing container bound position on element"),g.remove.offset(),y.removeClass(b.bound).removeClass(b.top).removeClass(b.bottom))},unfix:function(){g.is.fixed()&&(g.debug("Removing fixed position on element"),g.remove.minimumSize(),g.remove.offset(),y.removeClass(b.fixed).removeClass(b.top).removeClass(b.bottom),p.onUnstick.call(B))},reset:function(){g.debug("Resetting elements position"),g.unbind(),g.unfix(),g.resetCSS(),g.remove.offset(),g.remove.lastScroll()},resetCSS:function(){y.css({width:"",height:""}),s.css({height:""})},setting:function(t,o){if(e.isPlainObject(t))e.extend(!0,p,t);else{if(void 0===o)return p[t];p[t]=o}},internal:function(t,o){if(e.isPlainObject(t))e.extend(!0,g,t);else{if(void 0===o)return g[t];g[t]=o}},debug:function(){!p.silent&&p.debug&&(p.performance?g.performance.log(arguments):(g.debug=Function.prototype.bind.call(console.info,console,p.name+":"),g.debug.apply(console,arguments)))},verbose:function(){!p.silent&&p.verbose&&p.debug&&(p.performance?g.performance.log(arguments):(g.verbose=Function.prototype.bind.call(console.info,console,p.name+":"),g.verbose.apply(console,arguments)))},error:function(){p.silent||(g.error=Function.prototype.bind.call(console.error,console,p.name+":"),g.error.apply(console,arguments))},performance:{log:function(e){var t,o,n;p.performance&&(t=(new Date).getTime(),n=c||t,o=t-n,c=t,l.push({Name:e[0],Arguments:[].slice.call(e,1)||"",Element:B,"Execution Time":o})),clearTimeout(g.performance.timer),g.performance.timer=setTimeout(g.performance.display,0)},display:function(){var t=p.name+":",o=0;c=!1,clearTimeout(g.performance.timer),e.each(l,function(e,t){o+=t["Execution Time"]}),t+=" "+o+"ms",r&&(t+=" '"+r+"'"),(void 0!==console.group||void 0!==console.table)&&l.length>0&&(console.groupCollapsed(t),console.table?console.table(l):e.each(l,function(e,t){console.log(t.Name+": "+t["Execution Time"]+"ms")}),console.groupEnd()),l=[]}},invoke:function(t,o,n){var s,r,c,l=T;return o=o||m,n=B||n,"string"==typeof t&&void 0!==l&&(t=t.split(/[\. ]/),s=t.length-1,e.each(t,function(o,n){var i=o!=s?n+t[o+1].charAt(0).toUpperCase()+t[o+1].slice(1):t;if(e.isPlainObject(l[i])&&o!=s)l=l[i];else{if(void 0!==l[i])return r=l[i],!1;if(!e.isPlainObject(l[n])||o==s)return void 0!==l[n]&&(r=l[n],!1);l=l[n]}})),e.isFunction(r)?c=r.apply(n,o):void 0!==r&&(c=r),e.isArray(i)?i.push(c):void 0!==i?i=[i,c]:void 0!==c&&(i=c),r}},f?(void 0===T&&g.initialize(),g.invoke(a)):(void 0!==T&&T.invoke("destroy"),g.initialize())}),void 0!==i?i:this},e.fn.sticky.settings={name:"Sticky",namespace:"sticky",silent:!1,debug:!1,verbose:!0,performance:!0,pushing:!1,context:!1,container:!1,scrollContext:t,offset:0,bottomOffset:0,jitter:5,setSize:!0,observeChanges:!1,onReposition:function(){},onScroll:function(){},onStick:function(){},onUnstick:function(){},onTop:function(){},onBottom:function(){},error:{container:"Sticky element must be inside a relative container",visible:"Element is hidden, you must call refresh after element becomes visible. Use silent setting to surpress this warning in production.",method:"The method you called is not defined.",invalidContext:"Context specified does not exist",elementSize:"Sticky element is larger than its container, cannot create sticky."},className:{bound:"bound",fixed:"fixed",supported:"native",top:"top",bottom:"bottom"}}}(jQuery,window,document); \ No newline at end of file