Comparing version 2.0.1 to 3.0.0
{ | ||
"name": "optiscroll", | ||
"version": "2.0.1", | ||
"homepage": "https://github.com/wilsonfletcher/Optiscroll", | ||
"version": "3.0.0", | ||
"homepage": "https://github.com/albertogasparin/Optiscroll", | ||
"authors": [ | ||
@@ -6,0 +6,0 @@ "Alberto Gasparin <albertogasparin@gmail.com>" |
/*! | ||
* Optiscroll.js v2.0.1 | ||
* Optiscroll.js v3.0.0 | ||
* https://github.com/wilsonfletcher/Optiscroll/ | ||
* by Alberto Gasparin | ||
* | ||
* @copyright 2016 Wilson Fletcher | ||
* @copyright 2017 Alberto Gasparin | ||
* @license Released under MIT LICENSE | ||
@@ -13,47 +12,3 @@ */ | ||
/* | ||
* CustomEvent polyfill for IE9 | ||
* By MDN | ||
* https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent | ||
* MIT LICENSE | ||
*/ | ||
typeof window.CustomEvent === 'function' || (function (window) { | ||
function CustomEvent (event, params) { | ||
params = params || { bubbles: false, cancelable: false, detail: undefined }; | ||
var evt = document.createEvent('CustomEvent'); | ||
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); | ||
return evt; | ||
} | ||
CustomEvent.prototype = window.Event.prototype; | ||
window.CustomEvent = CustomEvent; | ||
})(window); | ||
// Adaped from https://github.com/darius/requestAnimationFrame | ||
// requestAnimationFrame polyfill by Erik Möller. | ||
// MIT license | ||
window.requestAnimationFrame || (function(window) { | ||
var lastTime = 0; | ||
window.requestAnimationFrame = function(callback) { | ||
var now = Date.now(); | ||
var nextTime = Math.max(lastTime + 16, now); | ||
return setTimeout(function() { | ||
callback(lastTime = nextTime); | ||
}, nextTime - now); | ||
}; | ||
window.cancelAnimationFrame = clearTimeout; | ||
}(window)); | ||
/** | ||
@@ -86,2 +41,4 @@ * Optiscroll, use this to create instances | ||
classPrefix: 'optiscroll-', | ||
wrapContent: true, | ||
rtl: false, | ||
}; | ||
@@ -92,10 +49,11 @@ | ||
Optiscroll.Instance = function (element, options) { | ||
var me = this; | ||
// instance variables | ||
me.element = element; | ||
me.settings = _extend(_extend({}, Optiscroll.defaults), options || {}); | ||
me.cache = {}; | ||
this.element = element; | ||
this.settings = _extend(_extend({}, Optiscroll.defaults), options || {}); | ||
if (typeof options.rtl !== 'boolean') { | ||
this.settings.rtl = window.getComputedStyle(element).direction === 'rtl'; | ||
} | ||
this.cache = {}; | ||
me.init(); | ||
this.init(); | ||
}; | ||
@@ -109,37 +67,41 @@ | ||
init: function () { | ||
var me = this, | ||
settings = me.settings, | ||
var element = this.element, | ||
settings = this.settings, | ||
shouldCreateScrollbars = false; | ||
var scrollEl = this.scrollEl = settings.wrapContent | ||
? Utils.createWrapper(element) | ||
: element.firstElementChild; | ||
me.scrollEl = Utils.createWrapper(me.element, settings.classPrefix + 'content'); | ||
toggleClass(me.element, 'is-enabled', true); | ||
toggleClass(scrollEl, settings.classPrefix + 'content', true); | ||
toggleClass(element, 'is-enabled' + (settings.rtl ? ' is-rtl' : ''), true); | ||
// initialize scrollbars | ||
me.scrollbars = { | ||
v: Scrollbar('v', me), | ||
h: Scrollbar('h', me), | ||
this.scrollbars = { | ||
v: Scrollbar('v', this), | ||
h: Scrollbar('h', this), | ||
}; | ||
// create DOM scrollbars only if they have size or if it's forced | ||
if(G.nativeScrollbarSize || settings.forceScrollbars) { | ||
shouldCreateScrollbars = Utils.hideNativeScrollbars(me.scrollEl); | ||
if(G.scrollbarSpec.width || settings.forceScrollbars) { | ||
shouldCreateScrollbars = Utils.hideNativeScrollbars(scrollEl, settings.rtl); | ||
} | ||
if(shouldCreateScrollbars) { | ||
_invoke(me.scrollbars, 'create'); | ||
_invoke(this.scrollbars, 'create'); | ||
} | ||
if(G.isTouch && settings.preventParentScroll) { | ||
toggleClass(me.element, settings.classPrefix + 'prevent', true); | ||
toggleClass(element, settings.classPrefix + 'prevent', true); | ||
} | ||
// calculate scrollbars | ||
me.update(); | ||
this.update(); | ||
// bind container events | ||
me.bind(); | ||
this.bind(); | ||
// add instance to global array for timed check | ||
if(settings.autoUpdate) { | ||
G.instances.push(me); | ||
G.instances.push(this); | ||
} | ||
@@ -157,21 +119,18 @@ | ||
bind: function () { | ||
var me = this, | ||
listeners = me.listeners = {}, | ||
scrollEl = me.scrollEl; | ||
var listeners = this.listeners = {}, | ||
scrollEl = this.scrollEl; | ||
// scroll event binding | ||
listeners.scroll = _throttle(function (ev) { | ||
Events.scroll(ev, me); | ||
}, GS.scrollMinUpdateInterval); | ||
listeners.scroll = _throttle(Events.scroll.bind(this), GS.scrollMinUpdateInterval); | ||
if(G.isTouch) { | ||
listeners.touchstart = function (ev) { Events.touchstart(ev, me); }; | ||
listeners.touchend = function (ev) { Events.touchend(ev, me); }; | ||
listeners.touchstart = Events.touchstart.bind(this); | ||
listeners.touchend = Events.touchend.bind(this); | ||
} | ||
// Safari does not support wheel event | ||
listeners.mousewheel = listeners.wheel = function (ev) { Events.wheel(ev, me); }; | ||
listeners.mousewheel = listeners.wheel = Events.wheel.bind(this); | ||
for (var ev in listeners) { | ||
scrollEl.addEventListener(ev, listeners[ev]); | ||
scrollEl.addEventListener(ev, listeners[ev], G.passiveEvent); | ||
} | ||
@@ -185,6 +144,5 @@ | ||
update: function () { | ||
var me = this, | ||
oldcH = me.cache.clientH, | ||
scrollEl = me.scrollEl, | ||
cache = me.cache, | ||
var scrollEl = this.scrollEl, | ||
cache = this.cache, | ||
oldcH = cache.clientH, | ||
sH = scrollEl.scrollHeight, | ||
@@ -207,8 +165,8 @@ cH = scrollEl.clientHeight, | ||
// if the element is no more in the DOM | ||
if(sH === 0 && cH === 0 && !Utils.containsNode(document.body, me.element)) { | ||
me.destroy(); | ||
if(sH === 0 && cH === 0 && !document.body.contains(this.element)) { | ||
this.destroy(); | ||
return false; | ||
} | ||
me.fireCustomEvent('sizechange'); | ||
this.fireCustomEvent('sizechange'); | ||
} | ||
@@ -218,3 +176,3 @@ | ||
// and check if bottom is reached | ||
_invoke(me.scrollbars, 'update'); | ||
_invoke(this.scrollbars, 'update'); | ||
} | ||
@@ -230,4 +188,3 @@ }, | ||
scrollTo: function (destX, destY, duration) { | ||
var me = this, | ||
cache = me.cache, | ||
var cache = this.cache, | ||
startX, startY, endX, endY; | ||
@@ -237,6 +194,6 @@ | ||
// force update | ||
me.update(); | ||
this.update(); | ||
startX = me.scrollEl.scrollLeft; | ||
startY = me.scrollEl.scrollTop; | ||
startX = this.scrollEl.scrollLeft; | ||
startY = this.scrollEl.scrollTop; | ||
@@ -254,3 +211,3 @@ endX = +destX; | ||
// animate | ||
me.animateScroll(startX, endX, startY, endY, +duration); | ||
this.animateScroll(startX, endX, startY, endY, +duration); | ||
@@ -262,4 +219,3 @@ }, | ||
scrollIntoView: function (elem, duration, delta) { | ||
var me = this, | ||
scrollEl = me.scrollEl, | ||
var scrollEl = this.scrollEl, | ||
eDim, sDim, | ||
@@ -272,3 +228,3 @@ leftEdge, topEdge, rightEdge, bottomEdge, | ||
// force update | ||
me.update(); | ||
this.update(); | ||
@@ -296,4 +252,4 @@ if(typeof elem === 'string') { // selector | ||
topEdge = offsetY - (delta.top || 0); | ||
rightEdge = offsetX + eDim.width - me.cache.clientW + (delta.right || 0); | ||
bottomEdge = offsetY + eDim.height - me.cache.clientH + (delta.bottom || 0); | ||
rightEdge = offsetX + eDim.width - this.cache.clientW + (delta.right || 0); | ||
bottomEdge = offsetY + eDim.height - this.cache.clientH + (delta.bottom || 0); | ||
@@ -307,3 +263,3 @@ if(leftEdge < startX) { endX = leftEdge; } | ||
// animate | ||
me.animateScroll(startX, endX, startY, endY, +duration); | ||
this.animateScroll(startX, endX, startY, endY, +duration); | ||
}, | ||
@@ -315,4 +271,4 @@ | ||
animateScroll: function (startX, endX, startY, endY, duration) { | ||
var me = this, | ||
scrollEl = me.scrollEl, | ||
var self = this, | ||
scrollEl = this.scrollEl, | ||
startTime = Date.now(); | ||
@@ -346,4 +302,4 @@ | ||
me.scrollAnimation = time < 1 ? window.requestAnimationFrame(animate) : null; | ||
}()); | ||
self.scrollAnimation = time < 1 ? window.requestAnimationFrame(animate) : null; | ||
}(this)); | ||
}, | ||
@@ -355,10 +311,9 @@ | ||
destroy: function () { | ||
var me = this, | ||
element = me.element, | ||
scrollEl = me.scrollEl, | ||
listeners = me.listeners, | ||
index = G.instances.indexOf(me), | ||
var self = this, | ||
element = this.element, | ||
scrollEl = this.scrollEl, | ||
listeners = this.listeners, | ||
child; | ||
if(!me.scrollEl) { return; } | ||
if(!this.scrollEl) { return; } | ||
@@ -371,22 +326,25 @@ // unbind events | ||
// remove scrollbars elements | ||
_invoke(me.scrollbars, 'remove'); | ||
_invoke(this.scrollbars, 'remove'); | ||
// unwrap content | ||
while(child = scrollEl.childNodes[0]) { | ||
element.insertBefore(child, scrollEl); | ||
if (!this.settings.contentElement) { | ||
while(child = scrollEl.childNodes[0]) { | ||
element.insertBefore(child, scrollEl); | ||
} | ||
element.removeChild(scrollEl); | ||
this.scrollEl = null; | ||
} | ||
element.removeChild(scrollEl); | ||
me.scrollEl = null; | ||
// remove classes | ||
toggleClass(element, me.settings.classPrefix + 'prevent', false); | ||
toggleClass(element, this.settings.classPrefix + 'prevent', false); | ||
toggleClass(element, 'is-enabled', false); | ||
// defer instance removal from global array | ||
// to not affect checkLoop _invoke | ||
if (index > -1) { | ||
window.requestAnimationFrame(function () { | ||
window.requestAnimationFrame(function () { | ||
var index = G.instances.indexOf(self); | ||
if (index > -1) { | ||
G.instances.splice(index, 1); | ||
}); | ||
} | ||
} | ||
}); | ||
}, | ||
@@ -398,4 +356,3 @@ | ||
fireCustomEvent: function (eventName) { | ||
var me = this, | ||
cache = me.cache, | ||
var cache = this.cache, | ||
sH = cache.scrollH, sW = cache.scrollW, | ||
@@ -422,3 +379,10 @@ eventData; | ||
me.element.dispatchEvent(new CustomEvent(eventName, { detail: eventData })); | ||
var event; | ||
if (CustomEvent === 'function') { | ||
event = new CustomEvent(eventName, { detail: eventData }); | ||
} else { // IE does not support CustomEvent | ||
event = document.createEvent('CustomEvent'); | ||
event.initCustomEvent(eventName, false, false, eventData); | ||
} | ||
this.element.dispatchEvent(event); | ||
}, | ||
@@ -433,39 +397,37 @@ | ||
scroll: function (ev, me) { | ||
scroll: function (ev) { | ||
if (!G.pauseCheck) { | ||
me.fireCustomEvent('scrollstart'); | ||
this.fireCustomEvent('scrollstart'); | ||
} | ||
G.pauseCheck = true; | ||
me.scrollbars.v.update(); | ||
me.scrollbars.h.update(); | ||
this.scrollbars.v.update(); | ||
this.scrollbars.h.update(); | ||
me.fireCustomEvent('scroll'); | ||
this.fireCustomEvent('scroll'); | ||
clearTimeout(me.cache.timerStop); | ||
me.cache.timerStop = setTimeout(function () { | ||
Events.scrollStop(me); | ||
}, me.settings.scrollStopDelay); | ||
clearTimeout(this.cache.timerStop); | ||
this.cache.timerStop = setTimeout(Events.scrollStop.bind(this), this.settings.scrollStopDelay); | ||
}, | ||
touchstart: function (ev, me) { | ||
touchstart: function (ev) { | ||
G.pauseCheck = false; | ||
me.scrollbars.v.update(); | ||
me.scrollbars.h.update(); | ||
this.scrollbars.v.update(); | ||
this.scrollbars.h.update(); | ||
Events.wheel(ev, me); | ||
Events.wheel.call(this, ev); | ||
}, | ||
touchend: function (ev, me) { | ||
touchend: function (ev) { | ||
// prevents touchmove generate scroll event to call | ||
// scrollstop while the page is still momentum scrolling | ||
clearTimeout(me.cache.timerStop); | ||
clearTimeout(this.cache.timerStop); | ||
}, | ||
scrollStop: function (me) { | ||
me.fireCustomEvent('scrollstop'); | ||
scrollStop: function () { | ||
this.fireCustomEvent('scrollstop'); | ||
G.pauseCheck = false; | ||
@@ -475,15 +437,15 @@ }, | ||
wheel: function (ev, me) { | ||
var cache = me.cache, | ||
wheel: function (ev) { | ||
var cache = this.cache, | ||
cacheV = cache.v, | ||
cacheH = cache.h, | ||
preventScroll = me.settings.preventParentScroll; | ||
preventScroll = this.settings.preventParentScroll && G.isTouch; | ||
window.cancelAnimationFrame(me.scrollAnimation); | ||
window.cancelAnimationFrame(this.scrollAnimation); | ||
if(preventScroll && cacheV.enabled && cacheV.percent % 100 === 0) { | ||
me.scrollEl.scrollTop = cacheV.percent ? (cache.scrollH - cache.clientH - 1) : 1; | ||
this.scrollEl.scrollTop = cacheV.percent ? (cache.scrollH - cache.clientH - 1) : 1; | ||
} | ||
if(preventScroll && cacheH.enabled && cacheH.percent % 100 === 0) { | ||
me.scrollEl.scrollLeft = cacheH.percent ? (cache.scrollW - cache.clientW - 1) : 1; | ||
this.scrollEl.scrollLeft = cacheH.percent ? (cache.scrollW - cache.clientW - 1) : 1; | ||
} | ||
@@ -511,2 +473,3 @@ }, | ||
rtlMode = G.scrollbarSpec.rtl, | ||
enabled = false, | ||
@@ -527,2 +490,3 @@ scrollbarEl = null, | ||
var evData = ev.touches ? ev.touches[0] : ev, | ||
dragMode = settings.rtl && rtlMode === 1 && !isVertical ? -1 : 1, | ||
delta, deltaRatio; | ||
@@ -534,3 +498,3 @@ | ||
scrollEl[scrollProp] = events.dragData.scroll + deltaRatio * cache[scrollSize]; | ||
scrollEl[scrollProp] = events.dragData.scroll + deltaRatio * cache[scrollSize] * dragMode; | ||
}, | ||
@@ -585,4 +549,3 @@ | ||
update: function () { | ||
var me = this, | ||
newSize, oldSize, | ||
var newSize, oldSize, | ||
newDim, newRelPos, deltaPos; | ||
@@ -602,11 +565,11 @@ | ||
if(newSize === 1 && enabled) { | ||
me.toggle(false); | ||
this.toggle(false); | ||
} | ||
if(newSize < 1 && !enabled) { | ||
me.toggle(true); | ||
this.toggle(true); | ||
} | ||
if(trackEl && enabled) { | ||
me.style(newRelPos, deltaPos, newSize, oldSize); | ||
this.style(newRelPos, deltaPos, newSize, oldSize); | ||
} | ||
@@ -618,3 +581,3 @@ | ||
if(enabled) { | ||
me.fireEdgeEv(); | ||
this.fireEdgeEv(); | ||
} | ||
@@ -628,4 +591,9 @@ | ||
trackEl.style[ isVertical ? 'height' : 'width' ] = newSize * 100 + '%'; | ||
if (settings.rtl && !isVertical) { | ||
trackEl.style.marginRight = (1 - newSize) * 100 + '%'; | ||
} | ||
} | ||
trackEl.style[G.cssTransform] = 'translate(' + (isVertical ? '0%,' + newRelPos + '%' : newRelPos + '%' + ',0%') + ')'; | ||
trackEl.style[G.cssTransform] = 'translate(' + | ||
(isVertical ? '0%,' + newRelPos + '%' : newRelPos + '%' + ',0%') | ||
+ ')'; | ||
}, | ||
@@ -641,6 +609,9 @@ | ||
positionRatio, percent; | ||
if(sizeRatio >= 1 || !scrollS) { // no scrollbars needed | ||
return { position: 0, size: 1, percent: 0 }; | ||
} | ||
if (!isVertical && settings.rtl && rtlMode) { | ||
position = sizeDiff - position * rtlMode; | ||
} | ||
@@ -693,4 +664,4 @@ percent = 100 * position / sizeDiff; | ||
hideNativeScrollbars: function (scrollEl) { | ||
var size = G.nativeScrollbarSize, | ||
hideNativeScrollbars: function (scrollEl, isRtl) { | ||
var size = G.scrollbarSpec.width, | ||
scrollElStyle = scrollEl.style; | ||
@@ -703,3 +674,3 @@ if(size === 0) { | ||
} else { | ||
scrollElStyle.right = -size + 'px'; | ||
scrollElStyle[isRtl ? 'left' : 'right'] = -size + 'px'; | ||
scrollElStyle.bottom = -size + 'px'; | ||
@@ -732,3 +703,2 @@ return true; | ||
} | ||
wrapper.className = className; | ||
return element.appendChild(wrapper); | ||
@@ -738,9 +708,2 @@ }, | ||
containsNode: function (parent, node) { | ||
return parent.contains ? | ||
parent != node && parent.contains(node) : | ||
!!(parent.compareDocumentPosition(node) & 16); | ||
}, | ||
// Global height checker | ||
@@ -781,4 +744,5 @@ // looped to listen element changes | ||
cssTransition: cssTest('transition'), | ||
cssTransform: cssTest('transform') || '', | ||
nativeScrollbarSize: getScrollbarWidth(), | ||
cssTransform: cssTest('transform'), | ||
scrollbarSpec: getScrollbarSpec(), | ||
passiveEvent: getPassiveSupport(), | ||
@@ -792,8 +756,8 @@ instances: [], | ||
// Get scrollbars width, thanks Google Closure Library | ||
function getScrollbarWidth () { | ||
function getScrollbarSpec () { | ||
var htmlEl = document.documentElement, | ||
outerEl, innerEl, width = 0; | ||
outerEl, innerEl, width = 0, rtl = 1; // IE is reverse | ||
outerEl = document.createElement('div'); | ||
outerEl.style.cssText = 'overflow:scroll;width:50px;height:50px;position:absolute;left:-100px'; | ||
outerEl.style.cssText = 'overflow:scroll;width:50px;height:50px;position:absolute;left:-100px;direction:rtl'; | ||
@@ -806,5 +770,23 @@ innerEl = document.createElement('div'); | ||
width = outerEl.offsetWidth - outerEl.clientWidth; | ||
if (outerEl.scrollLeft > 0) { | ||
rtl = 0; // webkit is default | ||
} else { | ||
outerEl.scrollLeft = 1; | ||
if (outerEl.scrollLeft === 0) { | ||
rtl = -1; // firefox is negative | ||
} | ||
} | ||
htmlEl.removeChild(outerEl); | ||
return { width: width, rtl: rtl }; | ||
} | ||
return width; | ||
function getPassiveSupport () { | ||
var passive = false; | ||
var options = Object.defineProperty({}, 'passive', { | ||
get: function () { passive = true; }, | ||
}); | ||
window.addEventListener('test', null, options); | ||
return passive ? { capture: false, passive: true } : false; | ||
} | ||
@@ -817,8 +799,8 @@ | ||
el = document.createElement('test'), | ||
props = (prop + ' ' + ['Webkit','Moz','O','ms'].join(ucProp + ' ') + ucProp).split(' '); | ||
props = [prop, 'Webkit' + ucProp]; | ||
for (var i in props) { | ||
if(el.style[props[i]] !== undefined) { return props[i]; } | ||
} | ||
return false; | ||
return ''; | ||
} | ||
@@ -825,0 +807,0 @@ |
/*! | ||
* Optiscroll.js v2.0.1 | ||
* Optiscroll.js v3.0.0 | ||
* https://github.com/wilsonfletcher/Optiscroll/ | ||
* by Alberto Gasparin | ||
* | ||
* @copyright 2016 Wilson Fletcher | ||
* @copyright 2017 Alberto Gasparin | ||
* @license Released under MIT LICENSE | ||
*/ | ||
!function(a,b,c,d){"use strict";function e(){var a,c,d=b.documentElement,e=0;return a=b.createElement("div"),a.style.cssText="overflow:scroll;width:50px;height:50px;position:absolute;left:-100px",c=b.createElement("div"),c.style.cssText="width:100px;height:100px",a.appendChild(c),d.appendChild(a),e=a.offsetWidth-a.clientWidth,d.removeChild(a),e}function f(a){var c=a.charAt(0).toUpperCase()+a.slice(1),e=b.createElement("test"),f=(a+" "+["Webkit","Moz","O","ms"].join(c+" ")+c).split(" ");for(var g in f)if(e.style[f[g]]!==d)return f[g];return!1}function g(a,b,c){var d=a.className.split(/\s+/),e=d.indexOf(b);c?~e||d.push(b):~e&&d.splice(e,1),a.className=d.join(" ")}function h(a,b,c){for(var e in b)!b.hasOwnProperty(e)||a[e]!==d&&c||(a[e]=b[e]);return a}function i(a,b,c){var d,e;if(a.length)for(d=0,e=a.length;e>d;d++)a[d][b].apply(a[d],c);else for(d in a)a[d][b].apply(a[d],c)}function j(a,b){var c,d;return function(){var e=this,f=Date.now(),g=arguments;c&&c+b>f?(clearTimeout(d),d=setTimeout(function(){c=f,a.apply(e,g)},b)):(c=f,a.apply(e,g))}}"function"==typeof a.CustomEvent||function(a){function c(a,c){c=c||{bubbles:!1,cancelable:!1,detail:d};var e=b.createEvent("CustomEvent");return e.initCustomEvent(a,c.bubbles,c.cancelable,c.detail),e}c.prototype=a.Event.prototype,a.CustomEvent=c}(a),a.requestAnimationFrame||function(a){var b=0;a.requestAnimationFrame=function(a){var d=Date.now(),e=c.max(b+16,d);return setTimeout(function(){a(b=e)},e-d)},a.cancelAnimationFrame=clearTimeout}(a);var k=function q(a,b){return new q.Instance(a,b||{})},l=k.globalSettings={scrollMinUpdateInterval:25,checkFrequency:1e3,pauseCheck:!1};k.defaults={preventParentScroll:!1,forceScrollbars:!1,scrollStopDelay:300,maxTrackSize:95,minTrackSize:5,draggableTracks:!0,autoUpdate:!0,classPrefix:"optiscroll-"},k.Instance=function(a,b){var c=this;c.element=a,c.settings=h(h({},k.defaults),b||{}),c.cache={},c.init()},k.Instance.prototype={init:function(){var a=this,b=a.settings,c=!1;a.scrollEl=o.createWrapper(a.element,b.classPrefix+"content"),g(a.element,"is-enabled",!0),a.scrollbars={v:n("v",a),h:n("h",a)},(p.nativeScrollbarSize||b.forceScrollbars)&&(c=o.hideNativeScrollbars(a.scrollEl)),c&&i(a.scrollbars,"create"),p.isTouch&&b.preventParentScroll&&g(a.element,b.classPrefix+"prevent",!0),a.update(),a.bind(),b.autoUpdate&&p.instances.push(a),b.autoUpdate&&!p.checkTimer&&o.checkLoop()},bind:function(){var a=this,b=a.listeners={},c=a.scrollEl;b.scroll=j(function(b){m.scroll(b,a)},l.scrollMinUpdateInterval),p.isTouch&&(b.touchstart=function(b){m.touchstart(b,a)},b.touchend=function(b){m.touchend(b,a)}),b.mousewheel=b.wheel=function(b){m.wheel(b,a)};for(var d in b)c.addEventListener(d,b[d])},update:function(){var a=this,c=a.cache.clientH,e=a.scrollEl,f=a.cache,g=e.scrollHeight,h=e.clientHeight,j=e.scrollWidth,k=e.clientWidth;if(g!==f.scrollH||h!==f.clientH||j!==f.scrollW||k!==f.clientW){if(f.scrollH=g,f.clientH=h,f.scrollW=j,f.clientW=k,c!==d){if(0===g&&0===h&&!o.containsNode(b.body,a.element))return a.destroy(),!1;a.fireCustomEvent("sizechange")}i(a.scrollbars,"update")}},scrollTo:function(a,b,c){var d,e,f,g,h=this,i=h.cache;p.pauseCheck=!0,h.update(),d=h.scrollEl.scrollLeft,e=h.scrollEl.scrollTop,f=+a,"left"===a&&(f=0),"right"===a&&(f=i.scrollW-i.clientW),a===!1&&(f=d),g=+b,"top"===b&&(g=0),"bottom"===b&&(g=i.scrollH-i.clientH),b===!1&&(g=e),h.animateScroll(d,f,e,g,+c)},scrollIntoView:function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o,q=this,r=q.scrollEl;p.pauseCheck=!0,q.update(),"string"==typeof a?a=r.querySelector(a):a.length&&a.jquery&&(a=a[0]),"number"==typeof c&&(c={top:c,right:c,bottom:c,left:c}),c=c||{},d=a.getBoundingClientRect(),e=r.getBoundingClientRect(),l=n=r.scrollLeft,m=o=r.scrollTop,j=l+d.left-e.left,k=m+d.top-e.top,f=j-(c.left||0),g=k-(c.top||0),h=j+d.width-q.cache.clientW+(c.right||0),i=k+d.height-q.cache.clientH+(c.bottom||0),l>f&&(n=f),h>l&&(n=h),m>g&&(o=g),i>m&&(o=i),q.animateScroll(l,n,m,o,+b)},animateScroll:function(b,d,e,f,g){var h=this,i=h.scrollEl,j=Date.now();if(d!==b||f!==e){if(0===g)return i.scrollLeft=d,void(i.scrollTop=f);isNaN(g)&&(g=15*c.pow(c.max(c.abs(d-b),c.abs(f-e)),.54)),function k(){var l=c.min(1,(Date.now()-j)/g),m=o.easingFunction(l);f!==e&&(i.scrollTop=~~(m*(f-e))+e),d!==b&&(i.scrollLeft=~~(m*(d-b))+b),h.scrollAnimation=1>l?a.requestAnimationFrame(k):null}()}},destroy:function(){var b,c=this,d=c.element,e=c.scrollEl,f=c.listeners,h=p.instances.indexOf(c);if(c.scrollEl){for(var j in f)e.removeEventListener(j,f[j]);for(i(c.scrollbars,"remove");b=e.childNodes[0];)d.insertBefore(b,e);d.removeChild(e),c.scrollEl=null,g(d,c.settings.classPrefix+"prevent",!1),g(d,"is-enabled",!1),h>-1&&a.requestAnimationFrame(function(){p.instances.splice(h,1)})}},fireCustomEvent:function(a){var b,c=this,d=c.cache,e=d.scrollH,f=d.scrollW;b={scrollbarV:h({},d.v),scrollbarH:h({},d.h),scrollTop:d.v.position*e,scrollLeft:d.h.position*f,scrollBottom:(1-d.v.position-d.v.size)*e,scrollRight:(1-d.h.position-d.h.size)*f,scrollWidth:f,scrollHeight:e,clientWidth:d.clientW,clientHeight:d.clientH},c.element.dispatchEvent(new CustomEvent(a,{detail:b}))}};var m={scroll:function(a,b){p.pauseCheck||b.fireCustomEvent("scrollstart"),p.pauseCheck=!0,b.scrollbars.v.update(),b.scrollbars.h.update(),b.fireCustomEvent("scroll"),clearTimeout(b.cache.timerStop),b.cache.timerStop=setTimeout(function(){m.scrollStop(b)},b.settings.scrollStopDelay)},touchstart:function(a,b){p.pauseCheck=!1,b.scrollbars.v.update(),b.scrollbars.h.update(),m.wheel(a,b)},touchend:function(a,b){clearTimeout(b.cache.timerStop)},scrollStop:function(a){a.fireCustomEvent("scrollstop"),p.pauseCheck=!1},wheel:function(b,c){var d=c.cache,e=d.v,f=d.h,g=c.settings.preventParentScroll;a.cancelAnimationFrame(c.scrollAnimation),g&&e.enabled&&e.percent%100===0&&(c.scrollEl.scrollTop=e.percent?d.scrollH-d.clientH-1:1),g&&f.enabled&&f.percent%100===0&&(c.scrollEl.scrollLeft=f.percent?d.scrollW-d.clientW-1:1)}},n=function(a,d){var e="v"===a,f=d.element,i=d.scrollEl,j=d.settings,k=d.cache,l=k[a]={},m=e?"H":"W",n="client"+m,o="scroll"+m,q=e?"scrollTop":"scrollLeft",r=e?["top","bottom"]:["left","right"],s=!1,t=null,u=null,v={dragData:null,dragStart:function(a){var b=a.touches?a.touches[0]:a;v.dragData={x:b.pageX,y:b.pageY,scroll:i[q]},v.bind(!0)},dragMove:function(a){var b,c,d=a.touches?a.touches[0]:a;a.preventDefault(),b=e?d.pageY-v.dragData.y:d.pageX-v.dragData.x,c=b/k[n],i[q]=v.dragData.scroll+c*k[o]},dragEnd:function(){v.dragData=null,v.bind(!1)},bind:function(a){var c=(a?"add":"remove")+"EventListener",d=p.isTouch?["touchmove","touchend"]:["mousemove","mouseup"];b[c](d[0],v.dragMove),b[c](d[1],v.dragEnd)}};return{toggle:function(b){s=b,u&&g(f,"has-"+a+"track",s),l.enabled=s},create:function(){var c=p.isTouch?"touchstart":"mousedown";t=b.createElement("div"),u=b.createElement("b"),t.className=j.classPrefix+a,u.className=j.classPrefix+a+"track",t.appendChild(u),f.appendChild(t),j.draggableTracks&&u.addEventListener(c,v.dragStart)},update:function(){var a,b,d,e,f,g=this;(s||k[n]!==k[o])&&(d=this.calc(),a=d.size,b=l.size,e=1/a*d.position*100,f=c.abs(d.position-(l.position||0))*k[n],1===a&&s&&g.toggle(!1),1>a&&!s&&g.toggle(!0),u&&s&&g.style(e,f,a,b),l=h(l,d),s&&g.fireEdgeEv())},style:function(a,b,c,d){c!==d&&(u.style[e?"height":"width"]=100*c+"%"),u.style[p.cssTransform]="translate("+(e?"0%,"+a+"%":a+"%,0%")+")"},calc:function(){var a,b,d=i[q],e=k[n],f=k[o],g=e/f,h=f-e;return g>=1||!f?{position:0,size:1,percent:0}:(b=100*d/h,1>=d&&(b=0),d>=h-1&&(b=100),g=c.max(g,j.minTrackSize/100),g=c.min(g,j.maxTrackSize/100),a=(1-g)*(b/100),{position:a,size:g,percent:b})},fireEdgeEv:function(){var a=l.percent;l.was!==a&&a%100===0&&(d.fireCustomEvent("scrollreachedge"),d.fireCustomEvent("scrollreach"+r[a/100])),l.was=a},remove:function(){this.toggle(!1),t&&(t.parentNode.removeChild(t),t=null)}}},o={hideNativeScrollbars:function(a){var b=p.nativeScrollbarSize,c=a.style;if(0===b){var d=Date.now();return a.setAttribute("data-scroll",d),o.addCssRule('[data-scroll="'+d+'"]::-webkit-scrollbar',"display:none;width:0;height:0;")}return c.right=-b+"px",c.bottom=-b+"px",!0},addCssRule:function(a,c){var d=b.getElementById("scroll-sheet");d||(d=b.createElement("style"),d.id="scroll-sheet",d.appendChild(b.createTextNode("")),b.head.appendChild(d));try{return d.sheet.insertRule(a+" {"+c+"}",0),!0}catch(e){return}},createWrapper:function(a,c){for(var d,e=b.createElement("div");d=a.childNodes[0];)e.appendChild(d);return e.className=c,a.appendChild(e)},containsNode:function(a,b){return a.contains?a!=b&&a.contains(b):!!(16&a.compareDocumentPosition(b))},checkLoop:function(){return p.instances.length?(p.pauseCheck||i(p.instances,"update"),void(l.checkFrequency&&(p.checkTimer=setTimeout(function(){o.checkLoop()},l.checkFrequency)))):void(p.checkTimer=null)},easingFunction:function(a){return--a*a*a+1}},p=k.G={isTouch:"ontouchstart"in a,cssTransition:f("transition"),cssTransform:f("transform")||"",nativeScrollbarSize:e(),instances:[],checkTimer:null,pauseCheck:!1};"function"==typeof define&&define.amd&&define(function(){return k}),"undefined"!=typeof module&&module.exports&&(module.exports=k),a.Optiscroll=k}(window,document,Math),function(a){var b="optiscroll";a.fn[b]=function(c){var d,e;return"string"==typeof c&&(e=Array.prototype.slice.call(arguments),d=e.shift()),this.each(function(){var f=a(this),g=f.data(b);g?g&&"string"==typeof d&&(g[d].apply(g,e),"destroy"===d&&f.removeData(b)):(g=new window.Optiscroll(this,c||{}),f.data(b,g))})}}(jQuery||Zepto); | ||
!function(a,b,c,d){"use strict";function e(){var a,c,d=b.documentElement,e=0,f=1;return a=b.createElement("div"),a.style.cssText="overflow:scroll;width:50px;height:50px;position:absolute;left:-100px;direction:rtl",c=b.createElement("div"),c.style.cssText="width:100px;height:100px",a.appendChild(c),d.appendChild(a),e=a.offsetWidth-a.clientWidth,a.scrollLeft>0?f=0:(a.scrollLeft=1,0===a.scrollLeft&&(f=-1)),d.removeChild(a),{width:e,rtl:f}}function f(){var b=!1,c=Object.defineProperty({},"passive",{get:function(){b=!0}});return a.addEventListener("test",null,c),!!b&&{capture:!1,passive:!0}}function g(a){var c=a.charAt(0).toUpperCase()+a.slice(1),e=b.createElement("test"),f=[a,"Webkit"+c];for(var g in f)if(e.style[f[g]]!==d)return f[g];return""}function h(a,b,c){var d=a.className.split(/\s+/),e=d.indexOf(b);c?~e||d.push(b):~e&&d.splice(e,1),a.className=d.join(" ")}function i(a,b,c){for(var e in b)!b.hasOwnProperty(e)||a[e]!==d&&c||(a[e]=b[e]);return a}function j(a,b,c){var d,e;if(a.length)for(d=0,e=a.length;d<e;d++)a[d][b].apply(a[d],c);else for(d in a)a[d][b].apply(a[d],c)}function k(a,b){var c,d;return function(){var e=this,f=Date.now(),g=arguments;c&&f<c+b?(clearTimeout(d),d=setTimeout(function(){c=f,a.apply(e,g)},b)):(c=f,a.apply(e,g))}}var l=function a(b,c){return new a.Instance(b,c||{})},m=l.globalSettings={scrollMinUpdateInterval:25,checkFrequency:1e3,pauseCheck:!1};l.defaults={preventParentScroll:!1,forceScrollbars:!1,scrollStopDelay:300,maxTrackSize:95,minTrackSize:5,draggableTracks:!0,autoUpdate:!0,classPrefix:"optiscroll-",wrapContent:!0,rtl:!1},l.Instance=function(b,c){this.element=b,this.settings=i(i({},l.defaults),c||{}),"boolean"!=typeof c.rtl&&(this.settings.rtl="rtl"===a.getComputedStyle(b).direction),this.cache={},this.init()},l.Instance.prototype={init:function(){var a=this.element,b=this.settings,c=!1,d=this.scrollEl=b.wrapContent?p.createWrapper(a):a.firstElementChild;h(d,b.classPrefix+"content",!0),h(a,"is-enabled"+(b.rtl?" is-rtl":""),!0),this.scrollbars={v:o("v",this),h:o("h",this)},(q.scrollbarSpec.width||b.forceScrollbars)&&(c=p.hideNativeScrollbars(d,b.rtl)),c&&j(this.scrollbars,"create"),q.isTouch&&b.preventParentScroll&&h(a,b.classPrefix+"prevent",!0),this.update(),this.bind(),b.autoUpdate&&q.instances.push(this),b.autoUpdate&&!q.checkTimer&&p.checkLoop()},bind:function(){var a=this.listeners={},b=this.scrollEl;a.scroll=k(n.scroll.bind(this),m.scrollMinUpdateInterval),q.isTouch&&(a.touchstart=n.touchstart.bind(this),a.touchend=n.touchend.bind(this)),a.mousewheel=a.wheel=n.wheel.bind(this);for(var c in a)b.addEventListener(c,a[c],q.passiveEvent)},update:function(){var a=this.scrollEl,c=this.cache,e=c.clientH,f=a.scrollHeight,g=a.clientHeight,h=a.scrollWidth,i=a.clientWidth;if(f!==c.scrollH||g!==c.clientH||h!==c.scrollW||i!==c.clientW){if(c.scrollH=f,c.clientH=g,c.scrollW=h,c.clientW=i,e!==d){if(0===f&&0===g&&!b.body.contains(this.element))return this.destroy(),!1;this.fireCustomEvent("sizechange")}j(this.scrollbars,"update")}},scrollTo:function(a,b,c){var d,e,f,g,h=this.cache;q.pauseCheck=!0,this.update(),d=this.scrollEl.scrollLeft,e=this.scrollEl.scrollTop,f=+a,"left"===a&&(f=0),"right"===a&&(f=h.scrollW-h.clientW),a===!1&&(f=d),g=+b,"top"===b&&(g=0),"bottom"===b&&(g=h.scrollH-h.clientH),b===!1&&(g=e),this.animateScroll(d,f,e,g,+c)},scrollIntoView:function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p=this.scrollEl;q.pauseCheck=!0,this.update(),"string"==typeof a?a=p.querySelector(a):a.length&&a.jquery&&(a=a[0]),"number"==typeof c&&(c={top:c,right:c,bottom:c,left:c}),c=c||{},d=a.getBoundingClientRect(),e=p.getBoundingClientRect(),l=n=p.scrollLeft,m=o=p.scrollTop,j=l+d.left-e.left,k=m+d.top-e.top,f=j-(c.left||0),g=k-(c.top||0),h=j+d.width-this.cache.clientW+(c.right||0),i=k+d.height-this.cache.clientH+(c.bottom||0),f<l&&(n=f),h>l&&(n=h),g<m&&(o=g),i>m&&(o=i),this.animateScroll(l,n,m,o,+b)},animateScroll:function(b,d,e,f,g){var h=this,i=this.scrollEl,j=Date.now();if(d!==b||f!==e){if(0===g)return i.scrollLeft=d,void(i.scrollTop=f);isNaN(g)&&(g=15*c.pow(c.max(c.abs(d-b),c.abs(f-e)),.54)),function k(){var l=c.min(1,(Date.now()-j)/g),m=p.easingFunction(l);f!==e&&(i.scrollTop=~~(m*(f-e))+e),d!==b&&(i.scrollLeft=~~(m*(d-b))+b),h.scrollAnimation=l<1?a.requestAnimationFrame(k):null}()}},destroy:function(){var b,c=this,d=this.element,e=this.scrollEl,f=this.listeners;if(this.scrollEl){for(var g in f)e.removeEventListener(g,f[g]);if(j(this.scrollbars,"remove"),!this.settings.contentElement){for(;b=e.childNodes[0];)d.insertBefore(b,e);d.removeChild(e),this.scrollEl=null}h(d,this.settings.classPrefix+"prevent",!1),h(d,"is-enabled",!1),a.requestAnimationFrame(function(){var a=q.instances.indexOf(c);a>-1&&q.instances.splice(a,1)})}},fireCustomEvent:function(a){var c,d=this.cache,e=d.scrollH,f=d.scrollW;c={scrollbarV:i({},d.v),scrollbarH:i({},d.h),scrollTop:d.v.position*e,scrollLeft:d.h.position*f,scrollBottom:(1-d.v.position-d.v.size)*e,scrollRight:(1-d.h.position-d.h.size)*f,scrollWidth:f,scrollHeight:e,clientWidth:d.clientW,clientHeight:d.clientH};var g;"function"===CustomEvent?g=new CustomEvent(a,{detail:c}):(g=b.createEvent("CustomEvent"),g.initCustomEvent(a,!1,!1,c)),this.element.dispatchEvent(g)}};var n={scroll:function(a){q.pauseCheck||this.fireCustomEvent("scrollstart"),q.pauseCheck=!0,this.scrollbars.v.update(),this.scrollbars.h.update(),this.fireCustomEvent("scroll"),clearTimeout(this.cache.timerStop),this.cache.timerStop=setTimeout(n.scrollStop.bind(this),this.settings.scrollStopDelay)},touchstart:function(a){q.pauseCheck=!1,this.scrollbars.v.update(),this.scrollbars.h.update(),n.wheel.call(this,a)},touchend:function(a){clearTimeout(this.cache.timerStop)},scrollStop:function(){this.fireCustomEvent("scrollstop"),q.pauseCheck=!1},wheel:function(b){var c=this.cache,d=c.v,e=c.h,f=this.settings.preventParentScroll&&q.isTouch;a.cancelAnimationFrame(this.scrollAnimation),f&&d.enabled&&d.percent%100==0&&(this.scrollEl.scrollTop=d.percent?c.scrollH-c.clientH-1:1),f&&e.enabled&&e.percent%100==0&&(this.scrollEl.scrollLeft=e.percent?c.scrollW-c.clientW-1:1)}},o=function(a,d){var e="v"===a,f=d.element,g=d.scrollEl,j=d.settings,k=d.cache,l=k[a]={},m=e?"H":"W",n="client"+m,o="scroll"+m,p=e?"scrollTop":"scrollLeft",r=e?["top","bottom"]:["left","right"],s=q.scrollbarSpec.rtl,t=!1,u=null,v=null,w={dragData:null,dragStart:function(a){var b=a.touches?a.touches[0]:a;w.dragData={x:b.pageX,y:b.pageY,scroll:g[p]},w.bind(!0)},dragMove:function(a){var b,c,d=a.touches?a.touches[0]:a,f=j.rtl&&1===s&&!e?-1:1;a.preventDefault(),b=e?d.pageY-w.dragData.y:d.pageX-w.dragData.x,c=b/k[n],g[p]=w.dragData.scroll+c*k[o]*f},dragEnd:function(){w.dragData=null,w.bind(!1)},bind:function(a){var c=(a?"add":"remove")+"EventListener",d=q.isTouch?["touchmove","touchend"]:["mousemove","mouseup"];b[c](d[0],w.dragMove),b[c](d[1],w.dragEnd)}};return{toggle:function(b){t=b,v&&h(f,"has-"+a+"track",t),l.enabled=t},create:function(){var c=q.isTouch?"touchstart":"mousedown";u=b.createElement("div"),v=b.createElement("b"),u.className=j.classPrefix+a,v.className=j.classPrefix+a+"track",u.appendChild(v),f.appendChild(u),j.draggableTracks&&v.addEventListener(c,w.dragStart)},update:function(){var a,b,d,e,f;(t||k[n]!==k[o])&&(d=this.calc(),a=d.size,b=l.size,e=1/a*d.position*100,f=c.abs(d.position-(l.position||0))*k[n],1===a&&t&&this.toggle(!1),a<1&&!t&&this.toggle(!0),v&&t&&this.style(e,f,a,b),l=i(l,d),t&&this.fireEdgeEv())},style:function(a,b,c,d){c!==d&&(v.style[e?"height":"width"]=100*c+"%",j.rtl&&!e&&(v.style.marginRight=100*(1-c)+"%")),v.style[q.cssTransform]="translate("+(e?"0%,"+a+"%":a+"%,0%")+")"},calc:function(){var a,b,d=g[p],f=k[n],h=k[o],i=f/h,l=h-f;return i>=1||!h?{position:0,size:1,percent:0}:(!e&&j.rtl&&s&&(d=l-d*s),b=100*d/l,d<=1&&(b=0),d>=l-1&&(b=100),i=c.max(i,j.minTrackSize/100),i=c.min(i,j.maxTrackSize/100),a=b/100*(1-i),{position:a,size:i,percent:b})},fireEdgeEv:function(){var a=l.percent;l.was!==a&&a%100==0&&(d.fireCustomEvent("scrollreachedge"),d.fireCustomEvent("scrollreach"+r[a/100])),l.was=a},remove:function(){this.toggle(!1),u&&(u.parentNode.removeChild(u),u=null)}}},p={hideNativeScrollbars:function(a,b){var c=q.scrollbarSpec.width,d=a.style;if(0===c){var e=Date.now();return a.setAttribute("data-scroll",e),p.addCssRule('[data-scroll="'+e+'"]::-webkit-scrollbar',"display:none;width:0;height:0;")}return d[b?"left":"right"]=-c+"px",d.bottom=-c+"px",!0},addCssRule:function(a,c){var d=b.getElementById("scroll-sheet");d||(d=b.createElement("style"),d.id="scroll-sheet",d.appendChild(b.createTextNode("")),b.head.appendChild(d));try{return d.sheet.insertRule(a+" {"+c+"}",0),!0}catch(a){return}},createWrapper:function(a,c){for(var d,e=b.createElement("div");d=a.childNodes[0];)e.appendChild(d);return a.appendChild(e)},checkLoop:function(){if(!q.instances.length)return void(q.checkTimer=null);q.pauseCheck||j(q.instances,"update"),m.checkFrequency&&(q.checkTimer=setTimeout(function(){p.checkLoop()},m.checkFrequency))},easingFunction:function(a){return--a*a*a+1}},q=l.G={isTouch:"ontouchstart"in a,cssTransition:g("transition"),cssTransform:g("transform"),scrollbarSpec:e(),passiveEvent:f(),instances:[],checkTimer:null,pauseCheck:!1};"function"==typeof define&&define.amd&&define(function(){return l}),"undefined"!=typeof module&&module.exports&&(module.exports=l),a.Optiscroll=l}(window,document,Math),function(a){var b="optiscroll";a.fn[b]=function(c){var d,e;return"string"==typeof c&&(e=Array.prototype.slice.call(arguments),d=e.shift()),this.each(function(){var f=a(this),g=f.data(b);g?g&&"string"==typeof d&&(g[d].apply(g,e),"destroy"===d&&f.removeData(b)):(g=new window.Optiscroll(this,c||{}),f.data(b,g))})}}(jQuery||Zepto); |
/*! | ||
* Optiscroll.js v2.0.1 | ||
* Optiscroll.js v3.0.0 | ||
* https://github.com/wilsonfletcher/Optiscroll/ | ||
* by Alberto Gasparin | ||
* | ||
* @copyright 2016 Wilson Fletcher | ||
* @copyright 2017 Alberto Gasparin | ||
* @license Released under MIT LICENSE | ||
@@ -13,47 +12,3 @@ */ | ||
/* | ||
* CustomEvent polyfill for IE9 | ||
* By MDN | ||
* https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent | ||
* MIT LICENSE | ||
*/ | ||
typeof window.CustomEvent === 'function' || (function (window) { | ||
function CustomEvent (event, params) { | ||
params = params || { bubbles: false, cancelable: false, detail: undefined }; | ||
var evt = document.createEvent('CustomEvent'); | ||
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); | ||
return evt; | ||
} | ||
CustomEvent.prototype = window.Event.prototype; | ||
window.CustomEvent = CustomEvent; | ||
})(window); | ||
// Adaped from https://github.com/darius/requestAnimationFrame | ||
// requestAnimationFrame polyfill by Erik Möller. | ||
// MIT license | ||
window.requestAnimationFrame || (function(window) { | ||
var lastTime = 0; | ||
window.requestAnimationFrame = function(callback) { | ||
var now = Date.now(); | ||
var nextTime = Math.max(lastTime + 16, now); | ||
return setTimeout(function() { | ||
callback(lastTime = nextTime); | ||
}, nextTime - now); | ||
}; | ||
window.cancelAnimationFrame = clearTimeout; | ||
}(window)); | ||
/** | ||
@@ -86,2 +41,4 @@ * Optiscroll, use this to create instances | ||
classPrefix: 'optiscroll-', | ||
wrapContent: true, | ||
rtl: false, | ||
}; | ||
@@ -92,10 +49,11 @@ | ||
Optiscroll.Instance = function (element, options) { | ||
var me = this; | ||
// instance variables | ||
me.element = element; | ||
me.settings = _extend(_extend({}, Optiscroll.defaults), options || {}); | ||
me.cache = {}; | ||
this.element = element; | ||
this.settings = _extend(_extend({}, Optiscroll.defaults), options || {}); | ||
if (typeof options.rtl !== 'boolean') { | ||
this.settings.rtl = window.getComputedStyle(element).direction === 'rtl'; | ||
} | ||
this.cache = {}; | ||
me.init(); | ||
this.init(); | ||
}; | ||
@@ -109,37 +67,41 @@ | ||
init: function () { | ||
var me = this, | ||
settings = me.settings, | ||
var element = this.element, | ||
settings = this.settings, | ||
shouldCreateScrollbars = false; | ||
var scrollEl = this.scrollEl = settings.wrapContent | ||
? Utils.createWrapper(element) | ||
: element.firstElementChild; | ||
me.scrollEl = Utils.createWrapper(me.element, settings.classPrefix + 'content'); | ||
toggleClass(me.element, 'is-enabled', true); | ||
toggleClass(scrollEl, settings.classPrefix + 'content', true); | ||
toggleClass(element, 'is-enabled' + (settings.rtl ? ' is-rtl' : ''), true); | ||
// initialize scrollbars | ||
me.scrollbars = { | ||
v: Scrollbar('v', me), | ||
h: Scrollbar('h', me), | ||
this.scrollbars = { | ||
v: Scrollbar('v', this), | ||
h: Scrollbar('h', this), | ||
}; | ||
// create DOM scrollbars only if they have size or if it's forced | ||
if(G.nativeScrollbarSize || settings.forceScrollbars) { | ||
shouldCreateScrollbars = Utils.hideNativeScrollbars(me.scrollEl); | ||
if(G.scrollbarSpec.width || settings.forceScrollbars) { | ||
shouldCreateScrollbars = Utils.hideNativeScrollbars(scrollEl, settings.rtl); | ||
} | ||
if(shouldCreateScrollbars) { | ||
_invoke(me.scrollbars, 'create'); | ||
_invoke(this.scrollbars, 'create'); | ||
} | ||
if(G.isTouch && settings.preventParentScroll) { | ||
toggleClass(me.element, settings.classPrefix + 'prevent', true); | ||
toggleClass(element, settings.classPrefix + 'prevent', true); | ||
} | ||
// calculate scrollbars | ||
me.update(); | ||
this.update(); | ||
// bind container events | ||
me.bind(); | ||
this.bind(); | ||
// add instance to global array for timed check | ||
if(settings.autoUpdate) { | ||
G.instances.push(me); | ||
G.instances.push(this); | ||
} | ||
@@ -157,21 +119,18 @@ | ||
bind: function () { | ||
var me = this, | ||
listeners = me.listeners = {}, | ||
scrollEl = me.scrollEl; | ||
var listeners = this.listeners = {}, | ||
scrollEl = this.scrollEl; | ||
// scroll event binding | ||
listeners.scroll = _throttle(function (ev) { | ||
Events.scroll(ev, me); | ||
}, GS.scrollMinUpdateInterval); | ||
listeners.scroll = _throttle(Events.scroll.bind(this), GS.scrollMinUpdateInterval); | ||
if(G.isTouch) { | ||
listeners.touchstart = function (ev) { Events.touchstart(ev, me); }; | ||
listeners.touchend = function (ev) { Events.touchend(ev, me); }; | ||
listeners.touchstart = Events.touchstart.bind(this); | ||
listeners.touchend = Events.touchend.bind(this); | ||
} | ||
// Safari does not support wheel event | ||
listeners.mousewheel = listeners.wheel = function (ev) { Events.wheel(ev, me); }; | ||
listeners.mousewheel = listeners.wheel = Events.wheel.bind(this); | ||
for (var ev in listeners) { | ||
scrollEl.addEventListener(ev, listeners[ev]); | ||
scrollEl.addEventListener(ev, listeners[ev], G.passiveEvent); | ||
} | ||
@@ -185,6 +144,5 @@ | ||
update: function () { | ||
var me = this, | ||
oldcH = me.cache.clientH, | ||
scrollEl = me.scrollEl, | ||
cache = me.cache, | ||
var scrollEl = this.scrollEl, | ||
cache = this.cache, | ||
oldcH = cache.clientH, | ||
sH = scrollEl.scrollHeight, | ||
@@ -207,8 +165,8 @@ cH = scrollEl.clientHeight, | ||
// if the element is no more in the DOM | ||
if(sH === 0 && cH === 0 && !Utils.containsNode(document.body, me.element)) { | ||
me.destroy(); | ||
if(sH === 0 && cH === 0 && !document.body.contains(this.element)) { | ||
this.destroy(); | ||
return false; | ||
} | ||
me.fireCustomEvent('sizechange'); | ||
this.fireCustomEvent('sizechange'); | ||
} | ||
@@ -218,3 +176,3 @@ | ||
// and check if bottom is reached | ||
_invoke(me.scrollbars, 'update'); | ||
_invoke(this.scrollbars, 'update'); | ||
} | ||
@@ -230,4 +188,3 @@ }, | ||
scrollTo: function (destX, destY, duration) { | ||
var me = this, | ||
cache = me.cache, | ||
var cache = this.cache, | ||
startX, startY, endX, endY; | ||
@@ -237,6 +194,6 @@ | ||
// force update | ||
me.update(); | ||
this.update(); | ||
startX = me.scrollEl.scrollLeft; | ||
startY = me.scrollEl.scrollTop; | ||
startX = this.scrollEl.scrollLeft; | ||
startY = this.scrollEl.scrollTop; | ||
@@ -254,3 +211,3 @@ endX = +destX; | ||
// animate | ||
me.animateScroll(startX, endX, startY, endY, +duration); | ||
this.animateScroll(startX, endX, startY, endY, +duration); | ||
@@ -262,4 +219,3 @@ }, | ||
scrollIntoView: function (elem, duration, delta) { | ||
var me = this, | ||
scrollEl = me.scrollEl, | ||
var scrollEl = this.scrollEl, | ||
eDim, sDim, | ||
@@ -272,3 +228,3 @@ leftEdge, topEdge, rightEdge, bottomEdge, | ||
// force update | ||
me.update(); | ||
this.update(); | ||
@@ -296,4 +252,4 @@ if(typeof elem === 'string') { // selector | ||
topEdge = offsetY - (delta.top || 0); | ||
rightEdge = offsetX + eDim.width - me.cache.clientW + (delta.right || 0); | ||
bottomEdge = offsetY + eDim.height - me.cache.clientH + (delta.bottom || 0); | ||
rightEdge = offsetX + eDim.width - this.cache.clientW + (delta.right || 0); | ||
bottomEdge = offsetY + eDim.height - this.cache.clientH + (delta.bottom || 0); | ||
@@ -307,3 +263,3 @@ if(leftEdge < startX) { endX = leftEdge; } | ||
// animate | ||
me.animateScroll(startX, endX, startY, endY, +duration); | ||
this.animateScroll(startX, endX, startY, endY, +duration); | ||
}, | ||
@@ -315,4 +271,4 @@ | ||
animateScroll: function (startX, endX, startY, endY, duration) { | ||
var me = this, | ||
scrollEl = me.scrollEl, | ||
var self = this, | ||
scrollEl = this.scrollEl, | ||
startTime = Date.now(); | ||
@@ -346,4 +302,4 @@ | ||
me.scrollAnimation = time < 1 ? window.requestAnimationFrame(animate) : null; | ||
}()); | ||
self.scrollAnimation = time < 1 ? window.requestAnimationFrame(animate) : null; | ||
}(this)); | ||
}, | ||
@@ -355,10 +311,9 @@ | ||
destroy: function () { | ||
var me = this, | ||
element = me.element, | ||
scrollEl = me.scrollEl, | ||
listeners = me.listeners, | ||
index = G.instances.indexOf(me), | ||
var self = this, | ||
element = this.element, | ||
scrollEl = this.scrollEl, | ||
listeners = this.listeners, | ||
child; | ||
if(!me.scrollEl) { return; } | ||
if(!this.scrollEl) { return; } | ||
@@ -371,22 +326,25 @@ // unbind events | ||
// remove scrollbars elements | ||
_invoke(me.scrollbars, 'remove'); | ||
_invoke(this.scrollbars, 'remove'); | ||
// unwrap content | ||
while(child = scrollEl.childNodes[0]) { | ||
element.insertBefore(child, scrollEl); | ||
if (!this.settings.contentElement) { | ||
while(child = scrollEl.childNodes[0]) { | ||
element.insertBefore(child, scrollEl); | ||
} | ||
element.removeChild(scrollEl); | ||
this.scrollEl = null; | ||
} | ||
element.removeChild(scrollEl); | ||
me.scrollEl = null; | ||
// remove classes | ||
toggleClass(element, me.settings.classPrefix + 'prevent', false); | ||
toggleClass(element, this.settings.classPrefix + 'prevent', false); | ||
toggleClass(element, 'is-enabled', false); | ||
// defer instance removal from global array | ||
// to not affect checkLoop _invoke | ||
if (index > -1) { | ||
window.requestAnimationFrame(function () { | ||
window.requestAnimationFrame(function () { | ||
var index = G.instances.indexOf(self); | ||
if (index > -1) { | ||
G.instances.splice(index, 1); | ||
}); | ||
} | ||
} | ||
}); | ||
}, | ||
@@ -398,4 +356,3 @@ | ||
fireCustomEvent: function (eventName) { | ||
var me = this, | ||
cache = me.cache, | ||
var cache = this.cache, | ||
sH = cache.scrollH, sW = cache.scrollW, | ||
@@ -422,3 +379,10 @@ eventData; | ||
me.element.dispatchEvent(new CustomEvent(eventName, { detail: eventData })); | ||
var event; | ||
if (CustomEvent === 'function') { | ||
event = new CustomEvent(eventName, { detail: eventData }); | ||
} else { // IE does not support CustomEvent | ||
event = document.createEvent('CustomEvent'); | ||
event.initCustomEvent(eventName, false, false, eventData); | ||
} | ||
this.element.dispatchEvent(event); | ||
}, | ||
@@ -433,39 +397,37 @@ | ||
scroll: function (ev, me) { | ||
scroll: function (ev) { | ||
if (!G.pauseCheck) { | ||
me.fireCustomEvent('scrollstart'); | ||
this.fireCustomEvent('scrollstart'); | ||
} | ||
G.pauseCheck = true; | ||
me.scrollbars.v.update(); | ||
me.scrollbars.h.update(); | ||
this.scrollbars.v.update(); | ||
this.scrollbars.h.update(); | ||
me.fireCustomEvent('scroll'); | ||
this.fireCustomEvent('scroll'); | ||
clearTimeout(me.cache.timerStop); | ||
me.cache.timerStop = setTimeout(function () { | ||
Events.scrollStop(me); | ||
}, me.settings.scrollStopDelay); | ||
clearTimeout(this.cache.timerStop); | ||
this.cache.timerStop = setTimeout(Events.scrollStop.bind(this), this.settings.scrollStopDelay); | ||
}, | ||
touchstart: function (ev, me) { | ||
touchstart: function (ev) { | ||
G.pauseCheck = false; | ||
me.scrollbars.v.update(); | ||
me.scrollbars.h.update(); | ||
this.scrollbars.v.update(); | ||
this.scrollbars.h.update(); | ||
Events.wheel(ev, me); | ||
Events.wheel.call(this, ev); | ||
}, | ||
touchend: function (ev, me) { | ||
touchend: function (ev) { | ||
// prevents touchmove generate scroll event to call | ||
// scrollstop while the page is still momentum scrolling | ||
clearTimeout(me.cache.timerStop); | ||
clearTimeout(this.cache.timerStop); | ||
}, | ||
scrollStop: function (me) { | ||
me.fireCustomEvent('scrollstop'); | ||
scrollStop: function () { | ||
this.fireCustomEvent('scrollstop'); | ||
G.pauseCheck = false; | ||
@@ -475,15 +437,15 @@ }, | ||
wheel: function (ev, me) { | ||
var cache = me.cache, | ||
wheel: function (ev) { | ||
var cache = this.cache, | ||
cacheV = cache.v, | ||
cacheH = cache.h, | ||
preventScroll = me.settings.preventParentScroll; | ||
preventScroll = this.settings.preventParentScroll && G.isTouch; | ||
window.cancelAnimationFrame(me.scrollAnimation); | ||
window.cancelAnimationFrame(this.scrollAnimation); | ||
if(preventScroll && cacheV.enabled && cacheV.percent % 100 === 0) { | ||
me.scrollEl.scrollTop = cacheV.percent ? (cache.scrollH - cache.clientH - 1) : 1; | ||
this.scrollEl.scrollTop = cacheV.percent ? (cache.scrollH - cache.clientH - 1) : 1; | ||
} | ||
if(preventScroll && cacheH.enabled && cacheH.percent % 100 === 0) { | ||
me.scrollEl.scrollLeft = cacheH.percent ? (cache.scrollW - cache.clientW - 1) : 1; | ||
this.scrollEl.scrollLeft = cacheH.percent ? (cache.scrollW - cache.clientW - 1) : 1; | ||
} | ||
@@ -511,2 +473,3 @@ }, | ||
rtlMode = G.scrollbarSpec.rtl, | ||
enabled = false, | ||
@@ -527,2 +490,3 @@ scrollbarEl = null, | ||
var evData = ev.touches ? ev.touches[0] : ev, | ||
dragMode = settings.rtl && rtlMode === 1 && !isVertical ? -1 : 1, | ||
delta, deltaRatio; | ||
@@ -534,3 +498,3 @@ | ||
scrollEl[scrollProp] = events.dragData.scroll + deltaRatio * cache[scrollSize]; | ||
scrollEl[scrollProp] = events.dragData.scroll + deltaRatio * cache[scrollSize] * dragMode; | ||
}, | ||
@@ -585,4 +549,3 @@ | ||
update: function () { | ||
var me = this, | ||
newSize, oldSize, | ||
var newSize, oldSize, | ||
newDim, newRelPos, deltaPos; | ||
@@ -602,11 +565,11 @@ | ||
if(newSize === 1 && enabled) { | ||
me.toggle(false); | ||
this.toggle(false); | ||
} | ||
if(newSize < 1 && !enabled) { | ||
me.toggle(true); | ||
this.toggle(true); | ||
} | ||
if(trackEl && enabled) { | ||
me.style(newRelPos, deltaPos, newSize, oldSize); | ||
this.style(newRelPos, deltaPos, newSize, oldSize); | ||
} | ||
@@ -618,3 +581,3 @@ | ||
if(enabled) { | ||
me.fireEdgeEv(); | ||
this.fireEdgeEv(); | ||
} | ||
@@ -628,4 +591,9 @@ | ||
trackEl.style[ isVertical ? 'height' : 'width' ] = newSize * 100 + '%'; | ||
if (settings.rtl && !isVertical) { | ||
trackEl.style.marginRight = (1 - newSize) * 100 + '%'; | ||
} | ||
} | ||
trackEl.style[G.cssTransform] = 'translate(' + (isVertical ? '0%,' + newRelPos + '%' : newRelPos + '%' + ',0%') + ')'; | ||
trackEl.style[G.cssTransform] = 'translate(' + | ||
(isVertical ? '0%,' + newRelPos + '%' : newRelPos + '%' + ',0%') | ||
+ ')'; | ||
}, | ||
@@ -641,6 +609,9 @@ | ||
positionRatio, percent; | ||
if(sizeRatio >= 1 || !scrollS) { // no scrollbars needed | ||
return { position: 0, size: 1, percent: 0 }; | ||
} | ||
if (!isVertical && settings.rtl && rtlMode) { | ||
position = sizeDiff - position * rtlMode; | ||
} | ||
@@ -693,4 +664,4 @@ percent = 100 * position / sizeDiff; | ||
hideNativeScrollbars: function (scrollEl) { | ||
var size = G.nativeScrollbarSize, | ||
hideNativeScrollbars: function (scrollEl, isRtl) { | ||
var size = G.scrollbarSpec.width, | ||
scrollElStyle = scrollEl.style; | ||
@@ -703,3 +674,3 @@ if(size === 0) { | ||
} else { | ||
scrollElStyle.right = -size + 'px'; | ||
scrollElStyle[isRtl ? 'left' : 'right'] = -size + 'px'; | ||
scrollElStyle.bottom = -size + 'px'; | ||
@@ -732,3 +703,2 @@ return true; | ||
} | ||
wrapper.className = className; | ||
return element.appendChild(wrapper); | ||
@@ -738,9 +708,2 @@ }, | ||
containsNode: function (parent, node) { | ||
return parent.contains ? | ||
parent != node && parent.contains(node) : | ||
!!(parent.compareDocumentPosition(node) & 16); | ||
}, | ||
// Global height checker | ||
@@ -781,4 +744,5 @@ // looped to listen element changes | ||
cssTransition: cssTest('transition'), | ||
cssTransform: cssTest('transform') || '', | ||
nativeScrollbarSize: getScrollbarWidth(), | ||
cssTransform: cssTest('transform'), | ||
scrollbarSpec: getScrollbarSpec(), | ||
passiveEvent: getPassiveSupport(), | ||
@@ -792,8 +756,8 @@ instances: [], | ||
// Get scrollbars width, thanks Google Closure Library | ||
function getScrollbarWidth () { | ||
function getScrollbarSpec () { | ||
var htmlEl = document.documentElement, | ||
outerEl, innerEl, width = 0; | ||
outerEl, innerEl, width = 0, rtl = 1; // IE is reverse | ||
outerEl = document.createElement('div'); | ||
outerEl.style.cssText = 'overflow:scroll;width:50px;height:50px;position:absolute;left:-100px'; | ||
outerEl.style.cssText = 'overflow:scroll;width:50px;height:50px;position:absolute;left:-100px;direction:rtl'; | ||
@@ -806,5 +770,23 @@ innerEl = document.createElement('div'); | ||
width = outerEl.offsetWidth - outerEl.clientWidth; | ||
if (outerEl.scrollLeft > 0) { | ||
rtl = 0; // webkit is default | ||
} else { | ||
outerEl.scrollLeft = 1; | ||
if (outerEl.scrollLeft === 0) { | ||
rtl = -1; // firefox is negative | ||
} | ||
} | ||
htmlEl.removeChild(outerEl); | ||
return { width: width, rtl: rtl }; | ||
} | ||
return width; | ||
function getPassiveSupport () { | ||
var passive = false; | ||
var options = Object.defineProperty({}, 'passive', { | ||
get: function () { passive = true; }, | ||
}); | ||
window.addEventListener('test', null, options); | ||
return passive ? { capture: false, passive: true } : false; | ||
} | ||
@@ -817,8 +799,8 @@ | ||
el = document.createElement('test'), | ||
props = (prop + ' ' + ['Webkit','Moz','O','ms'].join(ucProp + ' ') + ucProp).split(' '); | ||
props = [prop, 'Webkit' + ucProp]; | ||
for (var i in props) { | ||
if(el.style[props[i]] !== undefined) { return props[i]; } | ||
} | ||
return false; | ||
return ''; | ||
} | ||
@@ -825,0 +807,0 @@ |
/*! | ||
* Optiscroll.js v2.0.1 | ||
* Optiscroll.js v3.0.0 | ||
* https://github.com/wilsonfletcher/Optiscroll/ | ||
* by Alberto Gasparin | ||
* | ||
* @copyright 2016 Wilson Fletcher | ||
* @copyright 2017 Alberto Gasparin | ||
* @license Released under MIT LICENSE | ||
*/ | ||
!function(a,b,c,d){"use strict";function e(){var a,c,d=b.documentElement,e=0;return a=b.createElement("div"),a.style.cssText="overflow:scroll;width:50px;height:50px;position:absolute;left:-100px",c=b.createElement("div"),c.style.cssText="width:100px;height:100px",a.appendChild(c),d.appendChild(a),e=a.offsetWidth-a.clientWidth,d.removeChild(a),e}function f(a){var c=a.charAt(0).toUpperCase()+a.slice(1),e=b.createElement("test"),f=(a+" "+["Webkit","Moz","O","ms"].join(c+" ")+c).split(" ");for(var g in f)if(e.style[f[g]]!==d)return f[g];return!1}function g(a,b,c){var d=a.className.split(/\s+/),e=d.indexOf(b);c?~e||d.push(b):~e&&d.splice(e,1),a.className=d.join(" ")}function h(a,b,c){for(var e in b)!b.hasOwnProperty(e)||a[e]!==d&&c||(a[e]=b[e]);return a}function i(a,b,c){var d,e;if(a.length)for(d=0,e=a.length;e>d;d++)a[d][b].apply(a[d],c);else for(d in a)a[d][b].apply(a[d],c)}function j(a,b){var c,d;return function(){var e=this,f=Date.now(),g=arguments;c&&c+b>f?(clearTimeout(d),d=setTimeout(function(){c=f,a.apply(e,g)},b)):(c=f,a.apply(e,g))}}"function"==typeof a.CustomEvent||function(a){function c(a,c){c=c||{bubbles:!1,cancelable:!1,detail:d};var e=b.createEvent("CustomEvent");return e.initCustomEvent(a,c.bubbles,c.cancelable,c.detail),e}c.prototype=a.Event.prototype,a.CustomEvent=c}(a),a.requestAnimationFrame||function(a){var b=0;a.requestAnimationFrame=function(a){var d=Date.now(),e=c.max(b+16,d);return setTimeout(function(){a(b=e)},e-d)},a.cancelAnimationFrame=clearTimeout}(a);var k=function q(a,b){return new q.Instance(a,b||{})},l=k.globalSettings={scrollMinUpdateInterval:25,checkFrequency:1e3,pauseCheck:!1};k.defaults={preventParentScroll:!1,forceScrollbars:!1,scrollStopDelay:300,maxTrackSize:95,minTrackSize:5,draggableTracks:!0,autoUpdate:!0,classPrefix:"optiscroll-"},k.Instance=function(a,b){var c=this;c.element=a,c.settings=h(h({},k.defaults),b||{}),c.cache={},c.init()},k.Instance.prototype={init:function(){var a=this,b=a.settings,c=!1;a.scrollEl=o.createWrapper(a.element,b.classPrefix+"content"),g(a.element,"is-enabled",!0),a.scrollbars={v:n("v",a),h:n("h",a)},(p.nativeScrollbarSize||b.forceScrollbars)&&(c=o.hideNativeScrollbars(a.scrollEl)),c&&i(a.scrollbars,"create"),p.isTouch&&b.preventParentScroll&&g(a.element,b.classPrefix+"prevent",!0),a.update(),a.bind(),b.autoUpdate&&p.instances.push(a),b.autoUpdate&&!p.checkTimer&&o.checkLoop()},bind:function(){var a=this,b=a.listeners={},c=a.scrollEl;b.scroll=j(function(b){m.scroll(b,a)},l.scrollMinUpdateInterval),p.isTouch&&(b.touchstart=function(b){m.touchstart(b,a)},b.touchend=function(b){m.touchend(b,a)}),b.mousewheel=b.wheel=function(b){m.wheel(b,a)};for(var d in b)c.addEventListener(d,b[d])},update:function(){var a=this,c=a.cache.clientH,e=a.scrollEl,f=a.cache,g=e.scrollHeight,h=e.clientHeight,j=e.scrollWidth,k=e.clientWidth;if(g!==f.scrollH||h!==f.clientH||j!==f.scrollW||k!==f.clientW){if(f.scrollH=g,f.clientH=h,f.scrollW=j,f.clientW=k,c!==d){if(0===g&&0===h&&!o.containsNode(b.body,a.element))return a.destroy(),!1;a.fireCustomEvent("sizechange")}i(a.scrollbars,"update")}},scrollTo:function(a,b,c){var d,e,f,g,h=this,i=h.cache;p.pauseCheck=!0,h.update(),d=h.scrollEl.scrollLeft,e=h.scrollEl.scrollTop,f=+a,"left"===a&&(f=0),"right"===a&&(f=i.scrollW-i.clientW),a===!1&&(f=d),g=+b,"top"===b&&(g=0),"bottom"===b&&(g=i.scrollH-i.clientH),b===!1&&(g=e),h.animateScroll(d,f,e,g,+c)},scrollIntoView:function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o,q=this,r=q.scrollEl;p.pauseCheck=!0,q.update(),"string"==typeof a?a=r.querySelector(a):a.length&&a.jquery&&(a=a[0]),"number"==typeof c&&(c={top:c,right:c,bottom:c,left:c}),c=c||{},d=a.getBoundingClientRect(),e=r.getBoundingClientRect(),l=n=r.scrollLeft,m=o=r.scrollTop,j=l+d.left-e.left,k=m+d.top-e.top,f=j-(c.left||0),g=k-(c.top||0),h=j+d.width-q.cache.clientW+(c.right||0),i=k+d.height-q.cache.clientH+(c.bottom||0),l>f&&(n=f),h>l&&(n=h),m>g&&(o=g),i>m&&(o=i),q.animateScroll(l,n,m,o,+b)},animateScroll:function(b,d,e,f,g){var h=this,i=h.scrollEl,j=Date.now();if(d!==b||f!==e){if(0===g)return i.scrollLeft=d,void(i.scrollTop=f);isNaN(g)&&(g=15*c.pow(c.max(c.abs(d-b),c.abs(f-e)),.54)),function k(){var l=c.min(1,(Date.now()-j)/g),m=o.easingFunction(l);f!==e&&(i.scrollTop=~~(m*(f-e))+e),d!==b&&(i.scrollLeft=~~(m*(d-b))+b),h.scrollAnimation=1>l?a.requestAnimationFrame(k):null}()}},destroy:function(){var b,c=this,d=c.element,e=c.scrollEl,f=c.listeners,h=p.instances.indexOf(c);if(c.scrollEl){for(var j in f)e.removeEventListener(j,f[j]);for(i(c.scrollbars,"remove");b=e.childNodes[0];)d.insertBefore(b,e);d.removeChild(e),c.scrollEl=null,g(d,c.settings.classPrefix+"prevent",!1),g(d,"is-enabled",!1),h>-1&&a.requestAnimationFrame(function(){p.instances.splice(h,1)})}},fireCustomEvent:function(a){var b,c=this,d=c.cache,e=d.scrollH,f=d.scrollW;b={scrollbarV:h({},d.v),scrollbarH:h({},d.h),scrollTop:d.v.position*e,scrollLeft:d.h.position*f,scrollBottom:(1-d.v.position-d.v.size)*e,scrollRight:(1-d.h.position-d.h.size)*f,scrollWidth:f,scrollHeight:e,clientWidth:d.clientW,clientHeight:d.clientH},c.element.dispatchEvent(new CustomEvent(a,{detail:b}))}};var m={scroll:function(a,b){p.pauseCheck||b.fireCustomEvent("scrollstart"),p.pauseCheck=!0,b.scrollbars.v.update(),b.scrollbars.h.update(),b.fireCustomEvent("scroll"),clearTimeout(b.cache.timerStop),b.cache.timerStop=setTimeout(function(){m.scrollStop(b)},b.settings.scrollStopDelay)},touchstart:function(a,b){p.pauseCheck=!1,b.scrollbars.v.update(),b.scrollbars.h.update(),m.wheel(a,b)},touchend:function(a,b){clearTimeout(b.cache.timerStop)},scrollStop:function(a){a.fireCustomEvent("scrollstop"),p.pauseCheck=!1},wheel:function(b,c){var d=c.cache,e=d.v,f=d.h,g=c.settings.preventParentScroll;a.cancelAnimationFrame(c.scrollAnimation),g&&e.enabled&&e.percent%100===0&&(c.scrollEl.scrollTop=e.percent?d.scrollH-d.clientH-1:1),g&&f.enabled&&f.percent%100===0&&(c.scrollEl.scrollLeft=f.percent?d.scrollW-d.clientW-1:1)}},n=function(a,d){var e="v"===a,f=d.element,i=d.scrollEl,j=d.settings,k=d.cache,l=k[a]={},m=e?"H":"W",n="client"+m,o="scroll"+m,q=e?"scrollTop":"scrollLeft",r=e?["top","bottom"]:["left","right"],s=!1,t=null,u=null,v={dragData:null,dragStart:function(a){var b=a.touches?a.touches[0]:a;v.dragData={x:b.pageX,y:b.pageY,scroll:i[q]},v.bind(!0)},dragMove:function(a){var b,c,d=a.touches?a.touches[0]:a;a.preventDefault(),b=e?d.pageY-v.dragData.y:d.pageX-v.dragData.x,c=b/k[n],i[q]=v.dragData.scroll+c*k[o]},dragEnd:function(){v.dragData=null,v.bind(!1)},bind:function(a){var c=(a?"add":"remove")+"EventListener",d=p.isTouch?["touchmove","touchend"]:["mousemove","mouseup"];b[c](d[0],v.dragMove),b[c](d[1],v.dragEnd)}};return{toggle:function(b){s=b,u&&g(f,"has-"+a+"track",s),l.enabled=s},create:function(){var c=p.isTouch?"touchstart":"mousedown";t=b.createElement("div"),u=b.createElement("b"),t.className=j.classPrefix+a,u.className=j.classPrefix+a+"track",t.appendChild(u),f.appendChild(t),j.draggableTracks&&u.addEventListener(c,v.dragStart)},update:function(){var a,b,d,e,f,g=this;(s||k[n]!==k[o])&&(d=this.calc(),a=d.size,b=l.size,e=1/a*d.position*100,f=c.abs(d.position-(l.position||0))*k[n],1===a&&s&&g.toggle(!1),1>a&&!s&&g.toggle(!0),u&&s&&g.style(e,f,a,b),l=h(l,d),s&&g.fireEdgeEv())},style:function(a,b,c,d){c!==d&&(u.style[e?"height":"width"]=100*c+"%"),u.style[p.cssTransform]="translate("+(e?"0%,"+a+"%":a+"%,0%")+")"},calc:function(){var a,b,d=i[q],e=k[n],f=k[o],g=e/f,h=f-e;return g>=1||!f?{position:0,size:1,percent:0}:(b=100*d/h,1>=d&&(b=0),d>=h-1&&(b=100),g=c.max(g,j.minTrackSize/100),g=c.min(g,j.maxTrackSize/100),a=(1-g)*(b/100),{position:a,size:g,percent:b})},fireEdgeEv:function(){var a=l.percent;l.was!==a&&a%100===0&&(d.fireCustomEvent("scrollreachedge"),d.fireCustomEvent("scrollreach"+r[a/100])),l.was=a},remove:function(){this.toggle(!1),t&&(t.parentNode.removeChild(t),t=null)}}},o={hideNativeScrollbars:function(a){var b=p.nativeScrollbarSize,c=a.style;if(0===b){var d=Date.now();return a.setAttribute("data-scroll",d),o.addCssRule('[data-scroll="'+d+'"]::-webkit-scrollbar',"display:none;width:0;height:0;")}return c.right=-b+"px",c.bottom=-b+"px",!0},addCssRule:function(a,c){var d=b.getElementById("scroll-sheet");d||(d=b.createElement("style"),d.id="scroll-sheet",d.appendChild(b.createTextNode("")),b.head.appendChild(d));try{return d.sheet.insertRule(a+" {"+c+"}",0),!0}catch(e){return}},createWrapper:function(a,c){for(var d,e=b.createElement("div");d=a.childNodes[0];)e.appendChild(d);return e.className=c,a.appendChild(e)},containsNode:function(a,b){return a.contains?a!=b&&a.contains(b):!!(16&a.compareDocumentPosition(b))},checkLoop:function(){return p.instances.length?(p.pauseCheck||i(p.instances,"update"),void(l.checkFrequency&&(p.checkTimer=setTimeout(function(){o.checkLoop()},l.checkFrequency)))):void(p.checkTimer=null)},easingFunction:function(a){return--a*a*a+1}},p=k.G={isTouch:"ontouchstart"in a,cssTransition:f("transition"),cssTransform:f("transform")||"",nativeScrollbarSize:e(),instances:[],checkTimer:null,pauseCheck:!1};"function"==typeof define&&define.amd&&define(function(){return k}),"undefined"!=typeof module&&module.exports&&(module.exports=k),a.Optiscroll=k}(window,document,Math); | ||
!function(a,b,c,d){"use strict";function e(){var a,c,d=b.documentElement,e=0,f=1;return a=b.createElement("div"),a.style.cssText="overflow:scroll;width:50px;height:50px;position:absolute;left:-100px;direction:rtl",c=b.createElement("div"),c.style.cssText="width:100px;height:100px",a.appendChild(c),d.appendChild(a),e=a.offsetWidth-a.clientWidth,a.scrollLeft>0?f=0:(a.scrollLeft=1,0===a.scrollLeft&&(f=-1)),d.removeChild(a),{width:e,rtl:f}}function f(){var b=!1,c=Object.defineProperty({},"passive",{get:function(){b=!0}});return a.addEventListener("test",null,c),!!b&&{capture:!1,passive:!0}}function g(a){var c=a.charAt(0).toUpperCase()+a.slice(1),e=b.createElement("test"),f=[a,"Webkit"+c];for(var g in f)if(e.style[f[g]]!==d)return f[g];return""}function h(a,b,c){var d=a.className.split(/\s+/),e=d.indexOf(b);c?~e||d.push(b):~e&&d.splice(e,1),a.className=d.join(" ")}function i(a,b,c){for(var e in b)!b.hasOwnProperty(e)||a[e]!==d&&c||(a[e]=b[e]);return a}function j(a,b,c){var d,e;if(a.length)for(d=0,e=a.length;d<e;d++)a[d][b].apply(a[d],c);else for(d in a)a[d][b].apply(a[d],c)}function k(a,b){var c,d;return function(){var e=this,f=Date.now(),g=arguments;c&&f<c+b?(clearTimeout(d),d=setTimeout(function(){c=f,a.apply(e,g)},b)):(c=f,a.apply(e,g))}}var l=function a(b,c){return new a.Instance(b,c||{})},m=l.globalSettings={scrollMinUpdateInterval:25,checkFrequency:1e3,pauseCheck:!1};l.defaults={preventParentScroll:!1,forceScrollbars:!1,scrollStopDelay:300,maxTrackSize:95,minTrackSize:5,draggableTracks:!0,autoUpdate:!0,classPrefix:"optiscroll-",wrapContent:!0,rtl:!1},l.Instance=function(b,c){this.element=b,this.settings=i(i({},l.defaults),c||{}),"boolean"!=typeof c.rtl&&(this.settings.rtl="rtl"===a.getComputedStyle(b).direction),this.cache={},this.init()},l.Instance.prototype={init:function(){var a=this.element,b=this.settings,c=!1,d=this.scrollEl=b.wrapContent?p.createWrapper(a):a.firstElementChild;h(d,b.classPrefix+"content",!0),h(a,"is-enabled"+(b.rtl?" is-rtl":""),!0),this.scrollbars={v:o("v",this),h:o("h",this)},(q.scrollbarSpec.width||b.forceScrollbars)&&(c=p.hideNativeScrollbars(d,b.rtl)),c&&j(this.scrollbars,"create"),q.isTouch&&b.preventParentScroll&&h(a,b.classPrefix+"prevent",!0),this.update(),this.bind(),b.autoUpdate&&q.instances.push(this),b.autoUpdate&&!q.checkTimer&&p.checkLoop()},bind:function(){var a=this.listeners={},b=this.scrollEl;a.scroll=k(n.scroll.bind(this),m.scrollMinUpdateInterval),q.isTouch&&(a.touchstart=n.touchstart.bind(this),a.touchend=n.touchend.bind(this)),a.mousewheel=a.wheel=n.wheel.bind(this);for(var c in a)b.addEventListener(c,a[c],q.passiveEvent)},update:function(){var a=this.scrollEl,c=this.cache,e=c.clientH,f=a.scrollHeight,g=a.clientHeight,h=a.scrollWidth,i=a.clientWidth;if(f!==c.scrollH||g!==c.clientH||h!==c.scrollW||i!==c.clientW){if(c.scrollH=f,c.clientH=g,c.scrollW=h,c.clientW=i,e!==d){if(0===f&&0===g&&!b.body.contains(this.element))return this.destroy(),!1;this.fireCustomEvent("sizechange")}j(this.scrollbars,"update")}},scrollTo:function(a,b,c){var d,e,f,g,h=this.cache;q.pauseCheck=!0,this.update(),d=this.scrollEl.scrollLeft,e=this.scrollEl.scrollTop,f=+a,"left"===a&&(f=0),"right"===a&&(f=h.scrollW-h.clientW),a===!1&&(f=d),g=+b,"top"===b&&(g=0),"bottom"===b&&(g=h.scrollH-h.clientH),b===!1&&(g=e),this.animateScroll(d,f,e,g,+c)},scrollIntoView:function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p=this.scrollEl;q.pauseCheck=!0,this.update(),"string"==typeof a?a=p.querySelector(a):a.length&&a.jquery&&(a=a[0]),"number"==typeof c&&(c={top:c,right:c,bottom:c,left:c}),c=c||{},d=a.getBoundingClientRect(),e=p.getBoundingClientRect(),l=n=p.scrollLeft,m=o=p.scrollTop,j=l+d.left-e.left,k=m+d.top-e.top,f=j-(c.left||0),g=k-(c.top||0),h=j+d.width-this.cache.clientW+(c.right||0),i=k+d.height-this.cache.clientH+(c.bottom||0),f<l&&(n=f),h>l&&(n=h),g<m&&(o=g),i>m&&(o=i),this.animateScroll(l,n,m,o,+b)},animateScroll:function(b,d,e,f,g){var h=this,i=this.scrollEl,j=Date.now();if(d!==b||f!==e){if(0===g)return i.scrollLeft=d,void(i.scrollTop=f);isNaN(g)&&(g=15*c.pow(c.max(c.abs(d-b),c.abs(f-e)),.54)),function k(){var l=c.min(1,(Date.now()-j)/g),m=p.easingFunction(l);f!==e&&(i.scrollTop=~~(m*(f-e))+e),d!==b&&(i.scrollLeft=~~(m*(d-b))+b),h.scrollAnimation=l<1?a.requestAnimationFrame(k):null}()}},destroy:function(){var b,c=this,d=this.element,e=this.scrollEl,f=this.listeners;if(this.scrollEl){for(var g in f)e.removeEventListener(g,f[g]);if(j(this.scrollbars,"remove"),!this.settings.contentElement){for(;b=e.childNodes[0];)d.insertBefore(b,e);d.removeChild(e),this.scrollEl=null}h(d,this.settings.classPrefix+"prevent",!1),h(d,"is-enabled",!1),a.requestAnimationFrame(function(){var a=q.instances.indexOf(c);a>-1&&q.instances.splice(a,1)})}},fireCustomEvent:function(a){var c,d=this.cache,e=d.scrollH,f=d.scrollW;c={scrollbarV:i({},d.v),scrollbarH:i({},d.h),scrollTop:d.v.position*e,scrollLeft:d.h.position*f,scrollBottom:(1-d.v.position-d.v.size)*e,scrollRight:(1-d.h.position-d.h.size)*f,scrollWidth:f,scrollHeight:e,clientWidth:d.clientW,clientHeight:d.clientH};var g;"function"===CustomEvent?g=new CustomEvent(a,{detail:c}):(g=b.createEvent("CustomEvent"),g.initCustomEvent(a,!1,!1,c)),this.element.dispatchEvent(g)}};var n={scroll:function(a){q.pauseCheck||this.fireCustomEvent("scrollstart"),q.pauseCheck=!0,this.scrollbars.v.update(),this.scrollbars.h.update(),this.fireCustomEvent("scroll"),clearTimeout(this.cache.timerStop),this.cache.timerStop=setTimeout(n.scrollStop.bind(this),this.settings.scrollStopDelay)},touchstart:function(a){q.pauseCheck=!1,this.scrollbars.v.update(),this.scrollbars.h.update(),n.wheel.call(this,a)},touchend:function(a){clearTimeout(this.cache.timerStop)},scrollStop:function(){this.fireCustomEvent("scrollstop"),q.pauseCheck=!1},wheel:function(b){var c=this.cache,d=c.v,e=c.h,f=this.settings.preventParentScroll&&q.isTouch;a.cancelAnimationFrame(this.scrollAnimation),f&&d.enabled&&d.percent%100==0&&(this.scrollEl.scrollTop=d.percent?c.scrollH-c.clientH-1:1),f&&e.enabled&&e.percent%100==0&&(this.scrollEl.scrollLeft=e.percent?c.scrollW-c.clientW-1:1)}},o=function(a,d){var e="v"===a,f=d.element,g=d.scrollEl,j=d.settings,k=d.cache,l=k[a]={},m=e?"H":"W",n="client"+m,o="scroll"+m,p=e?"scrollTop":"scrollLeft",r=e?["top","bottom"]:["left","right"],s=q.scrollbarSpec.rtl,t=!1,u=null,v=null,w={dragData:null,dragStart:function(a){var b=a.touches?a.touches[0]:a;w.dragData={x:b.pageX,y:b.pageY,scroll:g[p]},w.bind(!0)},dragMove:function(a){var b,c,d=a.touches?a.touches[0]:a,f=j.rtl&&1===s&&!e?-1:1;a.preventDefault(),b=e?d.pageY-w.dragData.y:d.pageX-w.dragData.x,c=b/k[n],g[p]=w.dragData.scroll+c*k[o]*f},dragEnd:function(){w.dragData=null,w.bind(!1)},bind:function(a){var c=(a?"add":"remove")+"EventListener",d=q.isTouch?["touchmove","touchend"]:["mousemove","mouseup"];b[c](d[0],w.dragMove),b[c](d[1],w.dragEnd)}};return{toggle:function(b){t=b,v&&h(f,"has-"+a+"track",t),l.enabled=t},create:function(){var c=q.isTouch?"touchstart":"mousedown";u=b.createElement("div"),v=b.createElement("b"),u.className=j.classPrefix+a,v.className=j.classPrefix+a+"track",u.appendChild(v),f.appendChild(u),j.draggableTracks&&v.addEventListener(c,w.dragStart)},update:function(){var a,b,d,e,f;(t||k[n]!==k[o])&&(d=this.calc(),a=d.size,b=l.size,e=1/a*d.position*100,f=c.abs(d.position-(l.position||0))*k[n],1===a&&t&&this.toggle(!1),a<1&&!t&&this.toggle(!0),v&&t&&this.style(e,f,a,b),l=i(l,d),t&&this.fireEdgeEv())},style:function(a,b,c,d){c!==d&&(v.style[e?"height":"width"]=100*c+"%",j.rtl&&!e&&(v.style.marginRight=100*(1-c)+"%")),v.style[q.cssTransform]="translate("+(e?"0%,"+a+"%":a+"%,0%")+")"},calc:function(){var a,b,d=g[p],f=k[n],h=k[o],i=f/h,l=h-f;return i>=1||!h?{position:0,size:1,percent:0}:(!e&&j.rtl&&s&&(d=l-d*s),b=100*d/l,d<=1&&(b=0),d>=l-1&&(b=100),i=c.max(i,j.minTrackSize/100),i=c.min(i,j.maxTrackSize/100),a=b/100*(1-i),{position:a,size:i,percent:b})},fireEdgeEv:function(){var a=l.percent;l.was!==a&&a%100==0&&(d.fireCustomEvent("scrollreachedge"),d.fireCustomEvent("scrollreach"+r[a/100])),l.was=a},remove:function(){this.toggle(!1),u&&(u.parentNode.removeChild(u),u=null)}}},p={hideNativeScrollbars:function(a,b){var c=q.scrollbarSpec.width,d=a.style;if(0===c){var e=Date.now();return a.setAttribute("data-scroll",e),p.addCssRule('[data-scroll="'+e+'"]::-webkit-scrollbar',"display:none;width:0;height:0;")}return d[b?"left":"right"]=-c+"px",d.bottom=-c+"px",!0},addCssRule:function(a,c){var d=b.getElementById("scroll-sheet");d||(d=b.createElement("style"),d.id="scroll-sheet",d.appendChild(b.createTextNode("")),b.head.appendChild(d));try{return d.sheet.insertRule(a+" {"+c+"}",0),!0}catch(a){return}},createWrapper:function(a,c){for(var d,e=b.createElement("div");d=a.childNodes[0];)e.appendChild(d);return a.appendChild(e)},checkLoop:function(){if(!q.instances.length)return void(q.checkTimer=null);q.pauseCheck||j(q.instances,"update"),m.checkFrequency&&(q.checkTimer=setTimeout(function(){p.checkLoop()},m.checkFrequency))},easingFunction:function(a){return--a*a*a+1}},q=l.G={isTouch:"ontouchstart"in a,cssTransition:g("transition"),cssTransform:g("transform"),scrollbarSpec:e(),passiveEvent:f(),instances:[],checkTimer:null,pauseCheck:!1};"function"==typeof define&&define.amd&&define(function(){return l}),"undefined"!=typeof module&&module.exports&&(module.exports=l),a.Optiscroll=l}(window,document,Math); |
@@ -23,5 +23,4 @@ /*global exports:true, require:true */ | ||
"* https://github.com/wilsonfletcher/Optiscroll/\n"+ | ||
"* by Alberto Gasparin\n"+ | ||
"* \n"+ | ||
"* @copyright <%= grunt.template.today('yyyy') %> Wilson Fletcher\n"+ | ||
"* @copyright <%= grunt.template.today('yyyy') %> Alberto Gasparin\n"+ | ||
"* @license Released under MIT LICENSE\n"+ | ||
@@ -34,3 +33,2 @@ "*/\n\n", | ||
'src/intro.js', | ||
'src/polyfills/*.js', | ||
'src/optiscroll.js', | ||
@@ -96,3 +94,3 @@ 'src/events.js', | ||
options: { | ||
browsers: ['last 3 versions', 'IE 9'] | ||
browsers: ['last 3 versions', 'IE 11'] | ||
}, | ||
@@ -99,0 +97,0 @@ dist: { |
@@ -9,3 +9,3 @@ { | ||
], | ||
"version": "2.0.1", | ||
"version": "3.0.0", | ||
"homepage": "https://github.com/wilsonfletcher/optiscroll", | ||
@@ -12,0 +12,0 @@ "repository": { |
# Optiscroll | ||
Optiscroll is an tiny (**9kB**) and highly optimized custom scrollbar library for modern web apps. | ||
Optiscroll is an tiny (9kB min / **3.9kB gzip**) and highly optimized custom scrollbar library for modern web apps. | ||
Optiscroll aims to be as light as possible in order to not affect the performace of your webapp. Optiscroll does **not** replace the scrolling logic with Javascript. It only hides native scrollbars and allows you to style the fake scrollbars as you like. Moreover, Optiscroll adds custom events and methods to extend browser scroll functionalities. | ||
Optiscroll aims to be as light as possible in order to not affect the performance of your webapp. Optiscroll does **not** replace the scrolling logic with Javascript. It only hides native scrollbars and allows you to style the fake scrollbars as you like. Moreover, Optiscroll adds custom events and methods to extend browser scroll functionalities. | ||
@@ -14,2 +14,3 @@ | ||
- Vertical and horizontal scrollbars support | ||
- Both `ltr` and `rtl` text direction support (with smart detection) | ||
- Nested scrollbars support | ||
@@ -26,3 +27,3 @@ - Custom events | ||
Optiscroll works in **all modern browsers** (IE9 and above). Keep in mind that if Optiscroll does not work your web page will still fallback to default scrollbars. | ||
Optiscroll works in **all modern browsers** (IE11 and above). Keep in mind that if Optiscroll does not work your web page will still fallback to default scrollbars. | ||
@@ -37,4 +38,6 @@ | ||
``` | ||
```sh | ||
bower install optiscroll --save | ||
# or | ||
npm install optiscroll --save | ||
``` | ||
@@ -54,3 +57,3 @@ | ||
Add Optiscroll containers around your content. The library does **not** add them for you. | ||
Optiscroll automatically wraps your content with a scrollable element, but if you need more control you can create your own element and set `wrapContent: false`. | ||
@@ -66,3 +69,3 @@ ```html | ||
```javascript | ||
```js | ||
// plain JS version | ||
@@ -82,14 +85,16 @@ var element = document.querySelector('#scroll') | ||
|-------------|---------|---------- | ||
| preventParentScroll | false | Prevents scrolling parent container (or body) when scroll reach top or bottom. Works also on iOS preventing the page bounce. | ||
| preventParentScroll | false | Mobile only, prevents scrolling parent container (or body) when scroll reach top or bottom (known as iOS page bounce fix). | ||
| forceScrollbars | false | Use custom scrollbars also on iOS, Android and OSX (w/ trackpad) | ||
| scrollStopDelay | 300 (ms) | Time before presuming that the scroll is ended, then fire `scrollstop` event | ||
| scrollStopDelay | 300 (ms) | Time before presuming that the scroll is ended, after which `scrollstop` event is fired | ||
| maxTrackSize | 95 (%) | Maximum size (width or height) of the track | ||
| minTrackSize | 5 (%) | Minimum size (width or height) of the track | ||
| draggableTracks | true | Allow track dragging to scroll | ||
| draggableTracks | true | Allow scroll through tracks dragging | ||
| autoUpdate | true | Scrollbars will be automatically updated on size or content changes | ||
| classPrefix | 'optiscroll-' | Custom class prefix for optiscroll elements | ||
| wrapContent | true | Optiscroll will generate an element to wrap your content. If not, the first child will be used | ||
| rtl | false | Optiscroll will automatically detect if the content is rtl, however you can force it if the detection fails | ||
Examples: | ||
```javascript | ||
```js | ||
// change min and max track size - plain JS version | ||
@@ -120,3 +125,3 @@ var myOptiscrollInstance = new Optiscroll(element, { maxTrackSize: 50, minTrackSize: 20 }); | ||
```javascript | ||
```js | ||
// scroll vertically by 500px (scroll duration will be auto) - plain JS version | ||
@@ -148,3 +153,3 @@ myOptiscrollInstance.scrollTo(false, 500); | ||
```javascript | ||
```js | ||
// scrolls element with id anchor-1 into view (scroll duration will be auto) - plain JS version | ||
@@ -208,3 +213,3 @@ myOptiscrollInstance.scrollIntoView('#anchor-1'); | ||
```javascript | ||
```js | ||
// plain JS listener | ||
@@ -232,10 +237,9 @@ document.querySelector('#scroll').addEventListener('scrollreachtop', function (ev) { | ||
| scrollMinUpdateInterval | 25 (ms) | By default the scrollbars position is updated up to 40 times per second. By increasing this time the scroll tracks will be updated less frequently. The smallest interval is 16, which means scroll tracks are updated up to 60 times per second. | ||
| checkFrequency | 1000 (ms) | How often scroll areas are checked for size or content changes. To disable the check timer (and the scrollbars auto update feature) set this value to 0. | ||
| checkFrequency | 1000 (ms) | How often scroll areas are checked for size or content changes. To disable the timer (and stop all scrollbars to auto update) set this value to 0. | ||
Examples: | ||
```javascript | ||
```js | ||
// set the scrollbar update interval to 30 FPS | ||
Optiscroll.globalSettings.scrollMinUpdateInterval = 1000 / 30; | ||
// disable auto update for all Optiscroll instances | ||
@@ -246,3 +250,18 @@ Optiscroll.globalSettings.checkFrequency = 0; | ||
## SCSS styling options | ||
If you want more control over the styling, you can set these SCSS variables before including `scss/optiscroll.scss` in your `.scss` file: | ||
```scss | ||
$optiscroll-namespace: 'optiscroll'; // custom css class namespace | ||
$optiscroll-classPrefix: $optiscroll-namespace + '-'; // same as js classPrefix option | ||
$optiscroll-forceScrollbarV: false; // css trick to force vertical scrollbars | ||
$optiscroll-forceScrollbarH: false; // css trick to force horizontal scrollbars | ||
$optiscroll-supportRtl: true; // enable/disable rules for rtl support | ||
$optiscroll-defaultStyle: true; // enable/disable default styling | ||
``` | ||
## Known limitations | ||
@@ -256,2 +275,7 @@ | ||
## Why still timers to check size/content changes? | ||
Even if there are clever tricks to detect an element size change (eg iframes) there is still no reliable way to detect overflow changes (the event is Firefox only and Chrome has deprecated it). So, timers are still the most performing solution because they allow a more fine grained control. | ||
## Running Tests | ||
@@ -264,32 +288,29 @@ | ||
## Upgrading | ||
## Upgrade from v1 to v2 | ||
#### From v2 to v3 | ||
No changes should be required, just dropped IE < 11 support and added bunch of new features. | ||
**Options changes** | ||
#### From v1 to v2 | ||
- `classPrefix` option no longer adds `-` to the namespace, so it allows you to pick your favourite separator (or no separator at all) for `.optiscroll*` elements. | ||
- Optiscroll now automatically wraps inner content. So, remove `.optiscroll-content` from your html (behaviour customisable on v3). | ||
- Styles organisation got a major overhaul, so my suggestion is to [go and have a look](https://github.com/albertogasparin/Optiscroll/blob/master/scss/optiscroll.scss). | ||
**HTML changes** | ||
- Optiscroll now automatically wraps inner content. So, remove `.optiscroll-content` from your html. | ||
**CSS changes** | ||
- Styles organisation got a major overhaul, so my suggestion is to [go and have a look](https://github.com/wilsonfletcher/Optiscroll/blob/master/scss/optiscroll.scss). | ||
- Tracks states class names have been renamed to `.has-vtrack`, `.has-htrack`. | ||
- `opacity` is now set on the track, no longer on the whole scrollbar. | ||
## History & Changelog | ||
[Check Github Releases page](https://github.com/albertogasparin/Optiscroll/releases) | ||
## History | ||
[Check Github Releases page](https://github.com/wilsonfletcher/Optiscroll/releases) | ||
# License | ||
This program is free software; it is distributed under an | ||
[MIT License](https://github.com/wilsonfletcher/Optiscroll/blob/master/LICENSE). | ||
[MIT License](https://github.com/albertogasparin/Optiscroll/blob/master/LICENSE). | ||
--- | ||
Copyright (c) 2016 [Wilson Fletcher](http://wilsonfletcher.com/) | ||
([Contributors](https://github.com/wilsonfletcher/Optiscroll/graphs/contributors)). | ||
Copyright (c) 2017 Alberto Gasparin | ||
Initially developed at [Wilson Fletcher design studio](http://wilsonfletcher.com/) | ||
([Contributors](https://github.com/albertogasparin/Optiscroll/graphs/contributors)). |
var Events = { | ||
scroll: function (ev, me) { | ||
scroll: function (ev) { | ||
if (!G.pauseCheck) { | ||
me.fireCustomEvent('scrollstart'); | ||
this.fireCustomEvent('scrollstart'); | ||
} | ||
G.pauseCheck = true; | ||
me.scrollbars.v.update(); | ||
me.scrollbars.h.update(); | ||
this.scrollbars.v.update(); | ||
this.scrollbars.h.update(); | ||
me.fireCustomEvent('scroll'); | ||
this.fireCustomEvent('scroll'); | ||
clearTimeout(me.cache.timerStop); | ||
me.cache.timerStop = setTimeout(function () { | ||
Events.scrollStop(me); | ||
}, me.settings.scrollStopDelay); | ||
clearTimeout(this.cache.timerStop); | ||
this.cache.timerStop = setTimeout(Events.scrollStop.bind(this), this.settings.scrollStopDelay); | ||
}, | ||
touchstart: function (ev, me) { | ||
touchstart: function (ev) { | ||
G.pauseCheck = false; | ||
me.scrollbars.v.update(); | ||
me.scrollbars.h.update(); | ||
this.scrollbars.v.update(); | ||
this.scrollbars.h.update(); | ||
Events.wheel(ev, me); | ||
Events.wheel.call(this, ev); | ||
}, | ||
touchend: function (ev, me) { | ||
touchend: function (ev) { | ||
// prevents touchmove generate scroll event to call | ||
// scrollstop while the page is still momentum scrolling | ||
clearTimeout(me.cache.timerStop); | ||
clearTimeout(this.cache.timerStop); | ||
}, | ||
scrollStop: function (me) { | ||
me.fireCustomEvent('scrollstop'); | ||
scrollStop: function () { | ||
this.fireCustomEvent('scrollstop'); | ||
G.pauseCheck = false; | ||
@@ -44,15 +42,15 @@ }, | ||
wheel: function (ev, me) { | ||
var cache = me.cache, | ||
wheel: function (ev) { | ||
var cache = this.cache, | ||
cacheV = cache.v, | ||
cacheH = cache.h, | ||
preventScroll = me.settings.preventParentScroll; | ||
preventScroll = this.settings.preventParentScroll && G.isTouch; | ||
window.cancelAnimationFrame(me.scrollAnimation); | ||
window.cancelAnimationFrame(this.scrollAnimation); | ||
if(preventScroll && cacheV.enabled && cacheV.percent % 100 === 0) { | ||
me.scrollEl.scrollTop = cacheV.percent ? (cache.scrollH - cache.clientH - 1) : 1; | ||
this.scrollEl.scrollTop = cacheV.percent ? (cache.scrollH - cache.clientH - 1) : 1; | ||
} | ||
if(preventScroll && cacheH.enabled && cacheH.percent % 100 === 0) { | ||
me.scrollEl.scrollLeft = cacheH.percent ? (cache.scrollW - cache.clientW - 1) : 1; | ||
this.scrollEl.scrollLeft = cacheH.percent ? (cache.scrollW - cache.clientW - 1) : 1; | ||
} | ||
@@ -59,0 +57,0 @@ }, |
@@ -6,4 +6,5 @@ | ||
cssTransition: cssTest('transition'), | ||
cssTransform: cssTest('transform') || '', | ||
nativeScrollbarSize: getScrollbarWidth(), | ||
cssTransform: cssTest('transform'), | ||
scrollbarSpec: getScrollbarSpec(), | ||
passiveEvent: getPassiveSupport(), | ||
@@ -17,8 +18,8 @@ instances: [], | ||
// Get scrollbars width, thanks Google Closure Library | ||
function getScrollbarWidth () { | ||
function getScrollbarSpec () { | ||
var htmlEl = document.documentElement, | ||
outerEl, innerEl, width = 0; | ||
outerEl, innerEl, width = 0, rtl = 1; // IE is reverse | ||
outerEl = document.createElement('div'); | ||
outerEl.style.cssText = 'overflow:scroll;width:50px;height:50px;position:absolute;left:-100px'; | ||
outerEl.style.cssText = 'overflow:scroll;width:50px;height:50px;position:absolute;left:-100px;direction:rtl'; | ||
@@ -31,5 +32,23 @@ innerEl = document.createElement('div'); | ||
width = outerEl.offsetWidth - outerEl.clientWidth; | ||
if (outerEl.scrollLeft > 0) { | ||
rtl = 0; // webkit is default | ||
} else { | ||
outerEl.scrollLeft = 1; | ||
if (outerEl.scrollLeft === 0) { | ||
rtl = -1; // firefox is negative | ||
} | ||
} | ||
htmlEl.removeChild(outerEl); | ||
return { width: width, rtl: rtl }; | ||
} | ||
return width; | ||
function getPassiveSupport () { | ||
var passive = false; | ||
var options = Object.defineProperty({}, 'passive', { | ||
get: function () { passive = true; }, | ||
}); | ||
window.addEventListener('test', null, options); | ||
return passive ? { capture: false, passive: true } : false; | ||
} | ||
@@ -42,8 +61,8 @@ | ||
el = document.createElement('test'), | ||
props = (prop + ' ' + ['Webkit','Moz','O','ms'].join(ucProp + ' ') + ucProp).split(' '); | ||
props = [prop, 'Webkit' + ucProp]; | ||
for (var i in props) { | ||
if(el.style[props[i]] !== undefined) { return props[i]; } | ||
} | ||
return false; | ||
return ''; | ||
} | ||
@@ -50,0 +69,0 @@ |
@@ -29,2 +29,4 @@ | ||
classPrefix: 'optiscroll-', | ||
wrapContent: true, | ||
rtl: false, | ||
}; | ||
@@ -35,10 +37,11 @@ | ||
Optiscroll.Instance = function (element, options) { | ||
var me = this; | ||
// instance variables | ||
me.element = element; | ||
me.settings = _extend(_extend({}, Optiscroll.defaults), options || {}); | ||
me.cache = {}; | ||
this.element = element; | ||
this.settings = _extend(_extend({}, Optiscroll.defaults), options || {}); | ||
if (typeof options.rtl !== 'boolean') { | ||
this.settings.rtl = window.getComputedStyle(element).direction === 'rtl'; | ||
} | ||
this.cache = {}; | ||
me.init(); | ||
this.init(); | ||
}; | ||
@@ -52,37 +55,41 @@ | ||
init: function () { | ||
var me = this, | ||
settings = me.settings, | ||
var element = this.element, | ||
settings = this.settings, | ||
shouldCreateScrollbars = false; | ||
var scrollEl = this.scrollEl = settings.wrapContent | ||
? Utils.createWrapper(element) | ||
: element.firstElementChild; | ||
me.scrollEl = Utils.createWrapper(me.element, settings.classPrefix + 'content'); | ||
toggleClass(me.element, 'is-enabled', true); | ||
toggleClass(scrollEl, settings.classPrefix + 'content', true); | ||
toggleClass(element, 'is-enabled' + (settings.rtl ? ' is-rtl' : ''), true); | ||
// initialize scrollbars | ||
me.scrollbars = { | ||
v: Scrollbar('v', me), | ||
h: Scrollbar('h', me), | ||
this.scrollbars = { | ||
v: Scrollbar('v', this), | ||
h: Scrollbar('h', this), | ||
}; | ||
// create DOM scrollbars only if they have size or if it's forced | ||
if(G.nativeScrollbarSize || settings.forceScrollbars) { | ||
shouldCreateScrollbars = Utils.hideNativeScrollbars(me.scrollEl); | ||
if(G.scrollbarSpec.width || settings.forceScrollbars) { | ||
shouldCreateScrollbars = Utils.hideNativeScrollbars(scrollEl, settings.rtl); | ||
} | ||
if(shouldCreateScrollbars) { | ||
_invoke(me.scrollbars, 'create'); | ||
_invoke(this.scrollbars, 'create'); | ||
} | ||
if(G.isTouch && settings.preventParentScroll) { | ||
toggleClass(me.element, settings.classPrefix + 'prevent', true); | ||
toggleClass(element, settings.classPrefix + 'prevent', true); | ||
} | ||
// calculate scrollbars | ||
me.update(); | ||
this.update(); | ||
// bind container events | ||
me.bind(); | ||
this.bind(); | ||
// add instance to global array for timed check | ||
if(settings.autoUpdate) { | ||
G.instances.push(me); | ||
G.instances.push(this); | ||
} | ||
@@ -100,21 +107,18 @@ | ||
bind: function () { | ||
var me = this, | ||
listeners = me.listeners = {}, | ||
scrollEl = me.scrollEl; | ||
var listeners = this.listeners = {}, | ||
scrollEl = this.scrollEl; | ||
// scroll event binding | ||
listeners.scroll = _throttle(function (ev) { | ||
Events.scroll(ev, me); | ||
}, GS.scrollMinUpdateInterval); | ||
listeners.scroll = _throttle(Events.scroll.bind(this), GS.scrollMinUpdateInterval); | ||
if(G.isTouch) { | ||
listeners.touchstart = function (ev) { Events.touchstart(ev, me); }; | ||
listeners.touchend = function (ev) { Events.touchend(ev, me); }; | ||
listeners.touchstart = Events.touchstart.bind(this); | ||
listeners.touchend = Events.touchend.bind(this); | ||
} | ||
// Safari does not support wheel event | ||
listeners.mousewheel = listeners.wheel = function (ev) { Events.wheel(ev, me); }; | ||
listeners.mousewheel = listeners.wheel = Events.wheel.bind(this); | ||
for (var ev in listeners) { | ||
scrollEl.addEventListener(ev, listeners[ev]); | ||
scrollEl.addEventListener(ev, listeners[ev], G.passiveEvent); | ||
} | ||
@@ -128,6 +132,5 @@ | ||
update: function () { | ||
var me = this, | ||
oldcH = me.cache.clientH, | ||
scrollEl = me.scrollEl, | ||
cache = me.cache, | ||
var scrollEl = this.scrollEl, | ||
cache = this.cache, | ||
oldcH = cache.clientH, | ||
sH = scrollEl.scrollHeight, | ||
@@ -150,8 +153,8 @@ cH = scrollEl.clientHeight, | ||
// if the element is no more in the DOM | ||
if(sH === 0 && cH === 0 && !Utils.containsNode(document.body, me.element)) { | ||
me.destroy(); | ||
if(sH === 0 && cH === 0 && !document.body.contains(this.element)) { | ||
this.destroy(); | ||
return false; | ||
} | ||
me.fireCustomEvent('sizechange'); | ||
this.fireCustomEvent('sizechange'); | ||
} | ||
@@ -161,3 +164,3 @@ | ||
// and check if bottom is reached | ||
_invoke(me.scrollbars, 'update'); | ||
_invoke(this.scrollbars, 'update'); | ||
} | ||
@@ -173,4 +176,3 @@ }, | ||
scrollTo: function (destX, destY, duration) { | ||
var me = this, | ||
cache = me.cache, | ||
var cache = this.cache, | ||
startX, startY, endX, endY; | ||
@@ -180,6 +182,6 @@ | ||
// force update | ||
me.update(); | ||
this.update(); | ||
startX = me.scrollEl.scrollLeft; | ||
startY = me.scrollEl.scrollTop; | ||
startX = this.scrollEl.scrollLeft; | ||
startY = this.scrollEl.scrollTop; | ||
@@ -197,3 +199,3 @@ endX = +destX; | ||
// animate | ||
me.animateScroll(startX, endX, startY, endY, +duration); | ||
this.animateScroll(startX, endX, startY, endY, +duration); | ||
@@ -205,4 +207,3 @@ }, | ||
scrollIntoView: function (elem, duration, delta) { | ||
var me = this, | ||
scrollEl = me.scrollEl, | ||
var scrollEl = this.scrollEl, | ||
eDim, sDim, | ||
@@ -215,3 +216,3 @@ leftEdge, topEdge, rightEdge, bottomEdge, | ||
// force update | ||
me.update(); | ||
this.update(); | ||
@@ -239,4 +240,4 @@ if(typeof elem === 'string') { // selector | ||
topEdge = offsetY - (delta.top || 0); | ||
rightEdge = offsetX + eDim.width - me.cache.clientW + (delta.right || 0); | ||
bottomEdge = offsetY + eDim.height - me.cache.clientH + (delta.bottom || 0); | ||
rightEdge = offsetX + eDim.width - this.cache.clientW + (delta.right || 0); | ||
bottomEdge = offsetY + eDim.height - this.cache.clientH + (delta.bottom || 0); | ||
@@ -250,3 +251,3 @@ if(leftEdge < startX) { endX = leftEdge; } | ||
// animate | ||
me.animateScroll(startX, endX, startY, endY, +duration); | ||
this.animateScroll(startX, endX, startY, endY, +duration); | ||
}, | ||
@@ -258,4 +259,4 @@ | ||
animateScroll: function (startX, endX, startY, endY, duration) { | ||
var me = this, | ||
scrollEl = me.scrollEl, | ||
var self = this, | ||
scrollEl = this.scrollEl, | ||
startTime = Date.now(); | ||
@@ -289,4 +290,4 @@ | ||
me.scrollAnimation = time < 1 ? window.requestAnimationFrame(animate) : null; | ||
}()); | ||
self.scrollAnimation = time < 1 ? window.requestAnimationFrame(animate) : null; | ||
}(this)); | ||
}, | ||
@@ -298,10 +299,9 @@ | ||
destroy: function () { | ||
var me = this, | ||
element = me.element, | ||
scrollEl = me.scrollEl, | ||
listeners = me.listeners, | ||
index = G.instances.indexOf(me), | ||
var self = this, | ||
element = this.element, | ||
scrollEl = this.scrollEl, | ||
listeners = this.listeners, | ||
child; | ||
if(!me.scrollEl) { return; } | ||
if(!this.scrollEl) { return; } | ||
@@ -314,22 +314,25 @@ // unbind events | ||
// remove scrollbars elements | ||
_invoke(me.scrollbars, 'remove'); | ||
_invoke(this.scrollbars, 'remove'); | ||
// unwrap content | ||
while(child = scrollEl.childNodes[0]) { | ||
element.insertBefore(child, scrollEl); | ||
if (!this.settings.contentElement) { | ||
while(child = scrollEl.childNodes[0]) { | ||
element.insertBefore(child, scrollEl); | ||
} | ||
element.removeChild(scrollEl); | ||
this.scrollEl = null; | ||
} | ||
element.removeChild(scrollEl); | ||
me.scrollEl = null; | ||
// remove classes | ||
toggleClass(element, me.settings.classPrefix + 'prevent', false); | ||
toggleClass(element, this.settings.classPrefix + 'prevent', false); | ||
toggleClass(element, 'is-enabled', false); | ||
// defer instance removal from global array | ||
// to not affect checkLoop _invoke | ||
if (index > -1) { | ||
window.requestAnimationFrame(function () { | ||
window.requestAnimationFrame(function () { | ||
var index = G.instances.indexOf(self); | ||
if (index > -1) { | ||
G.instances.splice(index, 1); | ||
}); | ||
} | ||
} | ||
}); | ||
}, | ||
@@ -341,4 +344,3 @@ | ||
fireCustomEvent: function (eventName) { | ||
var me = this, | ||
cache = me.cache, | ||
var cache = this.cache, | ||
sH = cache.scrollH, sW = cache.scrollW, | ||
@@ -365,3 +367,10 @@ eventData; | ||
me.element.dispatchEvent(new CustomEvent(eventName, { detail: eventData })); | ||
var event; | ||
if (CustomEvent === 'function') { | ||
event = new CustomEvent(eventName, { detail: eventData }); | ||
} else { // IE does not support CustomEvent | ||
event = document.createEvent('CustomEvent'); | ||
event.initCustomEvent(eventName, false, false, eventData); | ||
} | ||
this.element.dispatchEvent(event); | ||
}, | ||
@@ -368,0 +377,0 @@ |
@@ -16,2 +16,3 @@ var Scrollbar = function (which, instance) { | ||
rtlMode = G.scrollbarSpec.rtl, | ||
enabled = false, | ||
@@ -32,2 +33,3 @@ scrollbarEl = null, | ||
var evData = ev.touches ? ev.touches[0] : ev, | ||
dragMode = settings.rtl && rtlMode === 1 && !isVertical ? -1 : 1, | ||
delta, deltaRatio; | ||
@@ -39,3 +41,3 @@ | ||
scrollEl[scrollProp] = events.dragData.scroll + deltaRatio * cache[scrollSize]; | ||
scrollEl[scrollProp] = events.dragData.scroll + deltaRatio * cache[scrollSize] * dragMode; | ||
}, | ||
@@ -90,4 +92,3 @@ | ||
update: function () { | ||
var me = this, | ||
newSize, oldSize, | ||
var newSize, oldSize, | ||
newDim, newRelPos, deltaPos; | ||
@@ -107,11 +108,11 @@ | ||
if(newSize === 1 && enabled) { | ||
me.toggle(false); | ||
this.toggle(false); | ||
} | ||
if(newSize < 1 && !enabled) { | ||
me.toggle(true); | ||
this.toggle(true); | ||
} | ||
if(trackEl && enabled) { | ||
me.style(newRelPos, deltaPos, newSize, oldSize); | ||
this.style(newRelPos, deltaPos, newSize, oldSize); | ||
} | ||
@@ -123,3 +124,3 @@ | ||
if(enabled) { | ||
me.fireEdgeEv(); | ||
this.fireEdgeEv(); | ||
} | ||
@@ -133,4 +134,9 @@ | ||
trackEl.style[ isVertical ? 'height' : 'width' ] = newSize * 100 + '%'; | ||
if (settings.rtl && !isVertical) { | ||
trackEl.style.marginRight = (1 - newSize) * 100 + '%'; | ||
} | ||
} | ||
trackEl.style[G.cssTransform] = 'translate(' + (isVertical ? '0%,' + newRelPos + '%' : newRelPos + '%' + ',0%') + ')'; | ||
trackEl.style[G.cssTransform] = 'translate(' + | ||
(isVertical ? '0%,' + newRelPos + '%' : newRelPos + '%' + ',0%') | ||
+ ')'; | ||
}, | ||
@@ -146,6 +152,9 @@ | ||
positionRatio, percent; | ||
if(sizeRatio >= 1 || !scrollS) { // no scrollbars needed | ||
return { position: 0, size: 1, percent: 0 }; | ||
} | ||
if (!isVertical && settings.rtl && rtlMode) { | ||
position = sizeDiff - position * rtlMode; | ||
} | ||
@@ -152,0 +161,0 @@ percent = 100 * position / sizeDiff; |
var Utils = { | ||
hideNativeScrollbars: function (scrollEl) { | ||
var size = G.nativeScrollbarSize, | ||
hideNativeScrollbars: function (scrollEl, isRtl) { | ||
var size = G.scrollbarSpec.width, | ||
scrollElStyle = scrollEl.style; | ||
@@ -12,3 +12,3 @@ if(size === 0) { | ||
} else { | ||
scrollElStyle.right = -size + 'px'; | ||
scrollElStyle[isRtl ? 'left' : 'right'] = -size + 'px'; | ||
scrollElStyle.bottom = -size + 'px'; | ||
@@ -41,3 +41,2 @@ return true; | ||
} | ||
wrapper.className = className; | ||
return element.appendChild(wrapper); | ||
@@ -47,9 +46,2 @@ }, | ||
containsNode: function (parent, node) { | ||
return parent.contains ? | ||
parent != node && parent.contains(node) : | ||
!!(parent.compareDocumentPosition(node) & 16); | ||
}, | ||
// Global height checker | ||
@@ -56,0 +48,0 @@ // looped to listen element changes |
@@ -157,1 +157,15 @@ /* eslint-env qunit */ | ||
}); | ||
asyncTest('It should fire sizechange', function () { | ||
expect(2); | ||
os.element.addEventListener('sizechange', function (ev) { | ||
equal(ev.type, 'sizechange'); | ||
equal(ev.detail.clientHeight, 150); | ||
start(); | ||
}); | ||
os.element.style.height = '150px'; | ||
os.update(); | ||
}); |
@@ -121,3 +121,3 @@ /* eslint-env qunit */ | ||
asyncTest('It should update tracks', function () { | ||
asyncTest('It should update tracks on size change', function () { | ||
expect(4); | ||
@@ -145,2 +145,22 @@ | ||
asyncTest('It should update tracks on content change', function () { | ||
expect(2); | ||
var content = document.querySelector('.test'); | ||
content.style.width = '400px'; | ||
content.style.height = '400px'; | ||
setTimeout(function () { | ||
os.update(); | ||
}); | ||
setTimeout(function () { | ||
equal(os.cache.v.size, 0.25); | ||
equal(os.cache.h.size, 0.25); | ||
start(); | ||
}, 100); | ||
}); | ||
asyncTest('Vertical track should be disabled if no scroll', function () { | ||
@@ -147,0 +167,0 @@ expect(4); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
378656
8115
304
32