onscrolling
Advanced tools
Comparing version 0.3.1 to 0.3.2
@@ -9,6 +9,18 @@ (function (global, factory) { | ||
var requestFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame, | ||
isSupported = requestFrame !== undefined, | ||
// Figure out proper requestAnimationFrame | ||
var requestFrame = window.requestAnimationFrame, | ||
cancelFrame = window.cancelAnimationFrame, | ||
vendors = ['ms', 'moz', 'webkit', 'o']; | ||
for (var i = 0; i < vendors.length && !requestFrame; i++) { | ||
requestFrame = window[vendors[i] + 'RequestAnimationFrame']; | ||
cancelFrame = window[vendors[i] + 'CancelAnimationFrame'] || | ||
window[vendors[i] + 'CancelRequestAnimationFrame']; | ||
} | ||
// Module state | ||
var isSupported = requestFrame !== undefined, | ||
isListening = false, | ||
isQueued = false, | ||
isIdle = true, | ||
scrollY = window.pageYOffset, | ||
@@ -19,3 +31,2 @@ scrollX = window.pageXOffset, | ||
directionX = ['x', 'horizontal'], | ||
// directionY = [ 'y', 'vertical'], | ||
directionAll = ['any'], | ||
@@ -26,43 +37,105 @@ callbackQueue = { | ||
any : [] | ||
}; | ||
}, | ||
detectIdleTimeout, | ||
tickId; | ||
// Main scroll handler | ||
// ------------------- | ||
function handleScroll() { | ||
var i; | ||
var isScrollChanged = false; | ||
if (callbackQueue.x.length || callbackQueue.any.length) { | ||
scrollX = window.pageXOffset; | ||
} | ||
if (callbackQueue.y.length || callbackQueue.any.length) { | ||
scrollY = window.pageYOffset; | ||
} | ||
if (scrollY !== scrollYCached) { | ||
for (i = 0; i < callbackQueue.y.length; i++) { | ||
callbackQueue.y[i](scrollY); | ||
} | ||
callbackQueue.y.forEach(triggerCallback.y); | ||
scrollYCached = scrollY; | ||
isScrollChanged = true; | ||
} | ||
if (scrollX !== scrollXCached) { | ||
for (i = 0; i < callbackQueue.x.length; i++) { | ||
callbackQueue.x[i](scrollX); | ||
} | ||
callbackQueue.x.forEach(triggerCallback.x); | ||
scrollXCached = scrollX; | ||
isScrollChanged = true; | ||
} | ||
for (i = 0; i < callbackQueue.any.length; i++) { | ||
callbackQueue.any[i]([scrollX, scrollY]); | ||
if (isScrollChanged) { | ||
callbackQueue.any.forEach(triggerCallback.any); | ||
window.clearTimeout(detectIdleTimeout); | ||
detectIdleTimeout = null; | ||
} | ||
isQueued = false; | ||
requestTick(); | ||
} | ||
function requestTick() { | ||
if (!isQueued) { | ||
requestFrame(handleScroll); | ||
} | ||
isQueued = true; | ||
// Utilities | ||
// --------- | ||
function triggerCallback(callback, scroll) { | ||
callback(scroll); | ||
} | ||
triggerCallback.y = function(callback) { | ||
triggerCallback(callback, scrollY); | ||
}; | ||
triggerCallback.x = function(callback) { | ||
triggerCallback(callback, scrollX); | ||
}; | ||
triggerCallback.any = function(callback) { | ||
triggerCallback(callback, [scrollX, scrollY]); | ||
}; | ||
function onScrollDebouncer() { | ||
if (callbackQueue.x.length || callbackQueue.any.length) { | ||
scrollX = window.pageXOffset; | ||
function enableScrollListener() { | ||
if (isListening || isQueued) { | ||
return; | ||
} | ||
if (callbackQueue.y.length || callbackQueue.any.length) { | ||
scrollY = window.pageYOffset; | ||
if (isIdle) { | ||
window.addEventListener('scroll', onScrollDebouncer); | ||
document.body.addEventListener('touchmove', onScrollDebouncer); | ||
isListening = true; | ||
return; | ||
} | ||
requestTick(); | ||
} | ||
function disableScrollListener() { | ||
if (!isListening) { | ||
return; | ||
} | ||
window.removeEventListener('scroll', onScrollDebouncer); | ||
document.body.removeEventListener('touchmove', onScrollDebouncer); | ||
isListening = false; | ||
} | ||
function onScrollDebouncer() { | ||
isIdle = false; | ||
requestTick(); | ||
disableScrollListener(); | ||
} | ||
function requestTick() { | ||
if (isQueued) { | ||
return; | ||
} | ||
if (!detectIdleTimeout) { | ||
// Idle is defined as 1.5 seconds without scroll change | ||
detectIdleTimeout = window.setTimeout(detectIdle, 1500); | ||
} | ||
tickId = requestFrame(handleScroll); | ||
isQueued = true; | ||
} | ||
function cancelTick() { | ||
if (!isQueued) { | ||
return; | ||
} | ||
cancelFrame(tickId); | ||
isQueued = false; | ||
} | ||
function detectIdle() { | ||
isIdle = true; | ||
enableScrollListener(); | ||
} | ||
/** | ||
@@ -83,7 +156,3 @@ * Attach callback to debounced scroll event | ||
} | ||
if (!isListening) { | ||
window.addEventListener('scroll', onScrollDebouncer); | ||
document.body.addEventListener('touchmove', onScrollDebouncer); | ||
isListening = true; | ||
} | ||
enableScrollListener(); | ||
// Verify parameters | ||
@@ -129,2 +198,7 @@ if (typeof direction === 'function') { | ||
} | ||
// If there's no listeners left, disable listening | ||
if (!callbackQueue.x.length && !callbackQueue.y.length && !callbackQueue.any.length) { | ||
cancelTick(); | ||
disableScrollListener(); | ||
} | ||
}; | ||
@@ -131,0 +205,0 @@ onscrolling.off = onscrolling.remove; |
{ | ||
"name": "onscrolling", | ||
"version": "0.3.1", | ||
"version": "0.3.2", | ||
"description": "A better, smoother, more performant window.onscroll event interface using requestAnimationFrame for performance and mobile-compatibility", | ||
"main": "dist/onscrolling.js", | ||
"jsnext:main": "src/onscrolling.js", | ||
"scripts": { | ||
@@ -10,3 +11,3 @@ "test": "npm run build && npm run lint-tests && mocha-phantomjs ./test/index.html", | ||
"lint-src": "jshint src/onscrolling.js", | ||
"lint-tests": "jshint test/onscroll-test.js", | ||
"lint-tests": "jshint test/onscroll-test.js && jshint --extract=auto test/index.html", | ||
"build": "npm run lint-src && esperanto --type umd --name onscrolling -i src/onscrolling.js -o dist/onscrolling.js", | ||
@@ -13,0 +14,0 @@ "build-babel": "babel --modules umd src/onscrolling.js -o dist/onscrolling.js" |
'use strict'; | ||
var requestFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame, | ||
isSupported = requestFrame !== undefined, | ||
// Get proper requestAnimationFrame | ||
var requestFrame = window.requestAnimationFrame, | ||
cancelFrame = window.cancelAnimationFrame; | ||
if (!requestFrame) { | ||
['ms', 'moz', 'webkit', 'o'].every(function(prefix) { | ||
requestFrame = window[prefix + 'RequestAnimationFrame']; | ||
cancelFrame = window[prefix + 'CancelAnimationFrame'] || | ||
window[prefix + 'CancelRequestAnimationFrame']; | ||
// Continue iterating only if requestFrame is still false | ||
return !requestFrame; | ||
}); | ||
} | ||
// Module state | ||
var isSupported = !!requestFrame, | ||
isListening = false, | ||
isQueued = false, | ||
isIdle = true, | ||
scrollY = window.pageYOffset, | ||
@@ -12,3 +27,2 @@ scrollX = window.pageXOffset, | ||
directionX = ['x', 'horizontal'], | ||
// directionY = [ 'y', 'vertical'], | ||
directionAll = ['any'], | ||
@@ -19,43 +33,106 @@ callbackQueue = { | ||
any : [] | ||
}; | ||
}, | ||
detectIdleTimeout, | ||
tickId; | ||
// Main scroll handler | ||
// ------------------- | ||
function handleScroll() { | ||
var i; | ||
var isScrollChanged = false; | ||
if (callbackQueue.x.length || callbackQueue.any.length) { | ||
scrollX = window.pageXOffset; | ||
} | ||
if (callbackQueue.y.length || callbackQueue.any.length) { | ||
scrollY = window.pageYOffset; | ||
} | ||
if (scrollY !== scrollYCached) { | ||
for (i = 0; i < callbackQueue.y.length; i++) { | ||
callbackQueue.y[i](scrollY); | ||
} | ||
callbackQueue.y.forEach(triggerCallback.y); | ||
scrollYCached = scrollY; | ||
isScrollChanged = true; | ||
} | ||
if (scrollX !== scrollXCached) { | ||
for (i = 0; i < callbackQueue.x.length; i++) { | ||
callbackQueue.x[i](scrollX); | ||
} | ||
callbackQueue.x.forEach(triggerCallback.x); | ||
scrollXCached = scrollX; | ||
isScrollChanged = true; | ||
} | ||
for (i = 0; i < callbackQueue.any.length; i++) { | ||
callbackQueue.any[i]([scrollX, scrollY]); | ||
if (isScrollChanged) { | ||
callbackQueue.any.forEach(triggerCallback.any); | ||
window.clearTimeout(detectIdleTimeout); | ||
detectIdleTimeout = null; | ||
} | ||
isQueued = false; | ||
requestTick(); | ||
} | ||
function requestTick() { | ||
if (!isQueued) { | ||
requestFrame(handleScroll); | ||
} | ||
isQueued = true; | ||
// Utilities | ||
// --------- | ||
function triggerCallback(callback, scroll) { | ||
callback(scroll); | ||
} | ||
triggerCallback.y = function(callback) { | ||
triggerCallback(callback, scrollY); | ||
}; | ||
triggerCallback.x = function(callback) { | ||
triggerCallback(callback, scrollX); | ||
}; | ||
triggerCallback.any = function(callback) { | ||
triggerCallback(callback, [scrollX, scrollY]); | ||
}; | ||
function onScrollDebouncer() { | ||
if (callbackQueue.x.length || callbackQueue.any.length) { | ||
scrollX = window.pageXOffset; | ||
function enableScrollListener() { | ||
if (isListening || isQueued) { | ||
return; | ||
} | ||
if (callbackQueue.y.length || callbackQueue.any.length) { | ||
scrollY = window.pageYOffset; | ||
if (isIdle) { | ||
isListening = true; | ||
window.addEventListener('scroll', onScrollDebouncer); | ||
document.body.addEventListener('touchmove', onScrollDebouncer); | ||
return; | ||
} | ||
requestTick(); | ||
} | ||
function disableScrollListener() { | ||
if (!isListening) { | ||
return; | ||
} | ||
window.removeEventListener('scroll', onScrollDebouncer); | ||
document.body.removeEventListener('touchmove', onScrollDebouncer); | ||
isListening = false; | ||
} | ||
function onScrollDebouncer() { | ||
isIdle = false; | ||
requestTick(); | ||
disableScrollListener(); | ||
} | ||
function requestTick() { | ||
if (isQueued) { | ||
return; | ||
} | ||
if (!detectIdleTimeout) { | ||
// Idle is defined as 1.5 seconds without scroll change | ||
detectIdleTimeout = window.setTimeout(detectIdle, 1500); | ||
} | ||
tickId = requestFrame(handleScroll); | ||
isQueued = true; | ||
} | ||
function cancelTick() { | ||
if (!isQueued) { | ||
return; | ||
} | ||
cancelFrame(tickId); | ||
isQueued = false; | ||
} | ||
function detectIdle() { | ||
isIdle = true; | ||
cancelTick(); | ||
enableScrollListener(); | ||
} | ||
/** | ||
@@ -76,7 +153,3 @@ * Attach callback to debounced scroll event | ||
} | ||
if (!isListening) { | ||
window.addEventListener('scroll', onScrollDebouncer); | ||
document.body.addEventListener('touchmove', onScrollDebouncer); | ||
isListening = true; | ||
} | ||
enableScrollListener(); | ||
// Verify parameters | ||
@@ -122,2 +195,7 @@ if (typeof direction === 'function') { | ||
} | ||
// If there's no listeners left, disable listening | ||
if (!callbackQueue.x.length && !callbackQueue.y.length && !callbackQueue.any.length) { | ||
cancelTick(); | ||
disableScrollListener(); | ||
} | ||
}; | ||
@@ -124,0 +202,0 @@ onscrolling.off = onscrolling.remove; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
33421
612