diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index b71057f..0907b16 100755 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,3 +1,9 @@ +### Version 2.0.4 - July 17, 2015 + +- **Sticky** - Fixed `sticky` element that cannot fit in viewport not scrolling correctly when fixed to viewport [#2605](https://github.com/Semantic-Org/Semantic-UI/issues/2605) +- **Sticky** - Fixed `sticky` content jumping from `fixed` to `bount bottom` when scroll position has surpassed bottom of container during page refresh. +- **Sticky** - Sticky no longer uses `bottomPadding` to determine bottom edge of container. + ### Version 2.0.0 - June 30, 2015 - **Visibility** - Visibility and sticky now use a more performant [pub/sub pattern](http://davidwalsh.name/pubsub-javascript) that will only attach a single event to context `scroll`. diff --git a/composer.json b/composer.json index 888df5d..b64557e 100755 --- a/composer.json +++ b/composer.json @@ -15,5 +15,5 @@ "framework" ], "license": "MIT", - "version": "2.0.3" + "version": "2.0.4" } \ No newline at end of file diff --git a/index.js b/index.js index f6827b4..4a2a521 100755 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ /*! - * # Semantic UI 2.0.3 - Sticky + * # Semantic UI 2.0.4 - Sticky * http://github.com/semantic-org/semantic-ui/ * * @@ -238,8 +238,7 @@ module.exports = function(parameters) { }, context = { offset : $context.offset(), - height : $context.outerHeight(), - bottomPadding : parseInt($context.css('padding-bottom'), 10) + height : $context.outerHeight() }, container = { height: $container.outerHeight() @@ -261,8 +260,7 @@ module.exports = function(parameters) { context: { top : context.offset.top, height : context.height, - bottomPadding : context.bottomPadding, - bottom : context.offset.top + context.height - context.bottomPadding + bottom : context.offset.top + context.height } }; module.set.containerSize(); @@ -458,8 +456,14 @@ module.exports = function(parameters) { } else if(scroll.top > element.top) { module.debug('Element passed, fixing element to page'); - module.fixTop(); + if( (element.height + scroll.top - elementScroll) > context.bottom ) { + module.bindBottom(); + } + else { + module.fixTop(); + } } + } else if( module.is.fixed() ) { @@ -476,6 +480,8 @@ module.exports = function(parameters) { // scroll element if larger than screen else if(doesntFit) { module.set.scroll(elementScroll); + module.save.lastScroll(scroll.top); + module.save.elementScroll(elementScroll); } } @@ -495,6 +501,8 @@ module.exports = function(parameters) { // scroll element if larger than screen else if(doesntFit) { module.set.scroll(elementScroll); + module.save.lastScroll(scroll.top); + module.save.elementScroll(elementScroll); } } @@ -514,10 +522,6 @@ module.exports = function(parameters) { } } } - - // save current scroll for next run - module.save.lastScroll(scroll.top); - module.save.elementScroll(elementScroll); }, bindTop: function() { @@ -543,8 +547,7 @@ module.exports = function(parameters) { $module .css({ left : '', - top : '', - marginBottom : module.cache.context.bottomPadding + top : '' }) .removeClass(className.fixed) .removeClass(className.top) diff --git a/package.js b/package.js index 51e1726..9912141 100755 --- a/package.js +++ b/package.js @@ -2,7 +2,7 @@ Package.describe({ name : 'semantic:ui-sticky', summary : 'Semantic UI - Sticky: Single component release', - version : '2.0.3', + version : '2.0.4', git : 'git://github.com/Semantic-Org/UI-Sticky.git', }); diff --git a/package.json b/package.json index 1b0133c..4a1a7d2 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "semantic-ui-sticky", - "version": "2.0.3", + "version": "2.0.4", "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 89a8c72..4bfb688 100755 --- a/sticky.css +++ b/sticky.css @@ -1,5 +1,5 @@ /*! - * # Semantic UI 2.0.3 - Sticky + * # Semantic UI 2.0.4 - Sticky * http://github.com/semantic-org/semantic-ui/ * * diff --git a/sticky.js b/sticky.js index e1d165c..8c54ef3 100755 --- a/sticky.js +++ b/sticky.js @@ -1,5 +1,5 @@ /*! - * # Semantic UI 2.0.3 - Sticky + * # Semantic UI 2.0.4 - Sticky * http://github.com/semantic-org/semantic-ui/ * * @@ -237,8 +237,7 @@ $.fn.sticky = function(parameters) { }, context = { offset : $context.offset(), - height : $context.outerHeight(), - bottomPadding : parseInt($context.css('padding-bottom'), 10) + height : $context.outerHeight() }, container = { height: $container.outerHeight() @@ -260,8 +259,7 @@ $.fn.sticky = function(parameters) { context: { top : context.offset.top, height : context.height, - bottomPadding : context.bottomPadding, - bottom : context.offset.top + context.height - context.bottomPadding + bottom : context.offset.top + context.height } }; module.set.containerSize(); @@ -457,8 +455,14 @@ $.fn.sticky = function(parameters) { } else if(scroll.top > element.top) { module.debug('Element passed, fixing element to page'); - module.fixTop(); + if( (element.height + scroll.top - elementScroll) > context.bottom ) { + module.bindBottom(); + } + else { + module.fixTop(); + } } + } else if( module.is.fixed() ) { @@ -475,6 +479,8 @@ $.fn.sticky = function(parameters) { // scroll element if larger than screen else if(doesntFit) { module.set.scroll(elementScroll); + module.save.lastScroll(scroll.top); + module.save.elementScroll(elementScroll); } } @@ -494,6 +500,8 @@ $.fn.sticky = function(parameters) { // scroll element if larger than screen else if(doesntFit) { module.set.scroll(elementScroll); + module.save.lastScroll(scroll.top); + module.save.elementScroll(elementScroll); } } @@ -513,10 +521,6 @@ $.fn.sticky = function(parameters) { } } } - - // save current scroll for next run - module.save.lastScroll(scroll.top); - module.save.elementScroll(elementScroll); }, bindTop: function() { @@ -542,8 +546,7 @@ $.fn.sticky = function(parameters) { $module .css({ left : '', - top : '', - marginBottom : module.cache.context.bottomPadding + top : '' }) .removeClass(className.fixed) .removeClass(className.top) diff --git a/sticky.min.css b/sticky.min.css index f3e414b..be72ad0 100755 --- a/sticky.min.css +++ b/sticky.min.css @@ -1,5 +1,5 @@ /*! - * # Semantic UI 2.0.3 - Sticky + * # Semantic UI 2.0.4 - Sticky * http://github.com/semantic-org/semantic-ui/ * * diff --git a/sticky.min.js b/sticky.min.js index 14d9a2e..b30a704 100755 --- a/sticky.min.js +++ b/sticky.min.js @@ -1,5 +1,5 @@ /*! - * # Semantic UI 2.0.3 - Sticky + * # Semantic UI 2.0.4 - Sticky * http://github.com/semantic-org/semantic-ui/ * * @@ -8,4 +8,4 @@ * http://opensource.org/licenses/MIT * */ -!function(e,t,o,n){"use strict";e.fn.sticky=function(o){var i,s=e(this),r=s.selector||"",c=(new Date).getTime(),l=[],a=arguments[0],m="string"==typeof a,f=[].slice.call(arguments,1);return s.each(function(){var s,u,d,h,g=e.isPlainObject(o)?e.extend(!0,{},e.fn.sticky.settings,o):e.extend({},e.fn.sticky.settings),b=g.className,p=g.namespace,v=g.error,x="."+p,C="module-"+p,S=e(this),y=e(t),k=e(g.scrollContext),w=(S.selector||"",S.data(C)),T=t.requestAnimationFrame||t.mozRequestAnimationFrame||t.webkitRequestAnimationFrame||t.msRequestAnimationFrame||function(e){setTimeout(e,0)},z=this;h={initialize:function(){h.determineContainer(),h.determineContext(),h.verbose("Initializing sticky",g,s),h.save.positions(),h.checkErrors(),h.bind.events(),g.observeChanges&&h.observeChanges(),h.instantiate()},instantiate:function(){h.verbose("Storing instance of module",h),w=h,S.data(C,h)},destroy:function(){h.verbose("Destroying previous instance"),h.reset(),d&&d.disconnect(),y.off("load"+x,h.event.load).off("resize"+x,h.event.resize),k.off("scrollchange"+x,h.event.scrollchange),S.removeData(C)},observeChanges:function(){var e=u[0];"MutationObserver"in t&&(d=new MutationObserver(function(e){clearTimeout(h.timer),h.timer=setTimeout(function(){h.verbose("DOM tree modified, updating sticky menu",e),h.refresh()},100)}),d.observe(z,{childList:!0,subtree:!0}),d.observe(e,{childList:!0,subtree:!0}),h.debug("Setting up mutation observer",d))},determineContainer:function(){s=S.offsetParent()},determineContext:function(){return u=g.context?e(g.context):s,0===u.length?void h.error(v.invalidContext,g.context,S):void 0},checkErrors:function(){return h.is.hidden()&&h.error(v.visible,S),h.cache.element.height>h.cache.context.height?(h.reset(),void h.error(v.elementSize,S)):void 0},bind:{events:function(){y.on("load"+x,h.event.load).on("resize"+x,h.event.resize),k.off("scroll"+x).on("scroll"+x,h.event.scroll).on("scrollchange"+x,h.event.scrollchange)}},event:{load:function(){h.verbose("Page contents finished loading"),T(h.refresh)},resize:function(){h.verbose("Window resized"),T(h.refresh)},scroll:function(){T(function(){k.triggerHandler("scrollchange"+x,k.scrollTop())})},scrollchange:function(e,t){h.stick(t),g.onScroll.call(z)}},refresh:function(e){h.reset(),g.context||h.determineContext(),e&&h.determineContainer(),h.save.positions(),h.stick(),g.onReposition.call(z)},supports:{sticky:function(){{var t=e("
");t[0]}return t.addClass(b.supported),t.css("position").match("sticky")}},save:{lastScroll:function(e){h.lastScroll=e},elementScroll:function(e){h.elementScroll=e},positions:function(){{var e={height:y.height()},t={margin:{top:parseInt(S.css("margin-top"),10),bottom:parseInt(S.css("margin-bottom"),10)},offset:S.offset(),width:S.outerWidth(),height:S.outerHeight()},o={offset:u.offset(),height:u.outerHeight(),bottomPadding:parseInt(u.css("padding-bottom"),10)};({height:s.outerHeight()})}h.cache={fits:t.heighte&&(t="up")),t},scrollChange:function(e){return e=e||k.scrollTop(),h.lastScroll?e-h.lastScroll:0},currentElementScroll:function(){return h.elementScroll?h.elementScroll:h.is.top()?Math.abs(parseInt(S.css("top"),10))||0:Math.abs(parseInt(S.css("bottom"),10))||0},elementScroll:function(e){e=e||k.scrollTop();var t=h.cache.element,o=h.cache.window,n=h.get.scrollChange(e),i=t.height-o.height+g.offset,s=h.get.currentElementScroll(),r=s+n;return s=h.cache.fits||0>r?0:r>i?i:r}},remove:{lastScroll:function(){delete h.lastScroll},elementScroll:function(e){delete h.elementScroll},offset:function(){S.css("margin-top","")}},set:{offset:function(){h.verbose("Setting offset on element",g.offset),S.css("margin-top",g.offset)},containerSize:function(){var e=s.get(0).tagName;"HTML"===e||"body"==e?h.determineContainer():Math.abs(s.outerHeight()-h.cache.context.height)>g.jitter&&(h.debug("Context has padding, specifying exact height for container",h.cache.context.height),s.css({height:h.cache.context.height}))},minimumSize:function(){var e=h.cache.element;s.css("min-height",e.height)},scroll:function(e){h.debug("Setting scroll on element",e),h.elementScroll!=e&&(h.is.top()&&S.css("bottom","").css("top",-e),h.is.bottom()&&S.css("top","").css("bottom",e))},size:function(){0!==h.cache.element.height&&0!==h.cache.element.width&&S.css({width:h.cache.element.width,height:h.cache.element.height})}},is:{top:function(){return S.hasClass(b.top)},bottom:function(){return S.hasClass(b.bottom)},initialPosition:function(){return!h.is.fixed()&&!h.is.bound()},hidden:function(){return!S.is(":visible")},bound:function(){return S.hasClass(b.bound)},fixed:function(){return S.hasClass(b.fixed)}},stick:function(e){var t=e||k.scrollTop(),o=h.cache,n=o.fits,i=o.element,s=o.window,r=o.context,c=h.is.bottom()&&g.pushing?g.bottomOffset:g.offset,e={top:t+c,bottom:t+c+s.height},l=(h.get.direction(e.top),n?0:h.get.elementScroll(e.top)),a=!n,m=0!==i.height;m&&(h.is.initialPosition()?e.top>r.bottom?(h.debug("Element bottom of container"),h.bindBottom()):e.top>i.top&&(h.debug("Element passed, fixing element to page"),h.fixTop()):h.is.fixed()?h.is.top()?e.topr.bottom?(h.debug("Fixed element reached bottom of container"),h.bindBottom()):a&&h.set.scroll(l):h.is.bottom()&&(e.bottom-i.heightr.bottom?(h.debug("Bottom fixed rail has reached bottom of container"),h.bindBottom()):a&&h.set.scroll(l)):h.is.bottom()&&(g.pushing?h.is.bound()&&e.bottom0&&(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,s){var r,c,l,a=w;return o=o||f,s=z||s,"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(s,o):c!==n&&(l=c),e.isArray(i)?i.push(l):i!==n?i=[i,l]:l!==n&&(i=l),c}},m?(w===n&&h.initialize(),h.invoke(a)):(w!==n&&w.invoke("destroy"),h.initialize())}),i!==n?i:this},e.fn.sticky.settings={name:"Sticky",namespace:"sticky",debug:!1,verbose:!0,performance:!0,pushing:!1,context:!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",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";e.fn.sticky=function(o){var i,s=e(this),r=s.selector||"",c=(new Date).getTime(),l=[],a=arguments[0],m="string"==typeof a,f=[].slice.call(arguments,1);return s.each(function(){var s,u,d,h,g=e.isPlainObject(o)?e.extend(!0,{},e.fn.sticky.settings,o):e.extend({},e.fn.sticky.settings),b=g.className,p=g.namespace,v=g.error,x="."+p,C="module-"+p,S=e(this),y=e(t),k=e(g.scrollContext),w=(S.selector||"",S.data(C)),T=t.requestAnimationFrame||t.mozRequestAnimationFrame||t.webkitRequestAnimationFrame||t.msRequestAnimationFrame||function(e){setTimeout(e,0)},z=this;h={initialize:function(){h.determineContainer(),h.determineContext(),h.verbose("Initializing sticky",g,s),h.save.positions(),h.checkErrors(),h.bind.events(),g.observeChanges&&h.observeChanges(),h.instantiate()},instantiate:function(){h.verbose("Storing instance of module",h),w=h,S.data(C,h)},destroy:function(){h.verbose("Destroying previous instance"),h.reset(),d&&d.disconnect(),y.off("load"+x,h.event.load).off("resize"+x,h.event.resize),k.off("scrollchange"+x,h.event.scrollchange),S.removeData(C)},observeChanges:function(){var e=u[0];"MutationObserver"in t&&(d=new MutationObserver(function(e){clearTimeout(h.timer),h.timer=setTimeout(function(){h.verbose("DOM tree modified, updating sticky menu",e),h.refresh()},100)}),d.observe(z,{childList:!0,subtree:!0}),d.observe(e,{childList:!0,subtree:!0}),h.debug("Setting up mutation observer",d))},determineContainer:function(){s=S.offsetParent()},determineContext:function(){return u=g.context?e(g.context):s,0===u.length?void h.error(v.invalidContext,g.context,S):void 0},checkErrors:function(){return h.is.hidden()&&h.error(v.visible,S),h.cache.element.height>h.cache.context.height?(h.reset(),void h.error(v.elementSize,S)):void 0},bind:{events:function(){y.on("load"+x,h.event.load).on("resize"+x,h.event.resize),k.off("scroll"+x).on("scroll"+x,h.event.scroll).on("scrollchange"+x,h.event.scrollchange)}},event:{load:function(){h.verbose("Page contents finished loading"),T(h.refresh)},resize:function(){h.verbose("Window resized"),T(h.refresh)},scroll:function(){T(function(){k.triggerHandler("scrollchange"+x,k.scrollTop())})},scrollchange:function(e,t){h.stick(t),g.onScroll.call(z)}},refresh:function(e){h.reset(),g.context||h.determineContext(),e&&h.determineContainer(),h.save.positions(),h.stick(),g.onReposition.call(z)},supports:{sticky:function(){var t=e("
");t[0];return t.addClass(b.supported),t.css("position").match("sticky")}},save:{lastScroll:function(e){h.lastScroll=e},elementScroll:function(e){h.elementScroll=e},positions:function(){var e={height:y.height()},t={margin:{top:parseInt(S.css("margin-top"),10),bottom:parseInt(S.css("margin-bottom"),10)},offset:S.offset(),width:S.outerWidth(),height:S.outerHeight()},o={offset:u.offset(),height:u.outerHeight()};({height:s.outerHeight()});h.cache={fits:t.heighte&&(t="up")),t},scrollChange:function(e){return e=e||k.scrollTop(),h.lastScroll?e-h.lastScroll:0},currentElementScroll:function(){return h.elementScroll?h.elementScroll:h.is.top()?Math.abs(parseInt(S.css("top"),10))||0:Math.abs(parseInt(S.css("bottom"),10))||0},elementScroll:function(e){e=e||k.scrollTop();var t=h.cache.element,o=h.cache.window,n=h.get.scrollChange(e),i=t.height-o.height+g.offset,s=h.get.currentElementScroll(),r=s+n;return s=h.cache.fits||0>r?0:r>i?i:r}},remove:{lastScroll:function(){delete h.lastScroll},elementScroll:function(e){delete h.elementScroll},offset:function(){S.css("margin-top","")}},set:{offset:function(){h.verbose("Setting offset on element",g.offset),S.css("margin-top",g.offset)},containerSize:function(){var e=s.get(0).tagName;"HTML"===e||"body"==e?h.determineContainer():Math.abs(s.outerHeight()-h.cache.context.height)>g.jitter&&(h.debug("Context has padding, specifying exact height for container",h.cache.context.height),s.css({height:h.cache.context.height}))},minimumSize:function(){var e=h.cache.element;s.css("min-height",e.height)},scroll:function(e){h.debug("Setting scroll on element",e),h.elementScroll!=e&&(h.is.top()&&S.css("bottom","").css("top",-e),h.is.bottom()&&S.css("top","").css("bottom",e))},size:function(){0!==h.cache.element.height&&0!==h.cache.element.width&&S.css({width:h.cache.element.width,height:h.cache.element.height})}},is:{top:function(){return S.hasClass(b.top)},bottom:function(){return S.hasClass(b.bottom)},initialPosition:function(){return!h.is.fixed()&&!h.is.bound()},hidden:function(){return!S.is(":visible")},bound:function(){return S.hasClass(b.bound)},fixed:function(){return S.hasClass(b.fixed)}},stick:function(e){var t=e||k.scrollTop(),o=h.cache,n=o.fits,i=o.element,s=o.window,r=o.context,c=h.is.bottom()&&g.pushing?g.bottomOffset:g.offset,e={top:t+c,bottom:t+c+s.height},l=(h.get.direction(e.top),n?0:h.get.elementScroll(e.top)),a=!n,m=0!==i.height;m&&(h.is.initialPosition()?e.top>r.bottom?(h.debug("Element bottom of container"),h.bindBottom()):e.top>i.top&&(h.debug("Element passed, fixing element to page"),i.height+e.top-l>r.bottom?h.bindBottom():h.fixTop()):h.is.fixed()?h.is.top()?e.topr.bottom?(h.debug("Fixed element reached bottom of container"),h.bindBottom()):a&&(h.set.scroll(l),h.save.lastScroll(e.top),h.save.elementScroll(l)):h.is.bottom()&&(e.bottom-i.heightr.bottom?(h.debug("Bottom fixed rail has reached bottom of container"),h.bindBottom()):a&&(h.set.scroll(l),h.save.lastScroll(e.top),h.save.elementScroll(l))):h.is.bottom()&&(g.pushing?h.is.bound()&&e.bottom0&&(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,s){var r,c,l,a=w;return o=o||f,s=z||s,"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(s,o):c!==n&&(l=c),e.isArray(i)?i.push(l):i!==n?i=[i,l]:l!==n&&(i=l),c}},m?(w===n&&h.initialize(),h.invoke(a)):(w!==n&&w.invoke("destroy"),h.initialize())}),i!==n?i:this},e.fn.sticky.settings={name:"Sticky",namespace:"sticky",debug:!1,verbose:!0,performance:!0,pushing:!1,context:!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",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