|
|
@ -62,9 +62,6 @@ $.fn.sticky = function(parameters) { |
|
|
|
module = { |
|
|
|
|
|
|
|
initialize: function() { |
|
|
|
if( !$module.is(':visible') ) { |
|
|
|
module.error(error.visible, $module); |
|
|
|
} |
|
|
|
if(settings.context) { |
|
|
|
$context = $(settings.context); |
|
|
|
} |
|
|
@ -75,17 +72,26 @@ $.fn.sticky = function(parameters) { |
|
|
|
module.error(error.invalidContext, settings.context, $module); |
|
|
|
return; |
|
|
|
} |
|
|
|
if(module.supports.sticky()) { |
|
|
|
// needs to enable native ios support
|
|
|
|
module.verbose('Initializing sticky', settings, $container); |
|
|
|
module.save.positions(); |
|
|
|
|
|
|
|
// error conditions
|
|
|
|
if( module.is.hidden() ) { |
|
|
|
module.error(error.visible, $module); |
|
|
|
} |
|
|
|
if(module.cache.element.height > module.cache.context.height) { |
|
|
|
module.reset(); |
|
|
|
module.error(error.elementSize, $module); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
$window |
|
|
|
.on('resize' + eventNamespace, module.event.resize) |
|
|
|
; |
|
|
|
$scroll |
|
|
|
.on('scroll' + eventNamespace, module.event.scroll) |
|
|
|
; |
|
|
|
module.verbose('Initializing sticky', settings, $container); |
|
|
|
module.save.positions(); |
|
|
|
|
|
|
|
module.observeChanges(); |
|
|
|
module.instantiate(); |
|
|
|
}, |
|
|
@ -102,8 +108,10 @@ $.fn.sticky = function(parameters) { |
|
|
|
module.verbose('Destroying previous module'); |
|
|
|
module.reset(); |
|
|
|
$window |
|
|
|
.off('resize', module.event.resize) |
|
|
|
.off('scroll', module.event.scroll) |
|
|
|
.off('resize' + eventNamespace, module.event.resize) |
|
|
|
; |
|
|
|
$scroll |
|
|
|
.off('scroll' + eventNamespace, module.event.scroll) |
|
|
|
; |
|
|
|
$module |
|
|
|
.removeData(moduleNamespace) |
|
|
@ -192,7 +200,7 @@ $.fn.sticky = function(parameters) { |
|
|
|
} |
|
|
|
; |
|
|
|
module.cache = { |
|
|
|
fits : ( element.height < $window.height() ), |
|
|
|
fits : ( element.height < window.height ), |
|
|
|
window: { |
|
|
|
height: window.height |
|
|
|
}, |
|
|
@ -233,30 +241,53 @@ $.fn.sticky = function(parameters) { |
|
|
|
} |
|
|
|
return direction; |
|
|
|
}, |
|
|
|
currentOffset: function() { |
|
|
|
return ( module.is.top() ) |
|
|
|
? parseInt($module.css('top'), 10) || 0 |
|
|
|
: parseInt($module.css('bottom'), 10) || 0 |
|
|
|
; |
|
|
|
}, |
|
|
|
offsetChange: function(scroll) { |
|
|
|
scrollChange: function(scroll) { |
|
|
|
scroll = scroll || $scroll.scrollTop(); |
|
|
|
return (module.lastScroll) |
|
|
|
? Math.abs(scroll - module.lastScroll) |
|
|
|
? (scroll - module.lastScroll) |
|
|
|
: 0 |
|
|
|
; |
|
|
|
}, |
|
|
|
newOffset: function(scroll) { |
|
|
|
currentElementScroll: function() { |
|
|
|
return ( module.is.top() ) |
|
|
|
? Math.abs(parseInt($module.css('top'), 10)) || 0 |
|
|
|
: Math.abs(parseInt($module.css('bottom'), 10)) || 0 |
|
|
|
; |
|
|
|
}, |
|
|
|
elementScroll: function(scroll) { |
|
|
|
scroll = scroll || $scroll.scrollTop(); |
|
|
|
var |
|
|
|
currentOffset = module.get.currentOffset(), |
|
|
|
delta = module.get.offsetChange(scroll) |
|
|
|
element = module.cache.element, |
|
|
|
window = module.cache.window, |
|
|
|
delta = module.get.scrollChange(scroll), |
|
|
|
maxScroll = (element.height - window.height + settings.offset), |
|
|
|
currentScroll = module.get.currentElementScroll(), |
|
|
|
possibleScroll = (currentScroll + delta), |
|
|
|
elementScroll |
|
|
|
; |
|
|
|
return Math.abs(currentOffset - delta); |
|
|
|
if(possibleScroll < 0) { |
|
|
|
elementScroll = 0; |
|
|
|
} |
|
|
|
else if (possibleScroll > maxScroll ) { |
|
|
|
elementScroll = maxScroll; |
|
|
|
} |
|
|
|
else { |
|
|
|
elementScroll = possibleScroll; |
|
|
|
} |
|
|
|
return elementScroll; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
remove: { |
|
|
|
offset: function() { |
|
|
|
$module.css('margin-top', ''); |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
set: { |
|
|
|
offset: function() { |
|
|
|
$module.css('margin-top', settings.offset); |
|
|
|
}, |
|
|
|
containerSize: function() { |
|
|
|
var |
|
|
|
tagName = $container.get(0).tagName |
|
|
@ -270,6 +301,18 @@ $.fn.sticky = function(parameters) { |
|
|
|
$container.height(module.cache.context.height); |
|
|
|
} |
|
|
|
}, |
|
|
|
scroll: function(scroll) { |
|
|
|
if( module.is.top() ) { |
|
|
|
$module |
|
|
|
.css('top', -scroll) |
|
|
|
; |
|
|
|
} |
|
|
|
if( module.is.bottom() ) { |
|
|
|
$module |
|
|
|
.css('bottom', scroll) |
|
|
|
; |
|
|
|
} |
|
|
|
}, |
|
|
|
size: function() { |
|
|
|
if(module.cache.element.height !== 0 && module.cache.element.width !== 0) { |
|
|
|
$module |
|
|
@ -289,6 +332,12 @@ $.fn.sticky = function(parameters) { |
|
|
|
bottom: function() { |
|
|
|
return $module.hasClass(className.bottom); |
|
|
|
}, |
|
|
|
initialPosition: function() { |
|
|
|
return (!module.is.fixed() && !module.is.bound()); |
|
|
|
}, |
|
|
|
hidden: function() { |
|
|
|
return (!$module.is(':visible')); |
|
|
|
}, |
|
|
|
bound: function() { |
|
|
|
return $module.hasClass(className.bound); |
|
|
|
}, |
|
|
@ -304,114 +353,77 @@ $.fn.sticky = function(parameters) { |
|
|
|
element = cache.element, |
|
|
|
window = cache.window, |
|
|
|
context = cache.context, |
|
|
|
scrollTop = $scroll.scrollTop(), |
|
|
|
screen = { |
|
|
|
top : scrollTop + settings.offset, |
|
|
|
bottom : scrollTop + window.height + settings.offset |
|
|
|
scrollTop = $scroll.scrollTop() + settings.offset, |
|
|
|
scroll = { |
|
|
|
top : scrollTop, |
|
|
|
bottom : scrollTop + window.height |
|
|
|
}, |
|
|
|
direction = module.get.direction(scrollTop), |
|
|
|
currentOffset = module.get.currentOffset(), |
|
|
|
newOffset = module.get.newOffset(scrollTop), |
|
|
|
elementPassed = (screen.bottom > element.top + element.height), |
|
|
|
fixedBottom = (cache.element.height + screen.top) |
|
|
|
elementScroll = module.get.elementScroll(scrollTop), |
|
|
|
|
|
|
|
// shorthand
|
|
|
|
doesntFit = !fits, |
|
|
|
elementVisible = (element.height !== 0) |
|
|
|
; |
|
|
|
|
|
|
|
// save current scroll for next run
|
|
|
|
module.save.scroll(scrollTop); |
|
|
|
if(element.height !== 0) { |
|
|
|
|
|
|
|
if( module.is.fixed() ) { |
|
|
|
if(fits) { |
|
|
|
// if module is fixed top
|
|
|
|
if(module.is.top()) { |
|
|
|
if( screen.top < element.top ) { |
|
|
|
module.unfix(); |
|
|
|
} |
|
|
|
else if( fixedBottom > context.bottom ) { |
|
|
|
module.debug('Top attached rail has reached bottom of container'); |
|
|
|
module.bindBottom(); |
|
|
|
} |
|
|
|
} |
|
|
|
// if module is fixed bottom
|
|
|
|
if(module.is.bottom() ) { |
|
|
|
// top edge
|
|
|
|
if( (screen.bottom - element.height) < element.top) { |
|
|
|
module.unfix(); |
|
|
|
} |
|
|
|
// bottom edge
|
|
|
|
else if(screen.bottom > context.bottom) { |
|
|
|
module.debug('Bottom attached rail has reached bottom of container'); |
|
|
|
module.bindBottom(); |
|
|
|
} |
|
|
|
|
|
|
|
if(elementVisible) { |
|
|
|
|
|
|
|
if( module.is.initialPosition() ) { |
|
|
|
if(scroll.top >= element.top) { |
|
|
|
module.debug('Element passed, fixing element to page'); |
|
|
|
module.fixTop(); |
|
|
|
} |
|
|
|
} |
|
|
|
else if( module.is.fixed() ) { |
|
|
|
|
|
|
|
// currently fixed top
|
|
|
|
if( module.is.top() ) { |
|
|
|
|
|
|
|
if( scroll.top < element.top ) { |
|
|
|
module.debug('Fixed element reached top of container'); |
|
|
|
module.setInitialPosition(); |
|
|
|
} |
|
|
|
if( fixedBottom > context.bottom ) { |
|
|
|
else if( (element.height + scroll.top) > context.bottom ) { |
|
|
|
module.debug('Fixed element reached bottom of container'); |
|
|
|
module.bindBottom(); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
if(screen.bottom > context.bottom) { |
|
|
|
module.bindBottom(); |
|
|
|
} |
|
|
|
else if(elementPassed) { |
|
|
|
if(module.is.top() && direction == 'down') { |
|
|
|
module.debug('Stuck content at bottom edge'); |
|
|
|
if(newOffset >= (element.height - window.height)) { |
|
|
|
$module |
|
|
|
.css('top', '') |
|
|
|
; |
|
|
|
module.stickBottom(); |
|
|
|
} |
|
|
|
else { |
|
|
|
$module |
|
|
|
.css('top', -newOffset) |
|
|
|
; |
|
|
|
} |
|
|
|
} |
|
|
|
if(module.is.bottom() && direction == 'up') { |
|
|
|
module.debug('Stuck content at top edge'); |
|
|
|
if(newOffset >= (element.height - window.height)) { |
|
|
|
$module |
|
|
|
.css('bottom', '') |
|
|
|
; |
|
|
|
module.stickTop(); |
|
|
|
} |
|
|
|
else { |
|
|
|
$module |
|
|
|
.css('bottom', -newOffset) |
|
|
|
; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// currently fixed bottom
|
|
|
|
if(module.is.bottom() ) { |
|
|
|
|
|
|
|
// top edge
|
|
|
|
if( (scroll.bottom - element.height) < element.top) { |
|
|
|
module.setInitialPosition(); |
|
|
|
} |
|
|
|
else { |
|
|
|
module.unfix(); |
|
|
|
// bottom edge
|
|
|
|
else if(scroll.bottom > context.bottom) { |
|
|
|
module.debug('Bottom attached rail has reached bottom of container'); |
|
|
|
module.bindBottom(); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
// determine if needs to be bound
|
|
|
|
if(screen.top + element.height > context.bottom) { |
|
|
|
module.bindBottom(); |
|
|
|
|
|
|
|
// scroll element if larger than screen
|
|
|
|
if(doesntFit) { |
|
|
|
module.set.scroll(elementScroll); |
|
|
|
} |
|
|
|
if(fits) { |
|
|
|
// fix to bottom of screen on way back up
|
|
|
|
if(module.is.bottom() ) { |
|
|
|
if(settings.pushing) { |
|
|
|
if(module.is.bound() && screen.bottom < context.bottom ) { |
|
|
|
module.stickBottom(); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
if(module.is.bound() && screen.top < context.bottom - element.height) { |
|
|
|
module.stickTop(); |
|
|
|
} |
|
|
|
} |
|
|
|
else if( module.is.bottom() ) { |
|
|
|
// fix to bottom of screen on way back up
|
|
|
|
if( module.is.bottom() ) { |
|
|
|
if(settings.pushing) { |
|
|
|
if(module.is.bound() && scroll.bottom < context.bottom ) { |
|
|
|
module.fixBottom(); |
|
|
|
} |
|
|
|
} |
|
|
|
else if(screen.top >= element.top && screen.top < context.bottom - element.height) { |
|
|
|
module.stickTop(); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
if(elementPassed && screen.bottom < context.bottom ) { |
|
|
|
module.stickBottom(); |
|
|
|
else { |
|
|
|
if(module.is.bound() && (scroll.top < context.bottom - element.height) ) { |
|
|
|
module.fixTop(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -420,6 +432,7 @@ $.fn.sticky = function(parameters) { |
|
|
|
|
|
|
|
bindTop: function() { |
|
|
|
module.debug('Binding element to top of parent container'); |
|
|
|
module.remove.offset(); |
|
|
|
$module |
|
|
|
.css('left' , '') |
|
|
|
.removeClass(className.fixed) |
|
|
@ -432,6 +445,7 @@ $.fn.sticky = function(parameters) { |
|
|
|
}, |
|
|
|
bindBottom: function() { |
|
|
|
module.debug('Binding element to bottom of parent container'); |
|
|
|
module.remove.offset(); |
|
|
|
$module |
|
|
|
.css('left' , '') |
|
|
|
.removeClass(className.fixed) |
|
|
@ -443,8 +457,15 @@ $.fn.sticky = function(parameters) { |
|
|
|
$.proxy(settings.onUnstick, element)(); |
|
|
|
}, |
|
|
|
|
|
|
|
stickTop: function() { |
|
|
|
setInitialPosition: function() { |
|
|
|
module.unfix(); |
|
|
|
module.unbind(); |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
fixTop: function() { |
|
|
|
module.debug('Fixing element to top of page'); |
|
|
|
module.set.offset(); |
|
|
|
$module |
|
|
|
.css('left', module.cache.element.left) |
|
|
|
.removeClass(className.bound) |
|
|
@ -455,8 +476,9 @@ $.fn.sticky = function(parameters) { |
|
|
|
$.proxy(settings.onStick, element)(); |
|
|
|
}, |
|
|
|
|
|
|
|
stickBottom: function() { |
|
|
|
fixBottom: function() { |
|
|
|
module.debug('Sticking element to bottom of page'); |
|
|
|
module.set.offset(); |
|
|
|
$module |
|
|
|
.css('left', module.cache.element.left) |
|
|
|
.removeClass(className.bound) |
|
|
@ -469,6 +491,7 @@ $.fn.sticky = function(parameters) { |
|
|
|
|
|
|
|
unbind: function() { |
|
|
|
module.debug('Removing absolute position on element'); |
|
|
|
module.remove.offset(); |
|
|
|
$module |
|
|
|
.removeClass(className.bound) |
|
|
|
.removeClass(className.top) |
|
|
@ -478,6 +501,7 @@ $.fn.sticky = function(parameters) { |
|
|
|
|
|
|
|
unfix: function() { |
|
|
|
module.debug('Removing fixed position on element'); |
|
|
|
module.remove.offset(); |
|
|
|
$module |
|
|
|
.removeClass(className.fixed) |
|
|
|
.removeClass(className.top) |
|
|
@ -689,9 +713,9 @@ $.fn.sticky.settings = { |
|
|
|
name : 'Sticky', |
|
|
|
namespace : 'sticky', |
|
|
|
|
|
|
|
verbose : false, |
|
|
|
debug : false, |
|
|
|
performance : false, |
|
|
|
verbose : true, |
|
|
|
debug : true, |
|
|
|
performance : true, |
|
|
|
|
|
|
|
pushing : false, |
|
|
|
|
|
|
@ -710,7 +734,8 @@ $.fn.sticky.settings = { |
|
|
|
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' |
|
|
|
invalidContext : 'Context specified does not exist', |
|
|
|
elementSize : 'Sticky element is larger than its container, cannot create sticky.' |
|
|
|
}, |
|
|
|
|
|
|
|
className : { |
|
|
|