admin-lte
Version:
Responsive open source admin dashboard and control panel.
922 lines (841 loc) • 319 kB
JavaScript
/*!
* OverlayScrollbars
* https://github.com/KingSora/OverlayScrollbars
*
* Version: 1.10.0
*
* Copyright KingSora | Rene Haas.
* https://github.com/KingSora
*
* Released under the MIT license.
* Date: 11.10.2019
*/
(function (global, factory) {
if (typeof define === 'function' && define.amd)
define(['jquery'], function(framework) { return factory(global, global.document, undefined, framework); });
else if (typeof module === 'object' && typeof module.exports === 'object')
module.exports = factory(global, global.document, undefined, require('jquery'));
else
factory(global, global.document, undefined, global.jQuery);
}(typeof window !== 'undefined' ? window : this,
function(window, document, undefined, framework) {
'use strict';
var PLUGINNAME = 'OverlayScrollbars';
var TYPES = {
o : 'object',
f : 'function',
a : 'array',
s : 'string',
b : 'boolean',
n : 'number',
u : 'undefined',
z : 'null'
//d : 'date',
//e : 'error',
//r : 'regexp',
//y : 'symbol'
};
var LEXICON = {
c : 'class',
s : 'style',
i : 'id',
l : 'length',
p : 'prototype',
oH : 'offsetHeight',
cH : 'clientHeight',
sH : 'scrollHeight',
oW : 'offsetWidth',
cW : 'clientWidth',
sW : 'scrollWidth',
hOP : 'hasOwnProperty',
bCR : 'getBoundingClientRect'
};
var VENDORS = (function() {
//https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix
var jsCache = { };
var cssCache = { };
var cssPrefixes = ['-webkit-', '-moz-', '-o-', '-ms-'];
var jsPrefixes = ['WebKit', 'Moz', 'O', 'MS'];
function firstLetterToUpper(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
return {
_cssPrefixes: cssPrefixes,
_jsPrefixes: jsPrefixes,
_cssProperty : function(name) {
var result = cssCache[name];
if(cssCache[LEXICON.hOP](name))
return result;
var uppercasedName = firstLetterToUpper(name);
var elmStyle = document.createElement('div')[LEXICON.s];
var resultPossibilities;
var i = 0;
var v;
var currVendorWithoutDashes;
for (; i < cssPrefixes.length; i++) {
currVendorWithoutDashes = cssPrefixes[i].replace(/-/g, '');
resultPossibilities = [
name, //transition
cssPrefixes[i] + name, //-webkit-transition
currVendorWithoutDashes + uppercasedName, //webkitTransition
firstLetterToUpper(currVendorWithoutDashes) + uppercasedName //WebkitTransition
];
for(v = 0; v < resultPossibilities[LEXICON.l]; v++) {
if(elmStyle[resultPossibilities[v]] !== undefined) {
result = resultPossibilities[v];
break;
}
}
}
cssCache[name] = result;
return result;
},
_jsAPI : function(name, isInterface, fallback) {
var i = 0;
var result = jsCache[name];
if(!jsCache[LEXICON.hOP](name)) {
result = window[name];
for(; i < jsPrefixes[LEXICON.l]; i++)
result = result || window[(isInterface ? jsPrefixes[i] : jsPrefixes[i].toLowerCase()) + firstLetterToUpper(name)];
jsCache[name] = result;
}
return result || fallback;
}
}
})();
var COMPATIBILITY = (function() {
function windowSize(x) {
return x ? window.innerWidth || document.documentElement[LEXICON.cW] || document.body[LEXICON.cW] : window.innerHeight || document.documentElement[LEXICON.cH] || document.body[LEXICON.cH];
}
function bind(func, thisObj) {
if (typeof func != TYPES.f) {
throw "Can't bind function!";
// closest thing possible to the ECMAScript 5
// internal IsCallable function
//throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var proto = LEXICON.p;
var aArgs = Array[proto].slice.call(arguments, 2);
var fNOP = function() {};
var fBound = function() { return func.apply(this instanceof fNOP ? this : thisObj, aArgs.concat(Array[proto].slice.call(arguments))); };
if (func[proto])
fNOP[proto] = func[proto]; // Function.prototype doesn't have a prototype property
fBound[proto] = new fNOP();
return fBound;
}
return {
/**
* Gets the current window width.
* @returns {Number|number} The current window width in pixel.
*/
wW: bind(windowSize, 0, true),
/**
* Gets the current window height.
* @returns {Number|number} The current window height in pixel.
*/
wH: bind(windowSize, 0),
/**
* Gets the MutationObserver Object or undefined if not supported.
* @returns {MutationObserver|*|undefined} The MutationsObserver Object or undefined.
*/
mO: bind(VENDORS._jsAPI, 0, 'MutationObserver', true),
/**
* Gets the ResizeObserver Object or undefined if not supported.
* @returns {MutationObserver|*|undefined} The ResizeObserver Object or undefined.
*/
rO: bind(VENDORS._jsAPI, 0, 'ResizeObserver', true),
/**
* Gets the RequestAnimationFrame method or it's corresponding polyfill.
* @returns {*|Function} The RequestAnimationFrame method or it's corresponding polyfill.
*/
rAF: bind(VENDORS._jsAPI, 0, 'requestAnimationFrame', false, function (func) { return window.setTimeout(func, 1000 / 60); }),
/**
* Gets the CancelAnimationFrame method or it's corresponding polyfill.
* @returns {*|Function} The CancelAnimationFrame method or it's corresponding polyfill.
*/
cAF: bind(VENDORS._jsAPI, 0, 'cancelAnimationFrame', false, function (id) { return window.clearTimeout(id); }),
/**
* Gets the current time.
* @returns {number} The current time.
*/
now: function() {
return Date.now && Date.now() || new Date().getTime();
},
/**
* Stops the propagation of the given event.
* @param event The event of which the propagation shall be stoped.
*/
stpP: function(event) {
if(event.stopPropagation)
event.stopPropagation();
else
event.cancelBubble = true;
},
/**
* Prevents the default action of the given event.
* @param event The event of which the default action shall be prevented.
*/
prvD: function(event) {
if(event.preventDefault && event.cancelable)
event.preventDefault();
else
event.returnValue = false;
},
/**
* Gets the pageX and pageY values of the given mouse event.
* @param event The mouse event of which the pageX and pageX shall be got.
* @returns {{x: number, y: number}} x = pageX value, y = pageY value.
*/
page: function(event) {
event = event.originalEvent || event;
var strPage = 'page';
var strClient = 'client';
var strX = 'X';
var strY = 'Y';
var target = event.target || event.srcElement || document;
var eventDoc = target.ownerDocument || document;
var doc = eventDoc.documentElement;
var body = eventDoc.body;
//if touch event return return pageX/Y of it
if(event.touches !== undefined) {
var touch = event.touches[0];
return {
x : touch[strPage + strX],
y : touch[strPage + strY]
}
}
// Calculate pageX/Y if not native supported
if (!event[strPage + strX] && event[strClient + strX] && event[strClient + strX] != null) {
return {
x : event[strClient + strX] +
(doc && doc.scrollLeft || body && body.scrollLeft || 0) -
(doc && doc.clientLeft || body && body.clientLeft || 0),
y : event[strClient + strY] +
(doc && doc.scrollTop || body && body.scrollTop || 0) -
(doc && doc.clientTop || body && body.clientTop || 0)
}
}
return {
x : event[strPage + strX],
y : event[strPage + strY]
};
},
/**
* Gets the clicked mouse button of the given mouse event.
* @param event The mouse event of which the clicked button shal be got.
* @returns {number} The number of the clicked mouse button. (0 : none | 1 : leftButton | 2 : middleButton | 3 : rightButton)
*/
mBtn: function(event) {
var button = event.button;
if (!event.which && button !== undefined)
return (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));
else
return event.which;
},
/**
* Checks whether a item is in the given array and returns its index.
* @param item The item of which the position in the array shall be determined.
* @param arr The array.
* @returns {number} The zero based index of the item or -1 if the item isn't in the array.
*/
inA : function(item, arr) {
for (var i = 0; i < arr[LEXICON.l]; i++)
//Sometiems in IE a "SCRIPT70" Permission denied error occurs if HTML elements in a iFrame are compared
try {
if (arr[i] === item)
return i;
}
catch(e) { }
return -1;
},
/**
* Returns true if the given value is a array.
* @param arr The potential array.
* @returns {boolean} True if the given value is a array, false otherwise.
*/
isA: function(arr) {
var def = Array.isArray;
return def ? def(arr) : this.type(arr) == TYPES.a;
},
/**
* Determine the internal JavaScript [[Class]] of the given object.
* @param obj The object of which the type shall be determined.
* @returns {string} The type of the given object.
*/
type: function(obj) {
if (obj === undefined)
return obj + '';
if (obj === null)
return obj + '';
return Object[LEXICON.p].toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
},
bind: bind
/**
* Gets the vendor-prefixed CSS property by the given name.
* For example the given name is "transform" and you're using a old Firefox browser then the returned value would be "-moz-transform".
* If the browser doesn't need a vendor-prefix, then the returned string is the given name.
* If the browser doesn't support the given property name at all (not even with a vendor-prefix) the returned value is null.
* @param propName The unprefixed CSS property name.
* @returns {string|null} The vendor-prefixed CSS property or null if the browser doesn't support the given CSS property.
cssProp: function(propName) {
return VENDORS._cssProperty(propName);
}
*/
}
})();
var MATH = Math;
var JQUERY = framework;
var EASING = framework.easing;
var FRAMEWORK = framework;
var INSTANCES = (function() {
var _targets = [ ];
var _instancePropertyString = '__overlayScrollbars__';
/**
* Register, unregister or get a certain (or all) instances.
* Register: Pass the target and the instance.
* Unregister: Pass the target and null.
* Get Instance: Pass the target from which the instance shall be got.
* Get Targets: Pass no arguments.
* @param target The target to which the instance shall be registered / from which the instance shall be unregistered / the instance shall be got
* @param instance The instance.
* @returns {*|void} Returns the instance from the given target.
*/
return function (target, instance) {
var argLen = arguments[LEXICON.l];
if(argLen < 1) {
//return all targets
return _targets;
}
else {
if(instance) {
//register instance
target[_instancePropertyString] = instance;
_targets.push(target);
}
else {
var index = COMPATIBILITY.inA(target, _targets);
if (index > -1) {
if(argLen > 1) {
//unregister instance
delete target[_instancePropertyString];
_targets.splice(index, 1);
}
else {
//get instance from target
return _targets[index][_instancePropertyString];
}
}
}
}
}
})();
var PLUGIN = (function() {
var _plugin;
var _pluginsGlobals;
var _pluginsAutoUpdateLoop;
var _pluginsExtensions = [ ];
var _pluginsOptions = (function() {
var type = COMPATIBILITY.type;
var possibleTemplateTypes = [
TYPES.b, //boolean
TYPES.n, //number
TYPES.s, //string
TYPES.a, //array
TYPES.o, //object
TYPES.f, //function
TYPES.z //null
];
var restrictedStringsSplit = ' ';
var restrictedStringsPossibilitiesSplit = ':';
var classNameAllowedValues = [TYPES.z, TYPES.s];
var numberAllowedValues = TYPES.n;
var booleanNullAllowedValues = [TYPES.z, TYPES.b];
var booleanTrueTemplate = [true, TYPES.b];
var booleanFalseTemplate = [false, TYPES.b];
var callbackTemplate = [null, [TYPES.z, TYPES.f]];
var inheritedAttrsTemplate = [['style', 'class'], [TYPES.s, TYPES.a, TYPES.z]];
var resizeAllowedValues = 'n:none b:both h:horizontal v:vertical';
var overflowBehaviorAllowedValues = 'v-h:visible-hidden v-s:visible-scroll s:scroll h:hidden';
var scrollbarsVisibilityAllowedValues = 'v:visible h:hidden a:auto';
var scrollbarsAutoHideAllowedValues = 'n:never s:scroll l:leave m:move';
var optionsDefaultsAndTemplate = {
className: ['os-theme-dark', classNameAllowedValues], //null || string
resize: ['none', resizeAllowedValues], //none || both || horizontal || vertical || n || b || h || v
sizeAutoCapable: booleanTrueTemplate, //true || false
clipAlways: booleanTrueTemplate, //true || false
normalizeRTL: booleanTrueTemplate, //true || false
paddingAbsolute: booleanFalseTemplate, //true || false
autoUpdate: [null, booleanNullAllowedValues], //true || false || null
autoUpdateInterval: [33, numberAllowedValues], //number
nativeScrollbarsOverlaid: {
showNativeScrollbars: booleanFalseTemplate, //true || false
initialize: booleanTrueTemplate //true || false
},
overflowBehavior: {
x: ['scroll', overflowBehaviorAllowedValues], //visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
y: ['scroll', overflowBehaviorAllowedValues] //visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
},
scrollbars: {
visibility: ['auto', scrollbarsVisibilityAllowedValues], //visible || hidden || auto || v || h || a
autoHide: ['never', scrollbarsAutoHideAllowedValues], //never || scroll || leave || move || n || s || l || m
autoHideDelay: [800, numberAllowedValues], //number
dragScrolling: booleanTrueTemplate, //true || false
clickScrolling: booleanFalseTemplate, //true || false
touchSupport: booleanTrueTemplate, //true || false
snapHandle: booleanFalseTemplate //true || false
},
textarea: {
dynWidth: booleanFalseTemplate, //true || false
dynHeight: booleanFalseTemplate, //true || false
inheritedAttrs : inheritedAttrsTemplate //string || array || null
},
callbacks: {
onInitialized: callbackTemplate, //null || function
onInitializationWithdrawn: callbackTemplate, //null || function
onDestroyed: callbackTemplate, //null || function
onScrollStart: callbackTemplate, //null || function
onScroll: callbackTemplate, //null || function
onScrollStop: callbackTemplate, //null || function
onOverflowChanged: callbackTemplate, //null || function
onOverflowAmountChanged: callbackTemplate, //null || function
onDirectionChanged: callbackTemplate, //null || function
onContentSizeChanged: callbackTemplate, //null || function
onHostSizeChanged: callbackTemplate, //null || function
onUpdated: callbackTemplate //null || function
}
};
var convert = function(template) {
var recursive = function(obj) {
var key;
var val;
var valType;
for(key in obj) {
if(!obj[LEXICON.hOP](key))
continue;
val = obj[key];
valType = type(val);
if(valType == TYPES.a)
obj[key] = val[template ? 1 : 0];
else if(valType == TYPES.o)
obj[key] = recursive(val);
}
return obj;
};
return recursive(FRAMEWORK.extend(true, { }, optionsDefaultsAndTemplate));
};
return {
_defaults : convert(),
_template : convert(true),
/**
* Validates the passed object by the passed template.
* @param obj The object which shall be validated.
* @param template The template which defines the allowed values and types.
* @param writeErrors True if errors shall be logged to the console.
* @param diffObj If a object is passed then only valid differences to this object will be returned.
* @returns {{}} A object which contains two objects called "default" and "prepared" which contains only the valid properties of the passed original object and discards not different values compared to the passed diffObj.
*/
_validate : function (obj, template, writeErrors, diffObj) {
var validatedOptions = { };
var validatedOptionsPrepared = { };
var objectCopy = FRAMEWORK.extend(true, { }, obj);
var inArray = FRAMEWORK.inArray;
var isEmptyObj = FRAMEWORK.isEmptyObject;
var checkObjectProps = function(data, template, diffData, validatedOptions, validatedOptionsPrepared, prevPropName) {
for (var prop in template) {
if (template[LEXICON.hOP](prop) && data[LEXICON.hOP](prop)) {
var isValid = false;
var isDiff = false;
var templateValue = template[prop];
var templateValueType = type(templateValue);
var templateIsComplex = templateValueType == TYPES.o;
var templateTypes = type(templateValue) != TYPES.a ? [ templateValue ] : templateValue;
var dataDiffValue = diffData[prop];
var dataValue = data[prop];
var dataValueType = type(dataValue);
var propPrefix = prevPropName ? prevPropName + '.' : '';
var error = "The option \"" + propPrefix + prop + "\" wasn't set, because";
var errorPossibleTypes = [ ];
var errorRestrictedStrings = [ ];
var restrictedStringValuesSplit;
var restrictedStringValuesPossibilitiesSplit;
var isRestrictedValue;
var mainPossibility;
var currType;
var i;
var v;
var j;
dataDiffValue = dataDiffValue === undefined ? { } : dataDiffValue;
//if the template has a object as value, it means that the options are complex (verschachtelt)
if(templateIsComplex && dataValueType == TYPES.o) {
validatedOptions[prop] = { };
validatedOptionsPrepared[prop] = { };
checkObjectProps(dataValue, templateValue, dataDiffValue, validatedOptions[prop], validatedOptionsPrepared[prop], propPrefix + prop);
FRAMEWORK.each([ data, validatedOptions, validatedOptionsPrepared ], function(index, value) {
if(isEmptyObj(value[prop])) {
delete value[prop];
}
});
}
else if(!templateIsComplex) {
for(i = 0; i < templateTypes[LEXICON.l]; i++) {
currType = templateTypes[i];
templateValueType = type(currType);
//if currtype is string and starts with restrictedStringPrefix and end with restrictedStringSuffix
isRestrictedValue = templateValueType == TYPES.s && inArray(currType, possibleTemplateTypes) === -1;
if(isRestrictedValue) {
errorPossibleTypes.push(TYPES.s);
//split it into a array which contains all possible values for example: ["y:yes", "n:no", "m:maybe"]
restrictedStringValuesSplit = currType.split(restrictedStringsSplit);
errorRestrictedStrings = errorRestrictedStrings.concat(restrictedStringValuesSplit);
for(v = 0; v < restrictedStringValuesSplit[LEXICON.l]; v++) {
//split the possible values into their possibiliteis for example: ["y", "yes"] -> the first is always the mainPossibility
restrictedStringValuesPossibilitiesSplit = restrictedStringValuesSplit[v].split(restrictedStringsPossibilitiesSplit);
mainPossibility = restrictedStringValuesPossibilitiesSplit[0];
for(j = 0; j < restrictedStringValuesPossibilitiesSplit[LEXICON.l]; j++) {
//if any possibility matches with the dataValue, its valid
if(dataValue === restrictedStringValuesPossibilitiesSplit[j]) {
isValid = true;
break;
}
}
if(isValid)
break;
}
}
else {
errorPossibleTypes.push(currType);
if(dataValueType === currType) {
isValid = true;
break;
}
}
}
if(isValid) {
isDiff = dataValue !== dataDiffValue;
if(isDiff)
validatedOptions[prop] = dataValue;
if(isRestrictedValue ? inArray(dataDiffValue, restrictedStringValuesPossibilitiesSplit) < 0 : isDiff)
validatedOptionsPrepared[prop] = isRestrictedValue ? mainPossibility : dataValue;
}
else if(writeErrors) {
console.warn(error + " it doesn't accept the type [ " + dataValueType.toUpperCase() + " ] with the value of \"" + dataValue + "\".\r\n" +
"Accepted types are: [ " + errorPossibleTypes.join(', ').toUpperCase() + " ]." +
(errorRestrictedStrings[length] > 0 ? "\r\nValid strings are: [ " + errorRestrictedStrings.join(', ').split(restrictedStringsPossibilitiesSplit).join(', ') + " ]." : ''));
}
delete data[prop];
}
}
}
};
checkObjectProps(objectCopy, template, diffObj || { }, validatedOptions, validatedOptionsPrepared);
//add values which aren't specified in the template to the finished validated object to prevent them from being discarded
/*
if(keepForeignProps) {
FRAMEWORK.extend(true, validatedOptions, objectCopy);
FRAMEWORK.extend(true, validatedOptionsPrepared, objectCopy);
}
*/
if(!isEmptyObj(objectCopy) && writeErrors)
console.warn('The following options are discarded due to invalidity:\r\n' + window.JSON.stringify(objectCopy, null, 2));
return {
_default : validatedOptions,
_prepared : validatedOptionsPrepared
};
}
}
}());
/**
* Initializes the object which contains global information about the plugin and each instance of it.
*/
function initOverlayScrollbarsStatics() {
if(!_pluginsGlobals)
_pluginsGlobals = new OverlayScrollbarsGlobals(_pluginsOptions._defaults);
if(!_pluginsAutoUpdateLoop)
_pluginsAutoUpdateLoop = new OverlayScrollbarsAutoUpdateLoop(_pluginsGlobals);
}
/**
* The global object for the OverlayScrollbars objects. It contains resources which every OverlayScrollbars object needs. This object is initialized only once: if the first OverlayScrollbars object gets initialized.
* @param defaultOptions
* @constructor
*/
function OverlayScrollbarsGlobals(defaultOptions) {
var _base = this;
var strOverflow = 'overflow';
var strHidden = 'hidden';
var strScroll = 'scroll';
var bodyElement = FRAMEWORK('body');
var scrollbarDummyElement = FRAMEWORK('<div id="os-dummy-scrollbar-size"><div></div></div>');
var scrollbarDummyElement0 = scrollbarDummyElement[0];
var dummyContainerChild = FRAMEWORK(scrollbarDummyElement.children('div').eq(0));
bodyElement.append(scrollbarDummyElement);
scrollbarDummyElement.hide().show(); //fix IE8 bug (incorrect measuring)
var nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement0);
var nativeScrollbarIsOverlaid = {
x: nativeScrollbarSize.x === 0,
y: nativeScrollbarSize.y === 0
};
var msie = (function() {
var ua = window.navigator.userAgent;
var strIndexOf = 'indexOf';
var strSubString = 'substring';
var msie = ua[strIndexOf]('MSIE ');
var trident = ua[strIndexOf]('Trident/');
var edge = ua[strIndexOf]('Edge/');
var rv = ua[strIndexOf]('rv:');
var result;
var parseIntFunc = parseInt;
// IE 10 or older => return version number
if (msie > 0)
result = parseIntFunc(ua[strSubString](msie + 5, ua[strIndexOf]('.', msie)), 10);
// IE 11 => return version number
else if (trident > 0)
result = parseIntFunc(ua[strSubString](rv + 3, ua[strIndexOf]('.', rv)), 10);
// Edge (IE 12+) => return version number
else if (edge > 0)
result = parseIntFunc(ua[strSubString](edge + 5, ua[strIndexOf]('.', edge)), 10);
// other browser
return result;
})();
FRAMEWORK.extend(_base, {
defaultOptions : defaultOptions,
msie : msie,
autoUpdateLoop : false,
autoUpdateRecommended : !COMPATIBILITY.mO(),
nativeScrollbarSize : nativeScrollbarSize,
nativeScrollbarIsOverlaid : nativeScrollbarIsOverlaid,
nativeScrollbarStyling : (function() {
var result = false;
scrollbarDummyElement.addClass('os-viewport-native-scrollbars-invisible');
try {
result = (scrollbarDummyElement.css('scrollbar-width') === 'none' && (msie > 9 || !msie)) || window.getComputedStyle(scrollbarDummyElement0, '::-webkit-scrollbar').getPropertyValue('display') === 'none';
} catch (ex) { }
//fix opera bug: scrollbar styles will only appear if overflow value is scroll or auto during the activation of the style.
//and set overflow to scroll
//scrollbarDummyElement.css(strOverflow, strHidden).hide().css(strOverflow, strScroll).show();
//return (scrollbarDummyElement0[LEXICON.oH] - scrollbarDummyElement0[LEXICON.cH]) === 0 && (scrollbarDummyElement0[LEXICON.oW] - scrollbarDummyElement0[LEXICON.cW]) === 0;
return result;
})(),
overlayScrollbarDummySize : { x: 30, y: 30 },
cssCalc : (function() {
var dummyStyle = document.createElement('div')[LEXICON.s];
var strCalc = 'calc';
var i = -1;
var prop;
for(; i < VENDORS._cssPrefixes[LEXICON.l]; i++) {
prop = i < 0 ? strCalc : VENDORS._cssPrefixes[i] + strCalc;
dummyStyle.cssText = 'width:' + prop + '(1px);';
if (dummyStyle[LEXICON.l])
return prop;
}
return null;
})(),
restrictedMeasuring : (function() {
//https://bugzilla.mozilla.org/show_bug.cgi?id=1439305
scrollbarDummyElement.css(strOverflow, strHidden);
var scrollSize = {
w : scrollbarDummyElement0[LEXICON.sW],
h : scrollbarDummyElement0[LEXICON.sH]
};
scrollbarDummyElement.css(strOverflow, 'visible');
var scrollSize2 = {
w : scrollbarDummyElement0[LEXICON.sW],
h : scrollbarDummyElement0[LEXICON.sH]
};
return (scrollSize.w - scrollSize2.w) !== 0 || (scrollSize.h - scrollSize2.h) !== 0;
})(),
rtlScrollBehavior : (function() {
scrollbarDummyElement.css({ 'overflow-y' : strHidden, 'overflow-x' : strScroll, 'direction' : 'rtl' }).scrollLeft(0);
var dummyContainerOffset = scrollbarDummyElement.offset();
var dummyContainerChildOffset = dummyContainerChild.offset();
scrollbarDummyElement.scrollLeft(999);
var dummyContainerScrollOffsetAfterScroll = dummyContainerChild.offset();
return {
//origin direction = determines if the zero scroll position is on the left or right side
//'i' means 'invert' (i === true means that the axis must be inverted to be correct)
//true = on the left side
//false = on the right side
i : dummyContainerOffset.left === dummyContainerChildOffset.left,
//negative = determines if the maximum scroll is positive or negative
//'n' means 'negate' (n === true means that the axis must be negated to be correct)
//true = negative
//false = positive
n : dummyContainerChildOffset.left - dummyContainerScrollOffsetAfterScroll.left === 0
};
})(),
supportTransform : VENDORS._cssProperty('transform') !== undefined,
supportTransition : VENDORS._cssProperty('transition') !== undefined,
supportPassiveEvents : (function() {
var supportsPassive = false;
try {
window.addEventListener('test', null, Object.defineProperty({ }, 'passive', {
get: function() {
supportsPassive = true;
}
}));
} catch (e) { }
return supportsPassive;
})(),
supportResizeObserver : !!COMPATIBILITY.rO(),
supportMutationObserver : !!COMPATIBILITY.mO()
});
scrollbarDummyElement.removeAttr(LEXICON.s).remove();
//Catch zoom event:
(function () {
if(nativeScrollbarIsOverlaid.x && nativeScrollbarIsOverlaid.y)
return;
var abs = MATH.abs;
var windowWidth = COMPATIBILITY.wW();
var windowHeight = COMPATIBILITY.wH();
var windowDpr = getWindowDPR();
var onResize = function() {
if(INSTANCES().length > 0) {
var newW = COMPATIBILITY.wW();
var newH = COMPATIBILITY.wH();
var deltaW = newW - windowWidth;
var deltaH = newH - windowHeight;
if (deltaW === 0 && deltaH === 0)
return;
var deltaWRatio = MATH.round(newW / (windowWidth / 100.0));
var deltaHRatio = MATH.round(newH / (windowHeight / 100.0));
var absDeltaW = abs(deltaW);
var absDeltaH = abs(deltaH);
var absDeltaWRatio = abs(deltaWRatio);
var absDeltaHRatio = abs(deltaHRatio);
var newDPR = getWindowDPR();
var deltaIsBigger = absDeltaW > 2 && absDeltaH > 2;
var difference = !differenceIsBiggerThanOne(absDeltaWRatio, absDeltaHRatio);
var dprChanged = newDPR !== windowDpr && windowDpr > 0;
var isZoom = deltaIsBigger && difference && dprChanged;
var oldScrollbarSize = _base.nativeScrollbarSize;
var newScrollbarSize;
if (isZoom) {
bodyElement.append(scrollbarDummyElement);
newScrollbarSize = _base.nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement[0]);
scrollbarDummyElement.remove();
if(oldScrollbarSize.x !== newScrollbarSize.x || oldScrollbarSize.y !== newScrollbarSize.y) {
FRAMEWORK.each(INSTANCES(), function () {
if(INSTANCES(this))
INSTANCES(this).update('zoom');
});
}
}
windowWidth = newW;
windowHeight = newH;
windowDpr = newDPR;
}
};
function differenceIsBiggerThanOne(valOne, valTwo) {
var absValOne = abs(valOne);
var absValTwo = abs(valTwo);
return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
}
function getWindowDPR() {
var dDPI = window.screen.deviceXDPI || 0;
var sDPI = window.screen.logicalXDPI || 1;
return window.devicePixelRatio || (dDPI / sDPI);
}
FRAMEWORK(window).on('resize', onResize);
})();
function calcNativeScrollbarSize(measureElement) {
return {
x: measureElement[LEXICON.oH] - measureElement[LEXICON.cH],
y: measureElement[LEXICON.oW] - measureElement[LEXICON.cW]
};
}
}
/**
* The object which manages the auto update loop for all OverlayScrollbars objects. This object is initialized only once: if the first OverlayScrollbars object gets initialized.
* @constructor
*/
function OverlayScrollbarsAutoUpdateLoop(globals) {
var _base = this;
var _inArray = FRAMEWORK.inArray;
var _getNow = COMPATIBILITY.now;
var _strAutoUpdate = 'autoUpdate';
var _strAutoUpdateInterval = _strAutoUpdate + 'Interval';
var _strLength = LEXICON.l;
var _loopingInstances = [ ];
var _loopingInstancesIntervalCache = [ ];
var _loopIsActive = false;
var _loopIntervalDefault = 33;
var _loopInterval = _loopIntervalDefault;
var _loopTimeOld = _getNow();
var _loopID;
/**
* The auto update loop which will run every 50 milliseconds or less if the update interval of a instance is lower than 50 milliseconds.
*/
var loop = function() {
if(_loopingInstances[_strLength] > 0 && _loopIsActive) {
_loopID = COMPATIBILITY.rAF()(function () {
loop();
});
var timeNew = _getNow();
var timeDelta = timeNew - _loopTimeOld;
var lowestInterval;
var instance;
var instanceOptions;
var instanceAutoUpdateAllowed;
var instanceAutoUpdateInterval;
var now;
if (timeDelta > _loopInterval) {
_loopTimeOld = timeNew - (timeDelta % _loopInterval);
lowestInterval = _loopIntervalDefault;
for(var i = 0; i < _loopingInstances[_strLength]; i++) {
instance = _loopingInstances[i];
if (instance !== undefined) {
instanceOptions = instance.options();
instanceAutoUpdateAllowed = instanceOptions[_strAutoUpdate];
instanceAutoUpdateInterval = MATH.max(1, instanceOptions[_strAutoUpdateInterval]);
now = _getNow();
if ((instanceAutoUpdateAllowed === true || instanceAutoUpdateAllowed === null) && (now - _loopingInstancesIntervalCache[i]) > instanceAutoUpdateInterval) {
instance.update('auto');
_loopingInstancesIntervalCache[i] = new Date(now += instanceAutoUpdateInterval);
}
lowestInterval = MATH.max(1, MATH.min(lowestInterval, instanceAutoUpdateInterval));
}
}
_loopInterval = lowestInterval;
}
} else {
_loopInterval = _loopIntervalDefault;
}
};
/**
* Add OverlayScrollbars instance to the auto update loop. Only successful if the instance isn't already added.
* @param instance The instance which shall be updated in a loop automatically.
*/
_base.add = function(instance) {
if(_inArray(instance, _loopingInstances) === -1) {
_loopingInstances.push(instance);
_loopingInstancesIntervalCache.push(_getNow());
if (_loopingInstances[_strLength] > 0 && !_loopIsActive) {
_loopIsActive = true;
globals.autoUpdateLoop = _loopIsActive;
loop();
}
}
};
/**
* Remove OverlayScrollbars instance from the auto update loop. Only successful if the instance was added before.
* @param instance The instance which shall be updated in a loop automatically.
*/
_base.remove = function(instance) {
var index = _inArray(instance, _loopingInstances);
if(index > -1) {
//remove from loopingInstances list
_loopingInstancesIntervalCache.splice(index, 1);
_loopingInstances.splice(index, 1);
//correct update loop behavior
if (_loopingInstances[_strLength] === 0 && _loopIsActive) {
_loopIsActive = false;
globals.autoUpdateLoop = _loopIsActive;
if(_loopID !== undefined) {
COMPATIBILITY.cAF()(_loopID);
_loopID = -1;
}
}
}
};
}
/**
* A object whic