, then its child content cannot be scrolled with the arrow keys unless you set tabindex on the content, too
- * https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
- */
- setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, false, true);
- }
- }
-
- //update for the first time & initialize cache
- _base.update(_strAuto);
-
- //the plugin is initialized now!
- _initialized = true;
- dispatchCallback('onInitialized');
-
- //call all callbacks which would fire before the initialized was complete
- each(_callbacksInitQeueue, function (index, value) { dispatchCallback(value.n, value.a); });
- _callbacksInitQeueue = [];
-
- //add extensions
- if (type(extensions) == TYPES.s)
- extensions = [extensions];
- if (COMPATIBILITY.isA(extensions))
- each(extensions, function (index, value) { _base.addExt(value); });
- else if (FRAMEWORK.isPlainObject(extensions))
- each(extensions, function (key, value) { _base.addExt(key, value); });
-
- //add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions)
- setTimeout(function () {
- if (_supportTransition && !_destroyed)
- addClass(_hostElement, _classNameHostTransition);
- }, 333);
-
- return _base;
- }
-
- if (_plugin.valid(construct(pluginTargetElement, options, extensions))) {
- INSTANCES(pluginTargetElement, _base);
- }
-
- return _base;
- }
-
- /**
- * Initializes a new OverlayScrollbarsInstance object or changes options if already initialized or returns the current instance.
- * @param pluginTargetElements The elements to which the Plugin shall be initialized.
- * @param options The custom options with which the plugin shall be initialized.
- * @param extensions The extension(s) which shall be added right after initialization.
- * @returns {*}
- */
- _plugin = window[PLUGINNAME] = function (pluginTargetElements, options, extensions) {
- if (arguments[LEXICON.l] === 0)
- return this;
-
- var arr = [];
- var optsIsPlainObj = FRAMEWORK.isPlainObject(options);
- var inst;
- var result;
-
- //pluginTargetElements is null or undefined
- if (!pluginTargetElements)
- return optsIsPlainObj || !options ? result : arr;
-
- /*
- pluginTargetElements will be converted to:
- 1. A jQueryElement Array
- 2. A HTMLElement Array
- 3. A Array with a single HTML Element
- so pluginTargetElements is always a array.
- */
- pluginTargetElements = pluginTargetElements[LEXICON.l] != undefined ? pluginTargetElements : [pluginTargetElements[0] || pluginTargetElements];
- initOverlayScrollbarsStatics();
-
- if (pluginTargetElements[LEXICON.l] > 0) {
- if (optsIsPlainObj) {
- FRAMEWORK.each(pluginTargetElements, function (i, v) {
- inst = v;
- if (inst !== undefined)
- arr.push(OverlayScrollbarsInstance(inst, options, extensions, _pluginsGlobals, _pluginsAutoUpdateLoop));
- });
- }
- else {
- FRAMEWORK.each(pluginTargetElements, function (i, v) {
- inst = INSTANCES(v);
- if ((options === '!' && _plugin.valid(inst)) || (COMPATIBILITY.type(options) == TYPES.f && options(v, inst)))
- arr.push(inst);
- else if (options === undefined)
- arr.push(inst);
- });
- }
- result = arr[LEXICON.l] === 1 ? arr[0] : arr;
- }
- return result;
- };
-
- /**
- * Returns a object which contains global information about the plugin and each instance of it.
- * The returned object is just a copy, that means that changes to the returned object won't have any effect to the original object.
- */
- _plugin.globals = function () {
- initOverlayScrollbarsStatics();
- var globals = FRAMEWORK.extend(true, {}, _pluginsGlobals);
- delete globals['msie'];
- return globals;
- };
-
- /**
- * Gets or Sets the default options for each new plugin initialization.
- * @param newDefaultOptions The object with which the default options shall be extended.
- */
- _plugin.defaultOptions = function (newDefaultOptions) {
- initOverlayScrollbarsStatics();
- var currDefaultOptions = _pluginsGlobals.defaultOptions;
- if (newDefaultOptions === undefined)
- return FRAMEWORK.extend(true, {}, currDefaultOptions);
-
- //set the new default options
- _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, {}, currDefaultOptions, _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true, currDefaultOptions)._default);
- };
-
- /**
- * Checks whether the passed instance is a non-destroyed OverlayScrollbars instance.
- * @param osInstance The potential OverlayScrollbars instance which shall be checked.
- * @returns {boolean} True if the passed value is a non-destroyed OverlayScrollbars instance, false otherwise.
- */
- _plugin.valid = function (osInstance) {
- return osInstance instanceof _plugin && !osInstance.getState().destroyed;
- };
-
- /**
- * Registers, Unregisters or returns a extension.
- * Register: Pass the name and the extension. (defaultOptions is optional)
- * Unregister: Pass the name and anything except a function as extension parameter.
- * Get extension: Pass the name of the extension which shall be got.
- * Get all extensions: Pass no arguments.
- * @param extensionName The name of the extension which shall be registered, unregistered or returned.
- * @param extension A function which generates the instance of the extension or anything other to remove a already registered extension.
- * @param defaultOptions The default options which shall be used for the registered extension.
- */
- _plugin.extension = function (extensionName, extension, defaultOptions) {
- var extNameTypeString = COMPATIBILITY.type(extensionName) == TYPES.s;
- var argLen = arguments[LEXICON.l];
- var i = 0;
- if (argLen < 1 || !extNameTypeString) {
- //return a copy of all extension objects
- return FRAMEWORK.extend(true, { length: _pluginsExtensions[LEXICON.l] }, _pluginsExtensions);
- }
- else if (extNameTypeString) {
- if (COMPATIBILITY.type(extension) == TYPES.f) {
- //register extension
- _pluginsExtensions.push({
- name: extensionName,
- extensionFactory: extension,
- defaultOptions: defaultOptions
- });
- }
- else {
- for (; i < _pluginsExtensions[LEXICON.l]; i++) {
- if (_pluginsExtensions[i].name === extensionName) {
- if (argLen > 1)
- _pluginsExtensions.splice(i, 1); //remove extension
- else
- return FRAMEWORK.extend(true, {}, _pluginsExtensions[i]); //return extension with the given name
- }
- }
- }
- }
- };
-
- return _plugin;
- })();
-
- if (JQUERY && JQUERY.fn) {
- /**
- * The jQuery initialization interface.
- * @param options The initial options for the construction of the plugin. To initialize the plugin, this option has to be a object! If it isn't a object, the instance(s) are returned and the plugin wont be initialized.
- * @param extensions The extension(s) which shall be added right after initialization.
- * @returns {*} After initialization it returns the jQuery element array, else it returns the instance(s) of the elements which are selected.
- */
- JQUERY.fn.overlayScrollbars = function (options, extensions) {
- var _elements = this;
- if (JQUERY.isPlainObject(options)) {
- JQUERY.each(_elements, function () { PLUGIN(this, options, extensions); });
- return _elements;
- }
- else
- return PLUGIN(_elements, options);
- };
- }
- return PLUGIN;
- }
+/*!
+ * OverlayScrollbars
+ * https://github.com/KingSora/OverlayScrollbars
+ *
+ * Version: 1.11.0
+ *
+ * Copyright KingSora | Rene Haas.
+ * https://github.com/KingSora
+ *
+ * Released under the MIT license.
+ * Date: 29.02.2020
+ */
+
+(function (global, factory) {
+ if (typeof define === 'function' && define.amd)
+ define(function () { return factory(global, global.document, undefined); });
+ else if (typeof module === 'object' && typeof module.exports === 'object')
+ module.exports = factory(global, global.document, undefined);
+ else
+ factory(global, global.document, undefined);
+}(typeof window !== 'undefined' ? window : this,
+ function (window, document, undefined) {
+ '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',
+ ti: 'tabindex',
+ 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 = window.jQuery;
+ var EASING = (function () {
+ var _easingsMath = {
+ p: MATH.PI,
+ c: MATH.cos,
+ s: MATH.sin,
+ w: MATH.pow,
+ t: MATH.sqrt,
+ n: MATH.asin,
+ a: MATH.abs,
+ o: 1.70158
+ };
+
+ /*
+ x : current percent (0 - 1),
+ t : current time (duration * percent),
+ b : start value (from),
+ c : end value (to),
+ d : duration
+
+ easingName : function(x, t, b, c, d) { return easedValue; }
+ */
+
+ return {
+ swing: function (x, t, b, c, d) {
+ return 0.5 - _easingsMath.c(x * _easingsMath.p) / 2;
+ },
+ linear: function (x, t, b, c, d) {
+ return x;
+ },
+ easeInQuad: function (x, t, b, c, d) {
+ return c * (t /= d) * t + b;
+ },
+ easeOutQuad: function (x, t, b, c, d) {
+ return -c * (t /= d) * (t - 2) + b;
+ },
+ easeInOutQuad: function (x, t, b, c, d) {
+ return ((t /= d / 2) < 1) ? c / 2 * t * t + b : -c / 2 * ((--t) * (t - 2) - 1) + b;
+ },
+ easeInCubic: function (x, t, b, c, d) {
+ return c * (t /= d) * t * t + b;
+ },
+ easeOutCubic: function (x, t, b, c, d) {
+ return c * ((t = t / d - 1) * t * t + 1) + b;
+ },
+ easeInOutCubic: function (x, t, b, c, d) {
+ return ((t /= d / 2) < 1) ? c / 2 * t * t * t + b : c / 2 * ((t -= 2) * t * t + 2) + b;
+ },
+ easeInQuart: function (x, t, b, c, d) {
+ return c * (t /= d) * t * t * t + b;
+ },
+ easeOutQuart: function (x, t, b, c, d) {
+ return -c * ((t = t / d - 1) * t * t * t - 1) + b;
+ },
+ easeInOutQuart: function (x, t, b, c, d) {
+ return ((t /= d / 2) < 1) ? c / 2 * t * t * t * t + b : -c / 2 * ((t -= 2) * t * t * t - 2) + b;
+ },
+ easeInQuint: function (x, t, b, c, d) {
+ return c * (t /= d) * t * t * t * t + b;
+ },
+ easeOutQuint: function (x, t, b, c, d) {
+ return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
+ },
+ easeInOutQuint: function (x, t, b, c, d) {
+ return ((t /= d / 2) < 1) ? c / 2 * t * t * t * t * t + b : c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
+ },
+ easeInSine: function (x, t, b, c, d) {
+ return -c * _easingsMath.c(t / d * (_easingsMath.p / 2)) + c + b;
+ },
+ easeOutSine: function (x, t, b, c, d) {
+ return c * _easingsMath.s(t / d * (_easingsMath.p / 2)) + b;
+ },
+ easeInOutSine: function (x, t, b, c, d) {
+ return -c / 2 * (_easingsMath.c(_easingsMath.p * t / d) - 1) + b;
+ },
+ easeInExpo: function (x, t, b, c, d) {
+ return (t == 0) ? b : c * _easingsMath.w(2, 10 * (t / d - 1)) + b;
+ },
+ easeOutExpo: function (x, t, b, c, d) {
+ return (t == d) ? b + c : c * (-_easingsMath.w(2, -10 * t / d) + 1) + b;
+ },
+ easeInOutExpo: function (x, t, b, c, d) {
+ if (t == 0) return b;
+ if (t == d) return b + c;
+ if ((t /= d / 2) < 1) return c / 2 * _easingsMath.w(2, 10 * (t - 1)) + b;
+ return c / 2 * (-_easingsMath.w(2, -10 * --t) + 2) + b;
+ },
+ easeInCirc: function (x, t, b, c, d) {
+ return -c * (_easingsMath.t(1 - (t /= d) * t) - 1) + b;
+ },
+ easeOutCirc: function (x, t, b, c, d) {
+ return c * _easingsMath.t(1 - (t = t / d - 1) * t) + b;
+ },
+ easeInOutCirc: function (x, t, b, c, d) {
+ return ((t /= d / 2) < 1) ? -c / 2 * (_easingsMath.t(1 - t * t) - 1) + b : c / 2 * (_easingsMath.t(1 - (t -= 2) * t) + 1) + b;
+ },
+ easeInElastic: function (x, t, b, c, d) {
+ var s = _easingsMath.o; var p = 0; var a = c;
+ if (t == 0) return b; if ((t /= d) == 1) return b + c; if (!p) p = d * .3;
+ if (a < _easingsMath.a(c)) { a = c; s = p / 4; }
+ else s = p / (2 * _easingsMath.p) * _easingsMath.n(c / a);
+ return -(a * _easingsMath.w(2, 10 * (t -= 1)) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p)) + b;
+ },
+ easeOutElastic: function (x, t, b, c, d) {
+ var s = _easingsMath.o; var p = 0; var a = c;
+ if (t == 0) return b;
+ if ((t /= d) == 1) return b + c;
+ if (!p) p = d * .3;
+ if (a < _easingsMath.a(c)) { a = c; s = p / 4; }
+ else s = p / (2 * _easingsMath.p) * _easingsMath.n(c / a);
+ return a * _easingsMath.w(2, -10 * t) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p) + c + b;
+ },
+ easeInOutElastic: function (x, t, b, c, d) {
+ var s = _easingsMath.o; var p = 0; var a = c;
+ if (t == 0) return b;
+ if ((t /= d / 2) == 2) return b + c;
+ if (!p) p = d * (.3 * 1.5);
+ if (a < _easingsMath.a(c)) { a = c; s = p / 4; }
+ else s = p / (2 * _easingsMath.p) * _easingsMath.n(c / a);
+ if (t < 1) return -.5 * (a * _easingsMath.w(2, 10 * (t -= 1)) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p)) + b;
+ return a * _easingsMath.w(2, -10 * (t -= 1)) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p) * .5 + c + b;
+ },
+ easeInBack: function (x, t, b, c, d, s) {
+ s = s || _easingsMath.o;
+ return c * (t /= d) * t * ((s + 1) * t - s) + b;
+ },
+ easeOutBack: function (x, t, b, c, d, s) {
+ s = s || _easingsMath.o;
+ return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
+ },
+ easeInOutBack: function (x, t, b, c, d, s) {
+ s = s || _easingsMath.o;
+ return ((t /= d / 2) < 1) ? c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b : c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
+ },
+ easeInBounce: function (x, t, b, c, d) {
+ return c - this.easeOutBounce(x, d - t, 0, c, d) + b;
+ },
+ easeOutBounce: function (x, t, b, c, d) {
+ var o = 7.5625;
+ if ((t /= d) < (1 / 2.75)) {
+ return c * (o * t * t) + b;
+ } else if (t < (2 / 2.75)) {
+ return c * (o * (t -= (1.5 / 2.75)) * t + .75) + b;
+ } else if (t < (2.5 / 2.75)) {
+ return c * (o * (t -= (2.25 / 2.75)) * t + .9375) + b;
+ } else {
+ return c * (o * (t -= (2.625 / 2.75)) * t + .984375) + b;
+ }
+ },
+ easeInOutBounce: function (x, t, b, c, d) {
+ return (t < d / 2) ? this.easeInBounce(x, t * 2, 0, c, d) * .5 + b : this.easeOutBounce(x, t * 2 - d, 0, c, d) * .5 + c * .5 + b;
+ }
+ };
+ /*
+ *
+ * TERMS OF USE - EASING EQUATIONS
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+ })();
+ var FRAMEWORK = (function () {
+ var _rnothtmlwhite = (/[^\x20\t\r\n\f]+/g);
+ var _strSpace = ' ';
+ var _strEmpty = '';
+ var _strScrollLeft = 'scrollLeft';
+ var _strScrollTop = 'scrollTop';
+ var _animations = [];
+ var _type = COMPATIBILITY.type;
+ var _cssNumber = {
+ animationIterationCount: true,
+ columnCount: true,
+ fillOpacity: true,
+ flexGrow: true,
+ flexShrink: true,
+ fontWeight: true,
+ lineHeight: true,
+ opacity: true,
+ order: true,
+ orphans: true,
+ widows: true,
+ zIndex: true,
+ zoom: true
+ };
+
+ function extend() {
+ var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {},
+ i = 1,
+ length = arguments[LEXICON.l],
+ deep = false;
+
+ // Handle a deep copy situation
+ if (_type(target) == TYPES.b) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if (_type(target) != TYPES.o && !_type(target) == TYPES.f) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if (length === i) {
+ target = FakejQuery;
+ --i;
+ }
+
+ for (; i < length; i++) {
+ // Only deal with non-null/undefined values
+ if ((options = arguments[i]) != null) {
+ // Extend the base object
+ for (name in options) {
+ src = target[name];
+ copy = options[name];
+
+ // Prevent never-ending loop
+ if (target === copy) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if (deep && copy && (isPlainObject(copy) || (copyIsArray = COMPATIBILITY.isA(copy)))) {
+ if (copyIsArray) {
+ copyIsArray = false;
+ clone = src && COMPATIBILITY.isA(src) ? src : [];
+
+ } else {
+ clone = src && isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[name] = extend(deep, clone, copy);
+
+ // Don't bring in undefined values
+ } else if (copy !== undefined) {
+ target[name] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+ };
+
+ function inArray(item, arr, fromIndex) {
+ for (var i = fromIndex || 0; i < arr[LEXICON.l]; i++)
+ if (arr[i] === item)
+ return i;
+ return -1;
+ }
+
+ function isFunction(obj) {
+ return _type(obj) == TYPES.f;
+ };
+
+ function isEmptyObject(obj) {
+ for (var name in obj)
+ return false;
+ return true;
+ };
+
+ function isPlainObject(obj) {
+ if (!obj || _type(obj) != TYPES.o)
+ return false;
+
+ var key;
+ var proto = LEXICON.p;
+ var hasOwnProperty = Object[proto].hasOwnProperty;
+ var hasOwnConstructor = hasOwnProperty.call(obj, 'constructor');
+ var hasIsPrototypeOf = obj.constructor && obj.constructor[proto] && hasOwnProperty.call(obj.constructor[proto], 'isPrototypeOf');
+
+ if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
+ return false;
+ }
+
+
+ for (key in obj) { /**/ }
+
+ return _type(key) == TYPES.u || hasOwnProperty.call(obj, key);
+ };
+
+ function each(obj, callback) {
+ var i = 0;
+
+ if (isArrayLike(obj)) {
+ for (; i < obj[LEXICON.l]; i++) {
+ if (callback.call(obj[i], i, obj[i]) === false)
+ break;
+ }
+ }
+ else {
+ for (i in obj) {
+ if (callback.call(obj[i], i, obj[i]) === false)
+ break;
+ }
+ }
+
+ return obj;
+ };
+
+ function isArrayLike(obj) {
+ var length = !!obj && [LEXICON.l] in obj && obj[LEXICON.l];
+ var t = _type(obj);
+ return isFunction(t) ? false : (t == TYPES.a || length === 0 || _type(length) == TYPES.n && length > 0 && (length - 1) in obj);
+ }
+
+ function stripAndCollapse(value) {
+ var tokens = value.match(_rnothtmlwhite) || [];
+ return tokens.join(_strSpace);
+ }
+
+ function matches(elem, selector) {
+ var nodeList = (elem.parentNode || document).querySelectorAll(selector) || [];
+ var i = nodeList[LEXICON.l];
+
+ while (i--)
+ if (nodeList[i] == elem)
+ return true;
+
+ return false;
+ }
+
+ function insertAdjacentElement(el, strategy, child) {
+ if (_type(child) == TYPES.a) {
+ for (var i = 0; i < child[LEXICON.l]; i++)
+ insertAdjacentElement(el, strategy, child[i]);
+ }
+ else if (_type(child) == TYPES.s)
+ el.insertAdjacentHTML(strategy, child);
+ else
+ el.insertAdjacentElement(strategy, child.nodeType ? child : child[0]);
+ }
+
+ function setCSSVal(el, prop, val) {
+ try {
+ if (el[LEXICON.s][prop] !== undefined)
+ el[LEXICON.s][prop] = parseCSSVal(prop, val);
+ } catch (e) { }
+ }
+
+ function parseCSSVal(prop, val) {
+ if (!_cssNumber[prop.toLowerCase()] && _type(val) == TYPES.n)
+ val += 'px';
+ return val;
+ }
+
+ function startNextAnimationInQ(animObj, removeFromQ) {
+ var index;
+ var nextAnim;
+ if (removeFromQ !== false)
+ animObj.q.splice(0, 1);
+ if (animObj.q[LEXICON.l] > 0) {
+ nextAnim = animObj.q[0];
+ animate(animObj.el, nextAnim.props, nextAnim.duration, nextAnim.easing, nextAnim.complete, true);
+ }
+ else {
+ index = inArray(animObj, _animations);
+ if (index > -1)
+ _animations.splice(index, 1);
+ }
+ }
+
+ function setAnimationValue(el, prop, value) {
+ if (prop === _strScrollLeft || prop === _strScrollTop)
+ el[prop] = value;
+ else
+ setCSSVal(el, prop, value);
+ }
+
+ function animate(el, props, options, easing, complete, guaranteedNext) {
+ var hasOptions = isPlainObject(options);
+ var from = {};
+ var to = {};
+ var i = 0;
+ var key;
+ var animObj;
+ var start;
+ var progress;
+ var step;
+ var specialEasing;
+ var duration;
+ if (hasOptions) {
+ easing = options.easing;
+ start = options.start;
+ progress = options.progress;
+ step = options.step;
+ specialEasing = options.specialEasing;
+ complete = options.complete;
+ duration = options.duration;
+ }
+ else
+ duration = options;
+ specialEasing = specialEasing || {};
+ duration = duration || 400;
+ easing = easing || 'swing';
+ guaranteedNext = guaranteedNext || false;
+
+ for (; i < _animations[LEXICON.l]; i++) {
+ if (_animations[i].el === el) {
+ animObj = _animations[i];
+ break;
+ }
+ }
+
+ if (!animObj) {
+ animObj = {
+ el: el,
+ q: []
+ };
+ _animations.push(animObj);
+ }
+
+ for (key in props) {
+ if (key === _strScrollLeft || key === _strScrollTop)
+ from[key] = el[key];
+ else
+ from[key] = FakejQuery(el).css(key);
+ }
+
+ for (key in from) {
+ if (from[key] !== props[key] && props[key] !== undefined)
+ to[key] = props[key];
+ }
+
+ if (!isEmptyObject(to)) {
+ var timeNow;
+ var end;
+ var percent;
+ var fromVal;
+ var toVal;
+ var easedVal;
+ var timeStart;
+ var frame;
+ var elapsed;
+ var qPos = guaranteedNext ? 0 : inArray(qObj, animObj.q);
+ var qObj = {
+ props: to,
+ duration: hasOptions ? options : duration,
+ easing: easing,
+ complete: complete
+ };
+ if (qPos === -1) {
+ qPos = animObj.q[LEXICON.l];
+ animObj.q.push(qObj);
+ }
+
+ if (qPos === 0) {
+ if (duration > 0) {
+ timeStart = COMPATIBILITY.now();
+ frame = function () {
+ timeNow = COMPATIBILITY.now();
+ elapsed = (timeNow - timeStart);
+ end = qObj.stop || elapsed >= duration;
+ percent = 1 - ((MATH.max(0, timeStart + duration - timeNow) / duration) || 0);
+
+ for (key in to) {
+ fromVal = parseFloat(from[key]);
+ toVal = parseFloat(to[key]);
+ easedVal = (toVal - fromVal) * EASING[specialEasing[key] || easing](percent, percent * duration, 0, 1, duration) + fromVal;
+ setAnimationValue(el, key, easedVal);
+ if (isFunction(step)) {
+ step(easedVal, {
+ elem: el,
+ prop: key,
+ start: fromVal,
+ now: easedVal,
+ end: toVal,
+ pos: percent,
+ options: {
+ easing: easing,
+ speacialEasing: specialEasing,
+ duration: duration,
+ complete: complete,
+ step: step
+ },
+ startTime: timeStart
+ });
+ }
+ }
+
+ if (isFunction(progress))
+ progress({}, percent, MATH.max(0, duration - elapsed));
+
+ if (end) {
+ startNextAnimationInQ(animObj);
+ if (isFunction(complete))
+ complete();
+ }
+ else
+ qObj.frame = COMPATIBILITY.rAF()(frame);
+ };
+ qObj.frame = COMPATIBILITY.rAF()(frame);
+ }
+ else {
+ for (key in to)
+ setAnimationValue(el, key, to[key]);
+ startNextAnimationInQ(animObj);
+ }
+ }
+ }
+ else if (guaranteedNext)
+ startNextAnimationInQ(animObj);
+ }
+
+ function stop(el, clearQ, jumpToEnd) {
+ var animObj;
+ var qObj;
+ var key;
+ var i = 0;
+ for (; i < _animations[LEXICON.l]; i++) {
+ animObj = _animations[i];
+ if (animObj.el === el) {
+ if (animObj.q[LEXICON.l] > 0) {
+ qObj = animObj.q[0];
+ qObj.stop = true;
+ COMPATIBILITY.cAF()(qObj.frame);
+ animObj.q.splice(0, 1);
+
+ if (jumpToEnd)
+ for (key in qObj.props)
+ setAnimationValue(el, key, qObj.props[key]);
+
+ if (clearQ)
+ animObj.q = [];
+ else
+ startNextAnimationInQ(animObj, false);
+ }
+ break;
+ }
+ }
+ }
+
+ function elementIsVisible(el) {
+ return !!(el[LEXICON.oW] || el[LEXICON.oH] || el.getClientRects()[LEXICON.l]);
+ }
+
+ function FakejQuery(selector) {
+ if (arguments[LEXICON.l] === 0)
+ return this;
+
+ var base = new FakejQuery();
+ var elements = selector;
+ var i = 0;
+ var elms;
+ var el;
+
+ if (_type(selector) == TYPES.s) {
+ elements = [];
+ if (selector.charAt(0) === '<') {
+ el = document.createElement('div');
+ el.innerHTML = selector;
+ elms = el.children;
+ }
+ else {
+ elms = document.querySelectorAll(selector);
+ }
+
+ for (; i < elms[LEXICON.l]; i++)
+ elements.push(elms[i]);
+ }
+
+ if (elements) {
+ if (_type(elements) != TYPES.s && (!isArrayLike(elements) || elements === window || elements === elements.self))
+ elements = [elements];
+
+ for (i = 0; i < elements[LEXICON.l]; i++)
+ base[i] = elements[i];
+
+ base[LEXICON.l] = elements[LEXICON.l];
+ }
+
+ return base;
+ };
+
+ FakejQuery[LEXICON.p] = {
+
+ //EVENTS:
+
+ on: function (eventName, handler) {
+ eventName = (eventName || _strEmpty).match(_rnothtmlwhite) || [_strEmpty];
+
+ var eventNameLength = eventName[LEXICON.l];
+ var i = 0;
+ var el;
+ return this.each(function () {
+ el = this;
+ try {
+ if (el.addEventListener) {
+ for (; i < eventNameLength; i++)
+ el.addEventListener(eventName[i], handler);
+ }
+ else if (el.detachEvent) {
+ for (; i < eventNameLength; i++)
+ el.attachEvent('on' + eventName[i], handler);
+ }
+ } catch (e) { }
+ });
+ },
+
+ off: function (eventName, handler) {
+ eventName = (eventName || _strEmpty).match(_rnothtmlwhite) || [_strEmpty];
+
+ var eventNameLength = eventName[LEXICON.l];
+ var i = 0;
+ var el;
+ return this.each(function () {
+ el = this;
+ try {
+ if (el.removeEventListener) {
+ for (; i < eventNameLength; i++)
+ el.removeEventListener(eventName[i], handler);
+ }
+ else if (el.detachEvent) {
+ for (; i < eventNameLength; i++)
+ el.detachEvent('on' + eventName[i], handler);
+ }
+ } catch (e) { }
+ });
+ },
+
+ one: function (eventName, handler) {
+ eventName = (eventName || _strEmpty).match(_rnothtmlwhite) || [_strEmpty];
+ return this.each(function () {
+ var el = FakejQuery(this);
+ FakejQuery.each(eventName, function (i, oneEventName) {
+ var oneHandler = function (e) {
+ handler.call(this, e);
+ el.off(oneEventName, oneHandler);
+ };
+ el.on(oneEventName, oneHandler);
+ });
+ });
+ },
+
+ trigger: function (eventName) {
+ var el;
+ var event;
+ return this.each(function () {
+ el = this;
+ if (document.createEvent) {
+ event = document.createEvent('HTMLEvents');
+ event.initEvent(eventName, true, false);
+ el.dispatchEvent(event);
+ }
+ else {
+ el.fireEvent('on' + eventName);
+ }
+ });
+ },
+
+ //DOM NODE INSERTING / REMOVING:
+
+ append: function (child) {
+ return this.each(function () { insertAdjacentElement(this, 'beforeend', child); });
+ },
+
+ prepend: function (child) {
+ return this.each(function () { insertAdjacentElement(this, 'afterbegin', child); });
+ },
+
+ before: function (child) {
+ return this.each(function () { insertAdjacentElement(this, 'beforebegin', child); });
+ },
+
+ after: function (child) {
+ return this.each(function () { insertAdjacentElement(this, 'afterend', child); });
+ },
+
+ remove: function () {
+ return this.each(function () {
+ var el = this;
+ var parentNode = el.parentNode;
+ if (parentNode != null)
+ parentNode.removeChild(el);
+ });
+ },
+
+ unwrap: function () {
+ var parents = [];
+ var i;
+ var el;
+ var parent;
+
+ this.each(function () {
+ parent = this.parentNode;
+ if (inArray(parent, parents) === - 1)
+ parents.push(parent);
+ });
+
+ for (i = 0; i < parents[LEXICON.l]; i++) {
+ el = parents[i];
+ parent = el.parentNode;
+ while (el.firstChild)
+ parent.insertBefore(el.firstChild, el);
+ parent.removeChild(el);
+ }
+
+ return this;
+ },
+
+ wrapAll: function (wrapperHTML) {
+ var i;
+ var nodes = this;
+ var wrapper = FakejQuery(wrapperHTML)[0];
+ var deepest = wrapper;
+ var parent = nodes[0].parentNode;
+ var previousSibling = nodes[0].previousSibling;
+ while (deepest.childNodes[LEXICON.l] > 0)
+ deepest = deepest.childNodes[0];
+
+ for (i = 0; nodes[LEXICON.l] - i; deepest.firstChild === nodes[0] && i++)
+ deepest.appendChild(nodes[i]);
+
+ var nextSibling = previousSibling ? previousSibling.nextSibling : parent.firstChild;
+ parent.insertBefore(wrapper, nextSibling);
+
+ return this;
+ },
+
+ wrapInner: function (wrapperHTML) {
+ return this.each(function () {
+ var el = FakejQuery(this);
+ var contents = el.contents();
+
+ if (contents[LEXICON.l])
+ contents.wrapAll(wrapperHTML);
+ else
+ el.append(wrapperHTML);
+ });
+ },
+
+ wrap: function (wrapperHTML) {
+ return this.each(function () { FakejQuery(this).wrapAll(wrapperHTML); });
+ },
+
+
+ //DOM NODE MANIPULATION / INFORMATION:
+
+ css: function (styles, val) {
+ var el;
+ var key;
+ var cptStyle;
+ var getCptStyle = window.getComputedStyle;
+ if (_type(styles) == TYPES.s) {
+ if (val === undefined) {
+ el = this[0];
+ cptStyle = getCptStyle ? getCptStyle(el, null) : el.currentStyle[styles];
+
+ //https://bugzilla.mozilla.org/show_bug.cgi?id=548397 can be null sometimes if iframe with display: none (firefox only!)
+ return getCptStyle ? cptStyle != null ? cptStyle.getPropertyValue(styles) : el[LEXICON.s][styles] : cptStyle;
+ }
+ else {
+ return this.each(function () {
+ setCSSVal(this, styles, val);
+ });
+ }
+ }
+ else {
+ return this.each(function () {
+ for (key in styles)
+ setCSSVal(this, key, styles[key]);
+ });
+ }
+ },
+
+ hasClass: function (className) {
+ var elem, i = 0;
+ var classNamePrepared = _strSpace + className + _strSpace;
+ var classList;
+
+ while ((elem = this[i++])) {
+ classList = elem.classList;
+ if (classList && classList.contains(className))
+ return true;
+ else if (elem.nodeType === 1 && (_strSpace + stripAndCollapse(elem.className + _strEmpty) + _strSpace).indexOf(classNamePrepared) > -1)
+ return true;
+ }
+
+ return false;
+ },
+
+ addClass: function (className) {
+ var classes;
+ var elem;
+ var cur;
+ var curValue;
+ var clazz;
+ var finalValue;
+ var supportClassList;
+ var elmClassList;
+ var i = 0;
+ var v = 0;
+
+ if (className) {
+ classes = className.match(_rnothtmlwhite) || [];
+
+ while ((elem = this[i++])) {
+ elmClassList = elem.classList;
+ if (supportClassList === undefined)
+ supportClassList = elmClassList !== undefined;
+
+ if (supportClassList) {
+ while ((clazz = classes[v++]))
+ elmClassList.add(clazz);
+ }
+ else {
+ curValue = elem.className + _strEmpty;
+ cur = elem.nodeType === 1 && (_strSpace + stripAndCollapse(curValue) + _strSpace);
+
+ if (cur) {
+ while ((clazz = classes[v++]))
+ if (cur.indexOf(_strSpace + clazz + _strSpace) < 0)
+ cur += clazz + _strSpace;
+
+ finalValue = stripAndCollapse(cur);
+ if (curValue !== finalValue)
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function (className) {
+ var classes;
+ var elem;
+ var cur;
+ var curValue;
+ var clazz;
+ var finalValue;
+ var supportClassList;
+ var elmClassList;
+ var i = 0;
+ var v = 0;
+
+ if (className) {
+ classes = className.match(_rnothtmlwhite) || [];
+
+ while ((elem = this[i++])) {
+ elmClassList = elem.classList;
+ if (supportClassList === undefined)
+ supportClassList = elmClassList !== undefined;
+
+ if (supportClassList) {
+ while ((clazz = classes[v++]))
+ elmClassList.remove(clazz);
+ }
+ else {
+ curValue = elem.className + _strEmpty;
+ cur = elem.nodeType === 1 && (_strSpace + stripAndCollapse(curValue) + _strSpace);
+
+ if (cur) {
+ while ((clazz = classes[v++]))
+ while (cur.indexOf(_strSpace + clazz + _strSpace) > -1)
+ cur = cur.replace(_strSpace + clazz + _strSpace, _strSpace);
+
+ finalValue = stripAndCollapse(cur);
+ if (curValue !== finalValue)
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ hide: function () {
+ return this.each(function () { this[LEXICON.s].display = 'none'; });
+ },
+
+ show: function () {
+ return this.each(function () { this[LEXICON.s].display = 'block'; });
+ },
+
+ attr: function (attrName, value) {
+ var i = 0;
+ var el;
+ while (el = this[i++]) {
+ if (value === undefined)
+ return el.getAttribute(attrName);
+ el.setAttribute(attrName, value);
+ }
+ return this;
+ },
+
+ removeAttr: function (attrName) {
+ return this.each(function () { this.removeAttribute(attrName); });
+ },
+
+ offset: function () {
+ var el = this[0];
+ var rect = el[LEXICON.bCR]();
+ var scrollLeft = window.pageXOffset || document.documentElement[_strScrollLeft];
+ var scrollTop = window.pageYOffset || document.documentElement[_strScrollTop];
+ return {
+ top: rect.top + scrollTop,
+ left: rect.left + scrollLeft
+ };
+ },
+
+ position: function () {
+ var el = this[0];
+ return {
+ top: el.offsetTop,
+ left: el.offsetLeft
+ };
+ },
+
+ scrollLeft: function (value) {
+ var i = 0;
+ var el;
+ while (el = this[i++]) {
+ if (value === undefined)
+ return el[_strScrollLeft];
+ el[_strScrollLeft] = value;
+ }
+ return this;
+ },
+
+ scrollTop: function (value) {
+ var i = 0;
+ var el;
+ while (el = this[i++]) {
+ if (value === undefined)
+ return el[_strScrollTop];
+ el[_strScrollTop] = value;
+ }
+ return this;
+ },
+
+ val: function (value) {
+ var el = this[0];
+ if (!value)
+ return el.value;
+ el.value = value;
+ return this;
+ },
+
+
+ //DOM TRAVERSAL / FILTERING:
+
+ first: function () {
+ return this.eq(0);
+ },
+
+ last: function () {
+ return this.eq(-1);
+ },
+
+ eq: function (index) {
+ return FakejQuery(this[index >= 0 ? index : this[LEXICON.l] + index]);
+ },
+
+ find: function (selector) {
+ var children = [];
+ var i;
+ this.each(function () {
+ var el = this;
+ var ch = el.querySelectorAll(selector);
+ for (i = 0; i < ch[LEXICON.l]; i++)
+ children.push(ch[i]);
+ });
+ return FakejQuery(children);
+ },
+
+ children: function (selector) {
+ var children = [];
+ var el;
+ var ch;
+ var i;
+
+ this.each(function () {
+ ch = this.children;
+ for (i = 0; i < ch[LEXICON.l]; i++) {
+ el = ch[i];
+ if (selector) {
+ if ((el.matches && el.matches(selector)) || matches(el, selector))
+ children.push(el);
+ }
+ else
+ children.push(el);
+ }
+ });
+ return FakejQuery(children);
+ },
+
+ parent: function (selector) {
+ var parents = [];
+ var parent;
+ this.each(function () {
+ parent = this.parentNode;
+ if (selector ? FakejQuery(parent).is(selector) : true)
+ parents.push(parent);
+ });
+ return FakejQuery(parents);
+ },
+
+ is: function (selector) {
+
+ var el;
+ var i;
+ for (i = 0; i < this[LEXICON.l]; i++) {
+ el = this[i];
+ if (selector === ':visible')
+ return elementIsVisible(el);
+ if (selector === ':hidden')
+ return !elementIsVisible(el);
+ if ((el.matches && el.matches(selector)) || matches(el, selector))
+ return true;
+ }
+ return false;
+ },
+
+ contents: function () {
+ var contents = [];
+ var childs;
+ var i;
+
+ this.each(function () {
+ childs = this.childNodes;
+ for (i = 0; i < childs[LEXICON.l]; i++)
+ contents.push(childs[i]);
+ });
+
+ return FakejQuery(contents);
+ },
+
+ each: function (callback) {
+ return each(this, callback);
+ },
+
+
+ //ANIMATION:
+
+ animate: function (props, duration, easing, complete) {
+ return this.each(function () { animate(this, props, duration, easing, complete); });
+ },
+
+ stop: function (clearQ, jump) {
+ return this.each(function () { stop(this, clearQ, jump); });
+ }
+ };
+
+ extend(FakejQuery, {
+ extend: extend,
+ inArray: inArray,
+ isEmptyObject: isEmptyObject,
+ isPlainObject: isPlainObject,
+ each: each
+ });
+
+ return FakejQuery;
+ })();
+ 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('
');
+ 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
+ //since 1.11.0 always false -> fixed via CSS (hopefully)
+ 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();
+ //https://github.com/KingSora/OverlayScrollbars/issues/187
+ scrollbarDummyElement.scrollLeft(-999);
+ var dummyContainerChildOffsetAfterScroll = 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 !== dummyContainerChildOffsetAfterScroll.left
+ };
+ })(),
+ 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 which manages the scrollbars visibility of the target element.
+ * @param pluginTargetElement The element from which the scrollbars shall be hidden.
+ * @param options The custom options.
+ * @param extensions The custom extensions.
+ * @param globals
+ * @param autoUpdateLoop
+ * @returns {*}
+ * @constructor
+ */
+ function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) {
+ //shortcuts
+ var type = COMPATIBILITY.type;
+ var inArray = FRAMEWORK.inArray;
+ var each = FRAMEWORK.each;
+
+ //make correct instanceof
+ var _base = new _plugin();
+ var _frameworkProto = FRAMEWORK[LEXICON.p];
+
+ //if passed element is no HTML element: skip and return
+ if (!isHTMLElement(pluginTargetElement))
+ return;
+
+ //if passed element is already initialized: set passed options if there are any and return its instance
+ if (INSTANCES(pluginTargetElement)) {
+ var inst = INSTANCES(pluginTargetElement);
+ inst.options(options);
+ return inst;
+ }
+
+ //globals:
+ var _nativeScrollbarIsOverlaid;
+ var _overlayScrollbarDummySize;
+ var _rtlScrollBehavior;
+ var _autoUpdateRecommended;
+ var _msieVersion;
+ var _nativeScrollbarStyling;
+ var _cssCalc;
+ var _nativeScrollbarSize;
+ var _supportTransition;
+ var _supportTransform;
+ var _supportPassiveEvents;
+ var _supportResizeObserver;
+ var _supportMutationObserver;
+ var _restrictedMeasuring;
+
+ //general readonly:
+ var _initialized;
+ var _destroyed;
+ var _isTextarea;
+ var _isBody;
+ var _documentMixed;
+ var _domExists;
+
+ //general:
+ var _isBorderBox;
+ var _sizeAutoObserverAdded;
+ var _paddingX;
+ var _paddingY;
+ var _borderX;
+ var _borderY;
+ var _marginX;
+ var _marginY;
+ var _isRTL;
+ var _sleeping;
+ var _contentBorderSize = {};
+ var _scrollHorizontalInfo = {};
+ var _scrollVerticalInfo = {};
+ var _viewportSize = {};
+ var _nativeScrollbarMinSize = {};
+
+ //naming:
+ var _strMinusHidden = '-hidden';
+ var _strMarginMinus = 'margin-';
+ var _strPaddingMinus = 'padding-';
+ var _strBorderMinus = 'border-';
+ var _strTop = 'top';
+ var _strRight = 'right';
+ var _strBottom = 'bottom';
+ var _strLeft = 'left';
+ var _strMinMinus = 'min-';
+ var _strMaxMinus = 'max-';
+ var _strWidth = 'width';
+ var _strHeight = 'height';
+ var _strFloat = 'float';
+ var _strEmpty = '';
+ var _strAuto = 'auto';
+ var _strSync = 'sync';
+ var _strScroll = 'scroll';
+ var _strHundredPercent = '100%';
+ var _strX = 'x';
+ var _strY = 'y';
+ var _strDot = '.';
+ var _strSpace = ' ';
+ var _strScrollbar = 'scrollbar';
+ var _strMinusHorizontal = '-horizontal';
+ var _strMinusVertical = '-vertical';
+ var _strScrollLeft = _strScroll + 'Left';
+ var _strScrollTop = _strScroll + 'Top';
+ var _strMouseTouchDownEvent = 'mousedown touchstart';
+ var _strMouseTouchUpEvent = 'mouseup touchend touchcancel';
+ var _strMouseTouchMoveEvent = 'mousemove touchmove';
+ var _strMouseTouchEnter = 'mouseenter';
+ var _strMouseTouchLeave = 'mouseleave';
+ var _strKeyDownEvent = 'keydown';
+ var _strKeyUpEvent = 'keyup';
+ var _strSelectStartEvent = 'selectstart';
+ var _strTransitionEndEvent = 'transitionend webkitTransitionEnd oTransitionEnd';
+ var _strResizeObserverProperty = '__overlayScrollbarsRO__';
+
+ //class names:
+ var _cassNamesPrefix = 'os-';
+ var _classNameHTMLElement = _cassNamesPrefix + 'html';
+ var _classNameHostElement = _cassNamesPrefix + 'host';
+ var _classNameHostTextareaElement = _classNameHostElement + '-textarea';
+ var _classNameHostScrollbarHorizontalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusHorizontal + _strMinusHidden;
+ var _classNameHostScrollbarVerticalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusVertical + _strMinusHidden;
+ var _classNameHostTransition = _classNameHostElement + '-transition';
+ var _classNameHostRTL = _classNameHostElement + '-rtl';
+ var _classNameHostResizeDisabled = _classNameHostElement + '-resize-disabled';
+ var _classNameHostScrolling = _classNameHostElement + '-scrolling';
+ var _classNameHostOverflow = _classNameHostElement + '-overflow';
+ var _classNameHostOverflowX = _classNameHostOverflow + '-x';
+ var _classNameHostOverflowY = _classNameHostOverflow + '-y';
+ var _classNameTextareaElement = _cassNamesPrefix + 'textarea';
+ var _classNameTextareaCoverElement = _classNameTextareaElement + '-cover';
+ var _classNamePaddingElement = _cassNamesPrefix + 'padding';
+ var _classNameViewportElement = _cassNamesPrefix + 'viewport';
+ var _classNameViewportNativeScrollbarsInvisible = _classNameViewportElement + '-native-scrollbars-invisible';
+ var _classNameViewportNativeScrollbarsOverlaid = _classNameViewportElement + '-native-scrollbars-overlaid';
+ var _classNameContentElement = _cassNamesPrefix + 'content';
+ var _classNameContentArrangeElement = _cassNamesPrefix + 'content-arrange';
+ var _classNameContentGlueElement = _cassNamesPrefix + 'content-glue';
+ var _classNameSizeAutoObserverElement = _cassNamesPrefix + 'size-auto-observer';
+ var _classNameResizeObserverElement = _cassNamesPrefix + 'resize-observer';
+ var _classNameResizeObserverItemElement = _cassNamesPrefix + 'resize-observer-item';
+ var _classNameResizeObserverItemFinalElement = _classNameResizeObserverItemElement + '-final';
+ var _classNameTextInherit = _cassNamesPrefix + 'text-inherit';
+ var _classNameScrollbar = _cassNamesPrefix + _strScrollbar;
+ var _classNameScrollbarTrack = _classNameScrollbar + '-track';
+ var _classNameScrollbarTrackOff = _classNameScrollbarTrack + '-off';
+ var _classNameScrollbarHandle = _classNameScrollbar + '-handle';
+ var _classNameScrollbarHandleOff = _classNameScrollbarHandle + '-off';
+ var _classNameScrollbarUnusable = _classNameScrollbar + '-unusable';
+ var _classNameScrollbarAutoHidden = _classNameScrollbar + '-' + _strAuto + _strMinusHidden;
+ var _classNameScrollbarCorner = _classNameScrollbar + '-corner';
+ var _classNameScrollbarCornerResize = _classNameScrollbarCorner + '-resize';
+ var _classNameScrollbarCornerResizeB = _classNameScrollbarCornerResize + '-both';
+ var _classNameScrollbarCornerResizeH = _classNameScrollbarCornerResize + _strMinusHorizontal;
+ var _classNameScrollbarCornerResizeV = _classNameScrollbarCornerResize + _strMinusVertical;
+ var _classNameScrollbarHorizontal = _classNameScrollbar + _strMinusHorizontal;
+ var _classNameScrollbarVertical = _classNameScrollbar + _strMinusVertical;
+ var _classNameDragging = _cassNamesPrefix + 'dragging';
+ var _classNameThemeNone = _cassNamesPrefix + 'theme-none';
+ var _classNamesDynamicDestroy = [
+ _classNameViewportNativeScrollbarsInvisible,
+ _classNameViewportNativeScrollbarsOverlaid,
+ _classNameScrollbarTrackOff,
+ _classNameScrollbarHandleOff,
+ _classNameScrollbarUnusable,
+ _classNameScrollbarAutoHidden,
+ _classNameScrollbarCornerResize,
+ _classNameScrollbarCornerResizeB,
+ _classNameScrollbarCornerResizeH,
+ _classNameScrollbarCornerResizeV,
+ _classNameDragging].join(_strSpace);
+
+ //callbacks:
+ var _callbacksInitQeueue = [];
+
+ //attrs viewport shall inherit from target
+ var _viewportAttrsFromTarget = [LEXICON.ti];
+
+ //options:
+ var _defaultOptions;
+ var _currentOptions;
+ var _currentPreparedOptions;
+
+ //extensions:
+ var _extensions = {};
+ var _extensionsPrivateMethods = 'added removed on contract';
+
+ //update
+ var _lastUpdateTime;
+ var _swallowedUpdateHints = {};
+ var _swallowedUpdateTimeout;
+ var _swallowUpdateLag = 42;
+ var _imgs = [];
+
+ //DOM elements:
+ var _windowElement;
+ var _documentElement;
+ var _htmlElement;
+ var _bodyElement;
+ var _targetElement; //the target element of this OverlayScrollbars object
+ var _hostElement; //the host element of this OverlayScrollbars object -> may be the same as targetElement
+ var _sizeAutoObserverElement; //observes size auto changes
+ var _sizeObserverElement; //observes size and padding changes
+ var _paddingElement; //manages the padding
+ var _viewportElement; //is the viewport of our scrollbar model
+ var _contentElement; //the element which holds the content
+ var _contentArrangeElement; //is needed for correct sizing of the content element (only if native scrollbars are overlays)
+ var _contentGlueElement; //has always the size of the content element
+ var _textareaCoverElement; //only applied if target is a textarea element. Used for correct size calculation and for prevention of uncontrolled scrolling
+ var _scrollbarCornerElement;
+ var _scrollbarHorizontalElement;
+ var _scrollbarHorizontalTrackElement;
+ var _scrollbarHorizontalHandleElement;
+ var _scrollbarVerticalElement;
+ var _scrollbarVerticalTrackElement;
+ var _scrollbarVerticalHandleElement;
+ var _windowElementNative;
+ var _documentElementNative;
+ var _targetElementNative;
+ var _hostElementNative;
+ var _sizeAutoObserverElementNative;
+ var _sizeObserverElementNative;
+ var _paddingElementNative;
+ var _viewportElementNative;
+ var _contentElementNative;
+
+ //Cache:
+ var _hostSizeCache;
+ var _contentScrollSizeCache;
+ var _arrangeContentSizeCache;
+ var _hasOverflowCache;
+ var _hideOverflowCache;
+ var _widthAutoCache;
+ var _heightAutoCache;
+ var _cssMaxValueCache;
+ var _cssBoxSizingCache;
+ var _cssPaddingCache;
+ var _cssBorderCache;
+ var _cssMarginCache;
+ var _cssDirectionCache;
+ var _cssDirectionDetectedCache;
+ var _paddingAbsoluteCache;
+ var _clipAlwaysCache;
+ var _contentGlueSizeCache;
+ var _overflowBehaviorCache;
+ var _overflowAmountCache;
+ var _ignoreOverlayScrollbarHidingCache;
+ var _autoUpdateCache;
+ var _sizeAutoCapableCache;
+ var _contentElementScrollSizeChangeDetectedCache;
+ var _hostElementSizeChangeDetectedCache;
+ var _scrollbarsVisibilityCache;
+ var _scrollbarsAutoHideCache;
+ var _scrollbarsClickScrollingCache;
+ var _scrollbarsDragScrollingCache;
+ var _resizeCache;
+ var _normalizeRTLCache;
+ var _classNameCache;
+ var _oldClassName;
+ var _textareaAutoWrappingCache;
+ var _textareaInfoCache;
+ var _textareaSizeCache;
+ var _textareaDynHeightCache;
+ var _textareaDynWidthCache;
+ var _bodyMinSizeCache;
+ var _displayIsHiddenCache;
+ var _updateAutoCache = {};
+
+ //MutationObserver:
+ var _mutationObserverHost;
+ var _mutationObserverContent;
+ var _mutationObserverHostCallback;
+ var _mutationObserverContentCallback;
+ var _mutationObserversConnected;
+ var _mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows'];
+ var _mutationObserverAttrsHost = [LEXICON.i, LEXICON.c, LEXICON.s, 'open'].concat(_viewportAttrsFromTarget);
+
+ //events:
+ var _destroyEvents = [];
+
+ //textarea:
+ var _textareaHasFocus;
+
+ //scrollbars:
+ var _scrollbarsAutoHideTimeoutId;
+ var _scrollbarsAutoHideMoveTimeoutId;
+ var _scrollbarsAutoHideDelay;
+ var _scrollbarsAutoHideNever;
+ var _scrollbarsAutoHideScroll;
+ var _scrollbarsAutoHideMove;
+ var _scrollbarsAutoHideLeave;
+ var _scrollbarsHandleHovered;
+ var _scrollbarsHandlesDefineScrollPos;
+
+ //resize
+ var _resizeNone;
+ var _resizeBoth;
+ var _resizeHorizontal;
+ var _resizeVertical;
+
+
+ //==== Event Listener ====//
+
+ /**
+ * Adds or removes a event listener from the given element.
+ * @param element The element to which the event listener shall be applied or removed.
+ * @param eventNames The name(s) of the events.
+ * @param listener The method which shall be called.
+ * @param remove True if the handler shall be removed, false or undefined if the handler shall be added.
+ */
+ function setupResponsiveEventListener(element, eventNames, listener, remove, passive) {
+ var collected = type(eventNames) == TYPES.a && type(listener) == TYPES.a;
+ var method = remove ? 'removeEventListener' : 'addEventListener';
+ var onOff = remove ? 'off' : 'on';
+ var events = collected ? false : eventNames.split(_strSpace)
+ var i = 0;
+
+ if (collected) {
+ for (; i < eventNames[LEXICON.l]; i++)
+ setupResponsiveEventListener(element, eventNames[i], listener[i], remove);
+ }
+ else {
+ for (; i < events[LEXICON.l]; i++) {
+ if (_supportPassiveEvents)
+ element[0][method](events[i], listener, { passive: passive || false });
+ else
+ element[onOff](events[i], listener);
+ }
+ }
+ }
+
+
+ function addDestroyEventListener(element, eventNames, listener, passive) {
+ setupResponsiveEventListener(element, eventNames, listener, false, passive);
+ _destroyEvents.push(COMPATIBILITY.bind(setupResponsiveEventListener, 0, element, eventNames, listener, true, passive));
+ }
+
+ //==== Resize Observer ====//
+
+ /**
+ * Adds or removes a resize observer from the given element.
+ * @param targetElement The element to which the resize observer shall be added or removed.
+ * @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change or false / undefined if the resizeObserver shall be removed.
+ */
+ function setupResizeObserver(targetElement, onElementResizedCallback) {
+ if (targetElement) {
+ var resizeObserver = COMPATIBILITY.rO();
+ var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart';
+ var strChildNodes = 'childNodes';
+ var constScroll = 3333333;
+ var callback = function () {
+ targetElement[_strScrollTop](constScroll)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll : constScroll);
+ onElementResizedCallback();
+ };
+ //add resize observer:
+ if (onElementResizedCallback) {
+ if (_supportResizeObserver) {
+ var element = targetElement.addClass('observed').append(generateDiv(_classNameResizeObserverElement)).contents()[0];
+ var observer = element[_strResizeObserverProperty] = new resizeObserver(callback);
+ observer.observe(element);
+ }
+ else {
+ if (_msieVersion > 9 || !_autoUpdateRecommended) {
+ targetElement.prepend(
+ generateDiv(_classNameResizeObserverElement,
+ generateDiv({ c: _classNameResizeObserverItemElement, dir: 'ltr' },
+ generateDiv(_classNameResizeObserverItemElement,
+ generateDiv(_classNameResizeObserverItemFinalElement)
+ ) +
+ generateDiv(_classNameResizeObserverItemElement,
+ generateDiv({ c: _classNameResizeObserverItemFinalElement, style: 'width: 200%; height: 200%' })
+ )
+ )
+ )
+ );
+
+ var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0];
+ var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]);
+ var expandElement = FRAMEWORK(observerElement[strChildNodes][0]);
+ var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]);
+ var widthCache = observerElement[LEXICON.oW];
+ var heightCache = observerElement[LEXICON.oH];
+ var isDirty;
+ var rAFId;
+ var currWidth;
+ var currHeight;
+ var factor = 2;
+ var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!!
+ var reset = function () {
+ /*
+ var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
+ var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
+ var expandChildCSS = {};
+ expandChildCSS[_strWidth] = sizeResetWidth;
+ expandChildCSS[_strHeight] = sizeResetHeight;
+ expandElementChild.css(expandChildCSS);
+
+
+ expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
+ shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
+ */
+ expandElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);
+ shrinkElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);
+ };
+ var onResized = function () {
+ rAFId = 0;
+ if (!isDirty)
+ return;
+
+ widthCache = currWidth;
+ heightCache = currHeight;
+ callback();
+ };
+ var onScroll = function (event) {
+ currWidth = observerElement[LEXICON.oW];
+ currHeight = observerElement[LEXICON.oH];
+ isDirty = currWidth != widthCache || currHeight != heightCache;
+
+ if (event && isDirty && !rAFId) {
+ COMPATIBILITY.cAF()(rAFId);
+ rAFId = COMPATIBILITY.rAF()(onResized);
+ }
+ else if (!event)
+ onResized();
+
+ reset();
+ if (event) {
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ }
+ return false;
+ };
+ var expandChildCSS = {};
+ var observerElementCSS = {};
+
+ setTopRightBottomLeft(observerElementCSS, _strEmpty, [
+ -((nativeScrollbarSize.y + 1) * factor),
+ nativeScrollbarSize.x * -factor,
+ nativeScrollbarSize.y * -factor,
+ -((nativeScrollbarSize.x + 1) * factor)
+ ]);
+
+ FRAMEWORK(observerElement).css(observerElementCSS);
+ expandElement.on(_strScroll, onScroll);
+ shrinkElement.on(_strScroll, onScroll);
+ targetElement.on(strAnimationStartEvent, function () {
+ onScroll(false);
+ });
+ //lets assume that the divs will never be that large and a constant value is enough
+ expandChildCSS[_strWidth] = constScroll;
+ expandChildCSS[_strHeight] = constScroll;
+ expandElementChild.css(expandChildCSS);
+
+ reset();
+ }
+ else {
+ var attachEvent = _documentElementNative.attachEvent;
+ var isIE = _msieVersion !== undefined;
+ if (attachEvent) {
+ targetElement.prepend(generateDiv(_classNameResizeObserverElement));
+ findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback);
+ }
+ else {
+ var obj = _documentElementNative.createElement(TYPES.o);
+ obj.setAttribute(LEXICON.ti, '-1');
+ obj.setAttribute(LEXICON.c, _classNameResizeObserverElement);
+ obj.onload = function () {
+ var wnd = this.contentDocument.defaultView;
+ wnd.addEventListener('resize', callback);
+ wnd.document.documentElement.style.display = 'none';
+ };
+ obj.type = 'text/html';
+ if (isIE)
+ targetElement.prepend(obj);
+ obj.data = 'about:blank';
+ if (!isIE)
+ targetElement.prepend(obj);
+ targetElement.on(strAnimationStartEvent, callback);
+ }
+ }
+ }
+
+ if (targetElement[0] === _sizeObserverElementNative) {
+ var directionChanged = function () {
+ var dir = _hostElement.css('direction');
+ var css = {};
+ var scrollLeftValue = 0;
+ var result = false;
+ if (dir !== _cssDirectionDetectedCache) {
+ if (dir === 'ltr') {
+ css[_strLeft] = 0;
+ css[_strRight] = _strAuto;
+ scrollLeftValue = constScroll;
+ }
+ else {
+ css[_strLeft] = _strAuto;
+ css[_strRight] = 0;
+ scrollLeftValue = _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll;
+ }
+ //execution order is important for IE!!!
+ _sizeObserverElement.children().eq(0).css(css);
+ _sizeObserverElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constScroll);
+ _cssDirectionDetectedCache = dir;
+ result = true;
+ }
+ return result;
+ };
+ directionChanged();
+ addDestroyEventListener(targetElement, _strScroll, function (event) {
+ if (directionChanged())
+ update();
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ return false;
+ });
+ }
+ }
+ //remove resize observer:
+ else {
+ if (_supportResizeObserver) {
+ var element = targetElement.contents()[0];
+ var resizeObserverObj = element[_strResizeObserverProperty];
+ if (resizeObserverObj) {
+ resizeObserverObj.disconnect();
+ delete element[_strResizeObserverProperty];
+ }
+ }
+ else {
+ remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0));
+ }
+ }
+ }
+ }
+
+ /**
+ * Freezes or unfreezes the given resize observer.
+ * @param targetElement The element to which the target resize observer is applied.
+ * @param freeze True if the resize observer shall be frozen, false otherwise.
+
+ function freezeResizeObserver(targetElement, freeze) {
+ if (targetElement !== undefined) {
+ if(freeze) {
+ if (_supportResizeObserver) {
+ var element = targetElement.contents()[0];
+ element[_strResizeObserverProperty].unobserve(element);
+ }
+ else {
+ targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0);
+ var w = targetElement.css(_strWidth);
+ var h = targetElement.css(_strHeight);
+ var css = {};
+ css[_strWidth] = w;
+ css[_strHeight] = h;
+ targetElement.css(css);
+ }
+ }
+ else {
+ if (_supportResizeObserver) {
+ var element = targetElement.contents()[0];
+ element[_strResizeObserverProperty].observe(element);
+ }
+ else {
+ var css = { };
+ css[_strHeight] = _strEmpty;
+ css[_strWidth] = _strEmpty;
+ targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css);
+ }
+ }
+ }
+ }
+ */
+
+
+ //==== Mutation Observers ====//
+
+ /**
+ * Creates MutationObservers for the host and content Element if they are supported.
+ */
+ function createMutationObservers() {
+ if (_supportMutationObserver) {
+ var mutationObserverContentLag = 11;
+ var mutationObserver = COMPATIBILITY.mO();
+ var contentLastUpdate = COMPATIBILITY.now();
+ var mutationTarget;
+ var mutationAttrName;
+ var contentTimeout;
+ var now;
+ var sizeAuto;
+ var action;
+
+ _mutationObserverHostCallback = function (mutations) {
+ var doUpdate = false;
+ var mutation;
+ var mutatedAttrs = [];
+
+ if (_initialized && !_sleeping) {
+ each(mutations, function () {
+ mutation = this;
+ mutationTarget = mutation.target;
+ mutationAttrName = mutation.attributeName;
+
+ if(!doUpdate) {
+ if (mutationAttrName === LEXICON.c)
+ doUpdate = hostClassNamesChanged(mutation.oldValue, mutationTarget.className);
+ else if (mutationAttrName === LEXICON.s)
+ doUpdate = mutation.oldValue !== mutationTarget[LEXICON.s].cssText;
+ else
+ doUpdate = true;
+ }
+
+ mutatedAttrs.push(mutationAttrName);
+ });
+
+ updateViewportAttrsFromTarget(mutatedAttrs);
+
+ if (doUpdate)
+ _base.update(_strAuto);
+ }
+ return doUpdate;
+ };
+ _mutationObserverContentCallback = function (mutations) {
+ var doUpdate = false;
+ var mutation;
+
+ if (_initialized && !_sleeping) {
+ each(mutations, function () {
+ mutation = this;
+ doUpdate = isUnknownMutation(mutation);
+ return !doUpdate;
+ });
+
+ if (doUpdate) {
+ now = COMPATIBILITY.now();
+ sizeAuto = (_heightAutoCache || _widthAutoCache);
+ action = function () {
+ if (!_destroyed) {
+ contentLastUpdate = now;
+
+ //if cols, rows or wrap attr was changed
+ if (_isTextarea)
+ textareaUpdate();
+
+ if (sizeAuto)
+ update();
+ else
+ _base.update(_strAuto);
+ }
+ };
+ clearTimeout(contentTimeout);
+ if (mutationObserverContentLag <= 0 || now - contentLastUpdate > mutationObserverContentLag || !sizeAuto)
+ action();
+ else
+ contentTimeout = setTimeout(action, mutationObserverContentLag);
+ }
+ }
+ return doUpdate;
+ }
+
+ _mutationObserverHost = new mutationObserver(_mutationObserverHostCallback);
+ _mutationObserverContent = new mutationObserver(_mutationObserverContentCallback);
+ }
+ }
+
+ /**
+ * Connects the MutationObservers if they are supported.
+ */
+ function connectMutationObservers() {
+ if (_supportMutationObserver && !_mutationObserversConnected) {
+ _mutationObserverHost.observe(_hostElementNative, {
+ attributes: true,
+ attributeOldValue: true,
+ attributeFilter: _mutationObserverAttrsHost
+ });
+
+ _mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, {
+ attributes: true,
+ attributeOldValue: true,
+ subtree: !_isTextarea,
+ childList: !_isTextarea,
+ characterData: !_isTextarea,
+ attributeFilter: _isTextarea ? _mutationObserverAttrsTextarea : _mutationObserverAttrsHost
+ });
+
+ _mutationObserversConnected = true;
+ }
+ }
+
+ /**
+ * Disconnects the MutationObservers if they are supported.
+ */
+ function disconnectMutationObservers() {
+ if (_supportMutationObserver && _mutationObserversConnected) {
+ _mutationObserverHost.disconnect();
+ _mutationObserverContent.disconnect();
+
+ _mutationObserversConnected = false;
+ }
+ }
+
+
+ //==== Events of elements ====//
+
+ /**
+ * This method gets called every time the host element gets resized. IMPORTANT: Padding changes are detected too!!
+ * It refreshes the hostResizedEventArgs and the hostSizeResizeCache.
+ * If there are any size changes, the update method gets called.
+ */
+ function hostOnResized() {
+ if (!_sleeping) {
+ var changed;
+ var hostSize = {
+ w: _sizeObserverElementNative[LEXICON.sW],
+ h: _sizeObserverElementNative[LEXICON.sH]
+ };
+
+ changed = checkCache(hostSize, _hostElementSizeChangeDetectedCache);
+ _hostElementSizeChangeDetectedCache = hostSize;
+ if (changed)
+ update({ _hostSizeChanged: true });
+ }
+ }
+
+ /**
+ * The mouse enter event of the host element. This event is only needed for the autoHide feature.
+ */
+ function hostOnMouseEnter() {
+ if (_scrollbarsAutoHideLeave)
+ refreshScrollbarsAutoHide(true);
+ }
+
+ /**
+ * The mouse leave event of the host element. This event is only needed for the autoHide feature.
+ */
+ function hostOnMouseLeave() {
+ if (_scrollbarsAutoHideLeave && !_bodyElement.hasClass(_classNameDragging))
+ refreshScrollbarsAutoHide(false);
+ }
+
+ /**
+ * The mouse move event of the host element. This event is only needed for the autoHide "move" feature.
+ */
+ function hostOnMouseMove() {
+ if (_scrollbarsAutoHideMove) {
+ refreshScrollbarsAutoHide(true);
+ clearTimeout(_scrollbarsAutoHideMoveTimeoutId);
+ _scrollbarsAutoHideMoveTimeoutId = setTimeout(function () {
+ if (_scrollbarsAutoHideMove && !_destroyed)
+ refreshScrollbarsAutoHide(false);
+ }, 100);
+ }
+ }
+
+ /**
+ * Prevents text from deselection if attached to the document element on the mousedown event of a DOM element.
+ * @param event The select start event.
+ */
+ function documentOnSelectStart(event) {
+ COMPATIBILITY.prvD(event);
+ return false;
+ }
+
+ /**
+ * A callback which will be called after a img element has downloaded its src asynchronous.
+ */
+ function imgOnLoad() {
+ update({ _contentSizeChanged: true });
+ }
+
+ /**
+ * Adds or removes mouse & touch events of the host element. (for handling auto-hiding of the scrollbars)
+ * @param destroy Indicates whether the events shall be added or removed.
+ */
+ function setupHostMouseTouchEvents(destroy) {
+ setupResponsiveEventListener(_hostElement,
+ _strMouseTouchMoveEvent,
+ hostOnMouseMove,
+ (_scrollbarsAutoHideMove ? destroy : true), true);
+ setupResponsiveEventListener(_hostElement,
+ [_strMouseTouchEnter, _strMouseTouchLeave],
+ [hostOnMouseEnter, hostOnMouseLeave],
+ (_scrollbarsAutoHideMove ? true : destroy), true);
+
+ //if the plugin is initialized and the mouse is over the host element, make the scrollbars visible
+ if (!_initialized && !destroy)
+ _hostElement.one('mouseover', hostOnMouseEnter);
+ }
+
+
+ //==== Update Detection ====//
+
+ /**
+ * Measures the min width and min height of the body element and refreshes the related cache.
+ * @returns {boolean} True if the min width or min height has changed, false otherwise.
+ */
+ function bodyMinSizeChanged() {
+ var bodyMinSize = {};
+ if (_isBody && _contentArrangeElement) {
+ bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth));
+ bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight));
+ bodyMinSize.c = checkCache(bodyMinSize, _bodyMinSizeCache);
+ bodyMinSize.f = true; //flag for "measured at least once"
+ }
+ _bodyMinSizeCache = bodyMinSize;
+ return !!bodyMinSize.c;
+ }
+
+ /**
+ * Returns true if the class names really changed (new class without plugin host prefix)
+ * @param oldCassNames The old ClassName string.
+ * @param newClassNames The new ClassName string.
+ * @returns {boolean} True if the class names has really changed, false otherwise.
+ */
+ function hostClassNamesChanged(oldCassNames, newClassNames) {
+ var currClasses = (newClassNames !== undefined && newClassNames !== null) ? newClassNames.split(_strSpace) : _strEmpty;
+ var oldClasses = (oldCassNames !== undefined && oldCassNames !== null) ? oldCassNames.split(_strSpace) : _strEmpty;
+ if (currClasses === _strEmpty && oldClasses === _strEmpty)
+ return false;
+ var diff = getArrayDifferences(oldClasses, currClasses);
+ var changed = false;
+ var oldClassNames = _oldClassName !== undefined && _oldClassName !== null ? _oldClassName.split(_strSpace) : [_strEmpty];
+ var currClassNames = _classNameCache !== undefined && _classNameCache !== null ? _classNameCache.split(_strSpace) : [_strEmpty];
+
+ //remove none theme from diff list to prevent update
+ var idx = inArray(_classNameThemeNone, diff);
+ var curr;
+ var i;
+ var v;
+ var o;
+ var c;
+
+ if (idx > -1)
+ diff.splice(idx, 1);
+
+ for (i = 0; i < diff.length; i++) {
+ curr = diff[i];
+ if (curr.indexOf(_classNameHostElement) !== 0) {
+ o = true;
+ c = true;
+ for (v = 0; v < oldClassNames.length; v++) {
+ if (curr === oldClassNames[v]) {
+ o = false;
+ break;
+ }
+ }
+ for (v = 0; v < currClassNames.length; v++) {
+ if (curr === currClassNames[v]) {
+ c = false;
+ break;
+ }
+ }
+ if (o && c) {
+ changed = true;
+ break;
+ }
+ }
+
+ }
+ return changed;
+ }
+
+ /**
+ * Returns true if the given mutation is not from a from the plugin generated element. If the target element is a textarea the mutation is always unknown.
+ * @param mutation The mutation which shall be checked.
+ * @returns {boolean} True if the mutation is from a unknown element, false otherwise.
+ */
+ function isUnknownMutation(mutation) {
+ var attributeName = mutation.attributeName;
+ var mutationTarget = mutation.target;
+ var mutationType = mutation.type;
+ var strClosest = 'closest';
+
+ if (mutationTarget === _contentElementNative)
+ return attributeName === null;
+ if (mutationType === 'attributes' && (attributeName === LEXICON.c || attributeName === LEXICON.s) && !_isTextarea) {
+ //ignore className changes by the plugin
+ if (attributeName === LEXICON.c && FRAMEWORK(mutationTarget).hasClass(_classNameHostElement))
+ return hostClassNamesChanged(mutation.oldValue, mutationTarget.getAttribute(LEXICON.c));
+
+ //only do it of browser support it natively
+ if (typeof mutationTarget[strClosest] != TYPES.f)
+ return true;
+ if (mutationTarget[strClosest](_strDot + _classNameResizeObserverElement) !== null ||
+ mutationTarget[strClosest](_strDot + _classNameScrollbar) !== null ||
+ mutationTarget[strClosest](_strDot + _classNameScrollbarCorner) !== null)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if the content size was changed since the last time this method was called.
+ * @returns {boolean} True if the content size was changed, false otherwise.
+ */
+ function updateAutoContentSizeChanged() {
+ if (_sleeping)
+ return false;
+
+ var contentMeasureElement = getContentMeasureElement();
+ var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0;
+ var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea;
+ var css = {};
+ var float;
+ var bodyMinSizeC;
+ var changed;
+ var contentElementScrollSize;
+
+ if (setCSS) {
+ float = _contentElement.css(_strFloat);
+ css[_strFloat] = _isRTL ? _strRight : _strLeft;
+ css[_strWidth] = _strAuto;
+ _contentElement.css(css);
+ }
+ contentElementScrollSize = {
+ w: contentMeasureElement[LEXICON.sW] + textareaValueLength,
+ h: contentMeasureElement[LEXICON.sH] + textareaValueLength
+ };
+ if (setCSS) {
+ css[_strFloat] = float;
+ css[_strWidth] = _strHundredPercent;
+ _contentElement.css(css);
+ }
+
+ bodyMinSizeC = bodyMinSizeChanged();
+ changed = checkCache(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache);
+
+ _contentElementScrollSizeChangeDetectedCache = contentElementScrollSize;
+
+ return changed || bodyMinSizeC;
+ }
+
+ /**
+ * Returns true when a attribute which the MutationObserver would observe has changed.
+ * @returns {boolean} True if one of the attributes which a MutationObserver would observe has changed, false or undefined otherwise.
+ */
+ function meaningfulAttrsChanged() {
+ if (_sleeping || _mutationObserversConnected)
+ return;
+
+ var elem;
+ var curr;
+ var cache;
+ var changedAttrs = [];
+ var checks = [
+ {
+ _elem: _hostElement,
+ _attrs: _mutationObserverAttrsHost.concat(':visible')
+ },
+ {
+ _elem: _isTextarea ? _targetElement : undefined,
+ _attrs: _mutationObserverAttrsTextarea
+ }
+ ];
+
+ each(checks, function (index, check) {
+ elem = check._elem;
+ if (elem) {
+ each(check._attrs, function (index, attr) {
+ curr = attr.charAt(0) === ':' ? elem.is(attr) : elem.attr(attr);
+ cache = _updateAutoCache[attr];
+
+ if(checkCache(curr, cache)) {
+ changedAttrs.push(attr);
+ }
+
+ _updateAutoCache[attr] = curr;
+ });
+ }
+ });
+
+ updateViewportAttrsFromTarget(changedAttrs);
+
+ return changedAttrs[LEXICON.l] > 0;
+ }
+
+ /**
+ * Checks is a CSS Property of a child element is affecting the scroll size of the content.
+ * @param propertyName The CSS property name.
+ * @returns {boolean} True if the property is affecting the content scroll size, false otherwise.
+ */
+ function isSizeAffectingCSSProperty(propertyName) {
+ if (!_initialized)
+ return true;
+ var flexGrow = 'flex-grow';
+ var flexShrink = 'flex-shrink';
+ var flexBasis = 'flex-basis';
+ var affectingPropsX = [
+ _strWidth,
+ _strMinMinus + _strWidth,
+ _strMaxMinus + _strWidth,
+ _strMarginMinus + _strLeft,
+ _strMarginMinus + _strRight,
+ _strLeft,
+ _strRight,
+ 'font-weight',
+ 'word-spacing',
+ flexGrow,
+ flexShrink,
+ flexBasis
+ ];
+ var affectingPropsXContentBox = [
+ _strPaddingMinus + _strLeft,
+ _strPaddingMinus + _strRight,
+ _strBorderMinus + _strLeft + _strWidth,
+ _strBorderMinus + _strRight + _strWidth
+ ];
+ var affectingPropsY = [
+ _strHeight,
+ _strMinMinus + _strHeight,
+ _strMaxMinus + _strHeight,
+ _strMarginMinus + _strTop,
+ _strMarginMinus + _strBottom,
+ _strTop,
+ _strBottom,
+ 'line-height',
+ flexGrow,
+ flexShrink,
+ flexBasis
+ ];
+ var affectingPropsYContentBox = [
+ _strPaddingMinus + _strTop,
+ _strPaddingMinus + _strBottom,
+ _strBorderMinus + _strTop + _strWidth,
+ _strBorderMinus + _strBottom + _strWidth
+ ];
+ var _strS = 's';
+ var _strVS = 'v-s';
+ var checkX = _overflowBehaviorCache.x === _strS || _overflowBehaviorCache.x === _strVS;
+ var checkY = _overflowBehaviorCache.y === _strS || _overflowBehaviorCache.y === _strVS;
+ var sizeIsAffected = false;
+ var checkPropertyName = function (arr, name) {
+ for (var i = 0; i < arr[LEXICON.l]; i++) {
+ if (arr[i] === name)
+ return true;
+ }
+ return false;
+ };
+
+ if (checkY) {
+ sizeIsAffected = checkPropertyName(affectingPropsY, propertyName);
+ if (!sizeIsAffected && !_isBorderBox)
+ sizeIsAffected = checkPropertyName(affectingPropsYContentBox, propertyName);
+ }
+ if (checkX && !sizeIsAffected) {
+ sizeIsAffected = checkPropertyName(affectingPropsX, propertyName);
+ if (!sizeIsAffected && !_isBorderBox)
+ sizeIsAffected = checkPropertyName(affectingPropsXContentBox, propertyName);
+ }
+ return sizeIsAffected;
+ }
+
+
+ //==== Update ====//
+
+ /**
+ * Sets the attribute values of the viewport element to the values from the target element.
+ * The value of a attribute is only set if the attribute is whitelisted.
+ * @attrs attrs The array of attributes which shall be set or undefined if all whitelisted shall be set.
+ */
+ function updateViewportAttrsFromTarget(attrs) {
+ attrs = attrs || _viewportAttrsFromTarget;
+ each(attrs, function (index, attr) {
+ if (COMPATIBILITY.inA(attr, _viewportAttrsFromTarget) > -1) {
+ var targetAttr = _targetElement.attr(attr);
+ if(type(targetAttr) == TYPES.s) {
+ _viewportElement.attr(attr, targetAttr);
+ }
+ else {
+ _viewportElement.removeAttr(attr);
+ }
+ }
+ });
+ }
+
+ /**
+ * Updates the variables and size of the textarea element, and manages the scroll on new line or new character.
+ */
+ function textareaUpdate() {
+ if (!_sleeping) {
+ var wrapAttrOff = !_textareaAutoWrappingCache;
+ var minWidth = _viewportSize.w;
+ var minHeight = _viewportSize.h;
+ var css = {};
+ var doMeasure = _widthAutoCache || wrapAttrOff;
+ var origWidth;
+ var width;
+ var origHeight;
+ var height;
+
+ //reset min size
+ css[_strMinMinus + _strWidth] = _strEmpty;
+ css[_strMinMinus + _strHeight] = _strEmpty;
+
+ //set width auto
+ css[_strWidth] = _strAuto;
+ _targetElement.css(css);
+
+ //measure width
+ origWidth = _targetElementNative[LEXICON.oW];
+ width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1;
+ /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/
+
+ //set measured width
+ css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent;
+ css[_strMinMinus + _strWidth] = _strHundredPercent;
+
+ //set height auto
+ css[_strHeight] = _strAuto;
+ _targetElement.css(css);
+
+ //measure height
+ origHeight = _targetElementNative[LEXICON.oH];
+ height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1);
+
+ //append correct size values
+ css[_strWidth] = width;
+ css[_strHeight] = height;
+ _textareaCoverElement.css(css);
+
+ //apply min width / min height to prevent textarea collapsing
+ css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/;
+ css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/;
+ _targetElement.css(css);
+
+ return {
+ _originalWidth: origWidth,
+ _originalHeight: origHeight,
+ _dynamicWidth: width,
+ _dynamicHeight: height
+ };
+ }
+ }
+
+ /**
+ * Updates the plugin and DOM to the current options.
+ * This method should only be called if a update is 100% required.
+ * @param updateHints A objects which contains hints for this update:
+ * {
+ * _hostSizeChanged : boolean,
+ * _contentSizeChanged : boolean,
+ * _force : boolean, == preventSwallowing
+ * _changedOptions : { }, == preventSwallowing && preventSleep
+ * }
+ */
+ function update(updateHints) {
+ clearTimeout(_swallowedUpdateTimeout);
+ updateHints = updateHints || {};
+ _swallowedUpdateHints._hostSizeChanged |= updateHints._hostSizeChanged;
+ _swallowedUpdateHints._contentSizeChanged |= updateHints._contentSizeChanged;
+ _swallowedUpdateHints._force |= updateHints._force;
+
+ var now = COMPATIBILITY.now();
+ var hostSizeChanged = !!_swallowedUpdateHints._hostSizeChanged;
+ var contentSizeChanged = !!_swallowedUpdateHints._contentSizeChanged;
+ var force = !!_swallowedUpdateHints._force;
+ var changedOptions = updateHints._changedOptions;
+ var swallow = _swallowUpdateLag > 0 && _initialized && !_destroyed && !force && !changedOptions && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache);
+ var displayIsHidden;
+
+ if (swallow)
+ _swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag);
+
+ //abort update due to:
+ //destroyed
+ //swallowing
+ //sleeping
+ //host is hidden or has false display
+ if (_destroyed || swallow || (_sleeping && !changedOptions) || (_initialized && !force && (displayIsHidden = _hostElement.is(':hidden'))) || _hostElement.css('display') === 'inline')
+ return;
+
+ _lastUpdateTime = now;
+ _swallowedUpdateHints = {};
+
+ //if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely.
+ if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
+ //native scrollbars are hidden, so change the values to zero
+ _nativeScrollbarSize.x = 0;
+ _nativeScrollbarSize.y = 0;
+ }
+ else {
+ //refresh native scrollbar size (in case of zoom)
+ _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
+ }
+
+ // Scrollbar padding is needed for firefox, because firefox hides scrollbar automatically if the size of the div is too small.
+ // The calculation: [scrollbar size +3 *3]
+ // (+3 because of possible decoration e.g. borders, margins etc., but only if native scrollbar is NOT a overlaid scrollbar)
+ // (*3 because (1)increase / (2)decrease -button and (3)resize handle)
+ _nativeScrollbarMinSize = {
+ x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3,
+ y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 3
+ };
+
+ //changedOptions = changedOptions || { };
+ //freezeResizeObserver(_sizeObserverElement, true);
+ //freezeResizeObserver(_sizeAutoObserverElement, true);
+
+ var checkCacheAutoForce = function () {
+ return checkCache.apply(this, [].slice.call(arguments).concat([force]));
+ };
+
+ //save current scroll offset
+ var currScroll = {
+ x: _viewportElement[_strScrollLeft](),
+ y: _viewportElement[_strScrollTop]()
+ };
+
+ var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars;
+ var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea;
+
+ //scrollbars visibility:
+ var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility;
+ var scrollbarsVisibilityChanged = checkCacheAutoForce(scrollbarsVisibility, _scrollbarsVisibilityCache);
+
+ //scrollbars autoHide:
+ var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide;
+ var scrollbarsAutoHideChanged = checkCacheAutoForce(scrollbarsAutoHide, _scrollbarsAutoHideCache);
+
+ //scrollbars click scrolling
+ var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling;
+ var scrollbarsClickScrollingChanged = checkCacheAutoForce(scrollbarsClickScrolling, _scrollbarsClickScrollingCache);
+
+ //scrollbars drag scrolling
+ var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling;
+ var scrollbarsDragScrollingChanged = checkCacheAutoForce(scrollbarsDragScrolling, _scrollbarsDragScrollingCache);
+
+ //className
+ var className = _currentPreparedOptions.className;
+ var classNameChanged = checkCacheAutoForce(className, _classNameCache);
+
+ //resize
+ var resize = _currentPreparedOptions.resize;
+ var resizeChanged = checkCacheAutoForce(resize, _resizeCache) && !_isBody; //body can't be resized since the window itself acts as resize possibility.
+
+ //paddingAbsolute
+ var paddingAbsolute = _currentPreparedOptions.paddingAbsolute;
+ var paddingAbsoluteChanged = checkCacheAutoForce(paddingAbsolute, _paddingAbsoluteCache);
+
+ //clipAlways
+ var clipAlways = _currentPreparedOptions.clipAlways;
+ var clipAlwaysChanged = checkCacheAutoForce(clipAlways, _clipAlwaysCache);
+
+ //sizeAutoCapable
+ var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport.
+ var sizeAutoCapableChanged = checkCacheAutoForce(sizeAutoCapable, _sizeAutoCapableCache);
+
+ //showNativeScrollbars
+ var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars;
+ var ignoreOverlayScrollbarHidingChanged = checkCacheAutoForce(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache);
+
+ //autoUpdate
+ var autoUpdate = _currentPreparedOptions.autoUpdate;
+ var autoUpdateChanged = checkCacheAutoForce(autoUpdate, _autoUpdateCache);
+
+ //overflowBehavior
+ var overflowBehavior = _currentPreparedOptions.overflowBehavior;
+ var overflowBehaviorChanged = checkCacheAutoForce(overflowBehavior, _overflowBehaviorCache, force);
+
+ //dynWidth:
+ var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth;
+ var textareaDynWidthChanged = checkCacheAutoForce(_textareaDynWidthCache, textareaDynWidth);
+
+ //dynHeight:
+ var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight;
+ var textareaDynHeightChanged = checkCacheAutoForce(_textareaDynHeightCache, textareaDynHeight);
+
+ //scrollbars visibility
+ _scrollbarsAutoHideNever = scrollbarsAutoHide === 'n';
+ _scrollbarsAutoHideScroll = scrollbarsAutoHide === 's';
+ _scrollbarsAutoHideMove = scrollbarsAutoHide === 'm';
+ _scrollbarsAutoHideLeave = scrollbarsAutoHide === 'l';
+
+ //scrollbars autoHideDelay
+ _scrollbarsAutoHideDelay = currentPreparedOptionsScrollbars.autoHideDelay;
+
+ //old className
+ _oldClassName = _classNameCache;
+
+ //resize
+ _resizeNone = resize === 'n';
+ _resizeBoth = resize === 'b';
+ _resizeHorizontal = resize === 'h';
+ _resizeVertical = resize === 'v';
+
+ //normalizeRTL
+ _normalizeRTLCache = _currentPreparedOptions.normalizeRTL;
+
+ //ignore overlay scrollbar hiding
+ ignoreOverlayScrollbarHiding = ignoreOverlayScrollbarHiding && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y);
+
+ //refresh options cache
+ _scrollbarsVisibilityCache = scrollbarsVisibility;
+ _scrollbarsAutoHideCache = scrollbarsAutoHide;
+ _scrollbarsClickScrollingCache = scrollbarsClickScrolling;
+ _scrollbarsDragScrollingCache = scrollbarsDragScrolling;
+ _classNameCache = className;
+ _resizeCache = resize;
+ _paddingAbsoluteCache = paddingAbsolute;
+ _clipAlwaysCache = clipAlways;
+ _sizeAutoCapableCache = sizeAutoCapable;
+ _ignoreOverlayScrollbarHidingCache = ignoreOverlayScrollbarHiding;
+ _autoUpdateCache = autoUpdate;
+ _overflowBehaviorCache = extendDeep({}, overflowBehavior);
+ _textareaDynWidthCache = textareaDynWidth;
+ _textareaDynHeightCache = textareaDynHeight;
+ _hasOverflowCache = _hasOverflowCache || { x: false, y: false };
+
+ //set correct class name to the host element
+ if (classNameChanged) {
+ removeClass(_hostElement, _oldClassName + _strSpace + _classNameThemeNone);
+ addClass(_hostElement, className !== undefined && className !== null && className.length > 0 ? className : _classNameThemeNone);
+ }
+
+ //set correct auto Update
+ if (autoUpdateChanged) {
+ if (autoUpdate === true) {
+ disconnectMutationObservers();
+ autoUpdateLoop.add(_base);
+ }
+ else if (autoUpdate === null) {
+ if (_autoUpdateRecommended) {
+ disconnectMutationObservers();
+ autoUpdateLoop.add(_base);
+ }
+ else {
+ autoUpdateLoop.remove(_base);
+ connectMutationObservers();
+ }
+ }
+ else {
+ autoUpdateLoop.remove(_base);
+ connectMutationObservers();
+ }
+ }
+
+ //activate or deactivate size auto capability
+ if (sizeAutoCapableChanged) {
+ if (sizeAutoCapable) {
+ if (!_contentGlueElement) {
+ _contentGlueElement = FRAMEWORK(generateDiv(_classNameContentGlueElement));
+ _paddingElement.before(_contentGlueElement);
+ }
+ else {
+ _contentGlueElement.show();
+ }
+ if (_sizeAutoObserverAdded) {
+ _sizeAutoObserverElement.show();
+ }
+ else {
+ _sizeAutoObserverElement = FRAMEWORK(generateDiv(_classNameSizeAutoObserverElement));
+ _sizeAutoObserverElementNative = _sizeAutoObserverElement[0];
+
+ _contentGlueElement.before(_sizeAutoObserverElement);
+ var oldSize = { w: -1, h: -1 };
+ setupResizeObserver(_sizeAutoObserverElement, function () {
+ var newSize = {
+ w: _sizeAutoObserverElementNative[LEXICON.oW],
+ h: _sizeAutoObserverElementNative[LEXICON.oH]
+ };
+ if (checkCache(newSize, oldSize)) {
+ if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) {
+ update();
+ }
+ else if (_initialized && (!_heightAutoCache && newSize.h === 0) || (!_widthAutoCache && newSize.w === 0)) {
+ update();
+ }
+ }
+ oldSize = newSize;
+ });
+ _sizeAutoObserverAdded = true;
+ //fix heightAuto detector bug if height is fixed but contentHeight is 0.
+ //the probability this bug will ever happen is very very low, thats why its ok if we use calc which isn't supported in IE8.
+ if (_cssCalc !== null)
+ _sizeAutoObserverElement.css(_strHeight, _cssCalc + '(100% + 1px)');
+ }
+ }
+ else {
+ if (_sizeAutoObserverAdded)
+ _sizeAutoObserverElement.hide();
+ if (_contentGlueElement)
+ _contentGlueElement.hide();
+ }
+ }
+
+ //if force, update all resizeObservers too
+ if (force) {
+ _sizeObserverElement.find('*').trigger(_strScroll);
+ if (_sizeAutoObserverAdded)
+ _sizeAutoObserverElement.find('*').trigger(_strScroll);
+ }
+
+ //display hidden:
+ displayIsHidden = displayIsHidden === undefined ? _hostElement.is(':hidden') : displayIsHidden;
+ var displayIsHiddenChanged = checkCacheAutoForce(displayIsHidden, _displayIsHiddenCache);
+
+ //textarea AutoWrapping:
+ var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false;
+ var textareaAutoWrappingChanged = checkCacheAutoForce(textareaAutoWrapping, _textareaAutoWrappingCache);
+
+ //detect direction:
+ var cssDirection = _hostElement.css('direction');
+ var cssDirectionChanged = checkCacheAutoForce(cssDirection, _cssDirectionCache);
+
+ //detect box-sizing:
+ var boxSizing = _hostElement.css('box-sizing');
+ var boxSizingChanged = checkCacheAutoForce(boxSizing, _cssBoxSizingCache);
+
+ //detect padding:
+ var padding = {
+ c: force,
+ t: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strTop)),
+ r: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strRight)),
+ b: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strBottom)),
+ l: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strLeft))
+ };
+
+ //width + height auto detecting var:
+ var sizeAutoObserverElementBCRect;
+ //exception occurs in IE8 sometimes (unknown exception)
+ try {
+ sizeAutoObserverElementBCRect = _sizeAutoObserverAdded ? _sizeAutoObserverElementNative[LEXICON.bCR]() : null;
+ } catch (ex) {
+ return;
+ }
+
+ _isRTL = cssDirection === 'rtl';
+ _isBorderBox = (boxSizing === 'border-box');
+ var isRTLLeft = _isRTL ? _strLeft : _strRight;
+ var isRTLRight = _isRTL ? _strRight : _strLeft;
+
+ //detect width auto:
+ var widthAutoResizeDetection = false;
+ var widthAutoObserverDetection = (_sizeAutoObserverAdded && (_hostElement.css(_strFloat) !== 'none' /*|| _isTextarea */)) ? (MATH.round(sizeAutoObserverElementBCRect.right - sizeAutoObserverElementBCRect.left) === 0) && (!paddingAbsolute ? (_hostElementNative[LEXICON.cW] - _paddingX) > 0 : true) : false;
+ if (sizeAutoCapable && !widthAutoObserverDetection) {
+ var tmpCurrHostWidth = _hostElementNative[LEXICON.oW];
+ var tmpCurrContentGlueWidth = _contentGlueElement.css(_strWidth);
+ _contentGlueElement.css(_strWidth, _strAuto);
+
+ var tmpNewHostWidth = _hostElementNative[LEXICON.oW];
+ _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
+ widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
+ if (!widthAutoResizeDetection) {
+ _contentGlueElement.css(_strWidth, tmpCurrHostWidth + 1);
+ tmpNewHostWidth = _hostElementNative[LEXICON.oW];
+ _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
+ widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
+ }
+ }
+ var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden;
+ var widthAutoChanged = checkCacheAutoForce(widthAuto, _widthAutoCache);
+ var wasWidthAuto = !widthAuto && _widthAutoCache;
+
+ //detect height auto:
+ var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false;
+ var heightAutoChanged = checkCacheAutoForce(heightAuto, _heightAutoCache);
+ var wasHeightAuto = !heightAuto && _heightAutoCache;
+
+ //detect border:
+ //we need the border only if border box and auto size
+ var strMinusWidth = '-' + _strWidth;
+ var updateBorderX = (widthAuto && _isBorderBox) || !_isBorderBox;
+ var updateBorderY = (heightAuto && _isBorderBox) || !_isBorderBox;
+ var border = {
+ c: force,
+ t: updateBorderY ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strTop + strMinusWidth), true) : 0,
+ r: updateBorderX ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strRight + strMinusWidth), true) : 0,
+ b: updateBorderY ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strBottom + strMinusWidth), true) : 0,
+ l: updateBorderX ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strLeft + strMinusWidth), true) : 0
+ };
+
+ //detect margin:
+ var margin = {
+ c: force,
+ t: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strTop)),
+ r: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strRight)),
+ b: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strBottom)),
+ l: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strLeft))
+ };
+
+ //detect css max width & height:
+ var cssMaxValue = {
+ h: String(_hostElement.css(_strMaxMinus + _strHeight)),
+ w: String(_hostElement.css(_strMaxMinus + _strWidth))
+ };
+
+ //vars to apply correct css
+ var contentElementCSS = {};
+ var contentGlueElementCSS = {};
+
+ //funcs
+ var getHostSize = function () {
+ //has to be clientSize because offsetSize respect borders
+ return {
+ w: _hostElementNative[LEXICON.cW],
+ h: _hostElementNative[LEXICON.cH]
+ };
+ };
+ var getViewportSize = function () {
+ //viewport size is padding container because it never has padding, margin and a border
+ //determine zoom rounding error -> sometimes scrollWidth/Height is smaller than clientWidth/Height
+ //if this happens add the difference to the viewportSize to compensate the rounding error
+ return {
+ w: _paddingElementNative[LEXICON.oW] + MATH.max(0, _contentElementNative[LEXICON.cW] - _contentElementNative[LEXICON.sW]),
+ h: _paddingElementNative[LEXICON.oH] + MATH.max(0, _contentElementNative[LEXICON.cH] - _contentElementNative[LEXICON.sH])
+ };
+ };
+
+ //set info for padding
+ var paddingAbsoluteX = _paddingX = padding.l + padding.r;
+ var paddingAbsoluteY = _paddingY = padding.t + padding.b;
+ paddingAbsoluteX *= paddingAbsolute ? 1 : 0;
+ paddingAbsoluteY *= paddingAbsolute ? 1 : 0;
+ padding.c = checkCacheAutoForce(padding, _cssPaddingCache);
+
+ //set info for border
+ _borderX = border.l + border.r;
+ _borderY = border.t + border.b;
+ border.c = checkCacheAutoForce(border, _cssBorderCache);
+
+ //set info for margin
+ _marginX = margin.l + margin.r;
+ _marginY = margin.t + margin.b;
+ margin.c = checkCacheAutoForce(margin, _cssMarginCache);
+
+ //set info for css max value
+ cssMaxValue.ih = parseToZeroOrNumber(cssMaxValue.h); //ih = integer height
+ cssMaxValue.iw = parseToZeroOrNumber(cssMaxValue.w); //iw = integer width
+ cssMaxValue.ch = cssMaxValue.h.indexOf('px') > -1; //ch = correct height
+ cssMaxValue.cw = cssMaxValue.w.indexOf('px') > -1; //cw = correct width
+ cssMaxValue.c = checkCacheAutoForce(cssMaxValue, _cssMaxValueCache);
+
+ //refresh cache
+ _displayIsHiddenCache = displayIsHidden;
+ _textareaAutoWrappingCache = textareaAutoWrapping;
+ _cssDirectionCache = cssDirection;
+ _cssBoxSizingCache = boxSizing;
+ _widthAutoCache = widthAuto;
+ _heightAutoCache = heightAuto;
+ _cssPaddingCache = padding;
+ _cssBorderCache = border;
+ _cssMarginCache = margin;
+ _cssMaxValueCache = cssMaxValue;
+
+ //IEFix direction changed
+ if (cssDirectionChanged && _sizeAutoObserverAdded)
+ _sizeAutoObserverElement.css(_strFloat, isRTLRight);
+
+ //apply padding:
+ if (padding.c || cssDirectionChanged || paddingAbsoluteChanged || widthAutoChanged || heightAutoChanged || boxSizingChanged || sizeAutoCapableChanged) {
+ var paddingElementCSS = {};
+ var textareaCSS = {};
+ setTopRightBottomLeft(contentGlueElementCSS, _strMarginMinus, [-padding.t, -padding.r, -padding.b, -padding.l]);
+ if (paddingAbsolute) {
+ setTopRightBottomLeft(paddingElementCSS, _strEmpty, [padding.t, padding.r, padding.b, padding.l]);
+ if (_isTextarea)
+ setTopRightBottomLeft(textareaCSS, _strPaddingMinus);
+ else
+ setTopRightBottomLeft(contentElementCSS, _strPaddingMinus);
+ }
+ else {
+ setTopRightBottomLeft(paddingElementCSS, _strEmpty);
+ if (_isTextarea)
+ setTopRightBottomLeft(textareaCSS, _strPaddingMinus, [padding.t, padding.r, padding.b, padding.l]);
+ else
+ setTopRightBottomLeft(contentElementCSS, _strPaddingMinus, [padding.t, padding.r, padding.b, padding.l]);
+ }
+ _paddingElement.css(paddingElementCSS);
+ _targetElement.css(textareaCSS);
+ }
+
+ //viewport size is padding container because it never has padding, margin and a border.
+ _viewportSize = getViewportSize();
+
+ //update Textarea
+ var textareaSize = _isTextarea ? textareaUpdate() : false;
+ var textareaSizeChanged = _isTextarea && checkCacheAutoForce(textareaSize, _textareaSizeCache);
+ var textareaDynOrigSize = _isTextarea && textareaSize ? {
+ w: textareaDynWidth ? textareaSize._dynamicWidth : textareaSize._originalWidth,
+ h: textareaDynHeight ? textareaSize._dynamicHeight : textareaSize._originalHeight
+ } : {};
+ _textareaSizeCache = textareaSize;
+
+ //fix height auto / width auto in cooperation with current padding & boxSizing behavior:
+ if (heightAuto && (heightAutoChanged || paddingAbsoluteChanged || boxSizingChanged || cssMaxValue.c || padding.c || border.c)) {
+ /*
+ if (cssMaxValue.ch)
+ contentElementCSS[_strMaxMinus + _strHeight] =
+ (cssMaxValue.ch ? (cssMaxValue.ih - paddingAbsoluteY + (_isBorderBox ? -_borderY : _paddingY))
+ : _strEmpty);
+ */
+ contentElementCSS[_strHeight] = _strAuto;
+ }
+ else if (heightAutoChanged || paddingAbsoluteChanged) {
+ contentElementCSS[_strMaxMinus + _strHeight] = _strEmpty;
+ contentElementCSS[_strHeight] = _strHundredPercent;
+ }
+ if (widthAuto && (widthAutoChanged || paddingAbsoluteChanged || boxSizingChanged || cssMaxValue.c || padding.c || border.c || cssDirectionChanged)) {
+ /*
+ if (cssMaxValue.cw)
+ contentElementCSS[_strMaxMinus + _strWidth] =
+ (cssMaxValue.cw ? (cssMaxValue.iw - paddingAbsoluteX + (_isBorderBox ? -_borderX : _paddingX)) +
+ (_nativeScrollbarIsOverlaid.y ? _overlayScrollbarDummySize.y : 0)
+ : _strEmpty);
+ */
+ contentElementCSS[_strWidth] = _strAuto;
+ contentGlueElementCSS[_strMaxMinus + _strWidth] = _strHundredPercent; //IE Fix
+ }
+ else if (widthAutoChanged || paddingAbsoluteChanged) {
+ contentElementCSS[_strMaxMinus + _strWidth] = _strEmpty;
+ contentElementCSS[_strWidth] = _strHundredPercent;
+ contentElementCSS[_strFloat] = _strEmpty;
+ contentGlueElementCSS[_strMaxMinus + _strWidth] = _strEmpty; //IE Fix
+ }
+ if (widthAuto) {
+ if (!cssMaxValue.cw)
+ contentElementCSS[_strMaxMinus + _strWidth] = _strEmpty;
+ //textareaDynOrigSize.w || _strAuto :: doesnt works because applied margin will shift width
+ contentGlueElementCSS[_strWidth] = _strAuto;
+
+ contentElementCSS[_strWidth] = _strAuto;
+ contentElementCSS[_strFloat] = isRTLRight;
+ }
+ else {
+ contentGlueElementCSS[_strWidth] = _strEmpty;
+ }
+ if (heightAuto) {
+ if (!cssMaxValue.ch)
+ contentElementCSS[_strMaxMinus + _strHeight] = _strEmpty;
+ //textareaDynOrigSize.h || _contentElementNative[LEXICON.cH] :: use for anti scroll jumping
+ contentGlueElementCSS[_strHeight] = textareaDynOrigSize.h || _contentElementNative[LEXICON.cH];
+ }
+ else {
+ contentGlueElementCSS[_strHeight] = _strEmpty;
+ }
+ if (sizeAutoCapable)
+ _contentGlueElement.css(contentGlueElementCSS);
+ _contentElement.css(contentElementCSS);
+
+ //CHECKPOINT HERE ~
+ contentElementCSS = {};
+ contentGlueElementCSS = {};
+
+ //if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true
+ if (hostSizeChanged || contentSizeChanged || textareaSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || cssMaxValue.c || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged) {
+ var strOverflow = 'overflow';
+ var strOverflowX = strOverflow + '-x';
+ var strOverflowY = strOverflow + '-y';
+ var strHidden = 'hidden';
+ var strVisible = 'visible';
+
+ //Reset the viewport (very important for natively overlaid scrollbars and zoom change
+ //don't change the overflow prop as it is very expensive and affects performance !A LOT!
+ if(!_nativeScrollbarStyling) {
+ var viewportElementResetCSS = {};
+ var resetXTmp = _hasOverflowCache.y && _hideOverflowCache.ys && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.y ? _viewportElement.css(isRTLLeft) : -_nativeScrollbarSize.y) : 0;
+ var resetBottomTmp = _hasOverflowCache.x && _hideOverflowCache.xs && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.x ? _viewportElement.css(_strBottom) : -_nativeScrollbarSize.x) : 0;
+ setTopRightBottomLeft(viewportElementResetCSS, _strEmpty);
+ _viewportElement.css(viewportElementResetCSS);
+ }
+
+ //measure several sizes:
+ var contentMeasureElement = getContentMeasureElement();
+ //in Firefox content element has to have overflow hidden, else element margins aren't calculated properly, this element prevents this bug, but only if scrollbars aren't overlaid
+ var contentSize = {
+ //use clientSize because natively overlaidScrollbars add borders
+ w: textareaDynOrigSize.w || contentMeasureElement[LEXICON.cW],
+ h: textareaDynOrigSize.h || contentMeasureElement[LEXICON.cH]
+ };
+ var scrollSize = {
+ w: contentMeasureElement[LEXICON.sW],
+ h: contentMeasureElement[LEXICON.sH]
+ };
+
+ //apply the correct viewport style and measure viewport size
+ if(!_nativeScrollbarStyling) {
+ viewportElementResetCSS[_strBottom] = wasHeightAuto ? _strEmpty : resetBottomTmp;
+ viewportElementResetCSS[isRTLLeft] = wasWidthAuto ? _strEmpty : resetXTmp;
+ _viewportElement.css(viewportElementResetCSS);
+ }
+ _viewportSize = getViewportSize();
+
+ //measure and correct several sizes
+ var hostSize = getHostSize();
+ var contentGlueSize = {
+ //client/scrollSize + AbsolutePadding -> because padding is only applied to the paddingElement if its absolute, so you have to add it manually
+ //hostSize is clientSize -> so padding should be added manually, right? FALSE! Because content glue is inside hostElement, so we don't have to worry about padding
+ w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostSize.w),
+ h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostSize.h)
+ };
+ contentGlueSize.c = checkCacheAutoForce(contentGlueSize, _contentGlueSizeCache);
+ _contentGlueSizeCache = contentGlueSize;
+
+ //apply correct contentGlue size
+ if (sizeAutoCapable) {
+ //size contentGlue correctly to make sure the element has correct size if the sizing switches to auto
+ if (contentGlueSize.c || (heightAuto || widthAuto)) {
+ contentGlueElementCSS[_strWidth] = contentGlueSize.w;
+ contentGlueElementCSS[_strHeight] = contentGlueSize.h;
+
+ //textarea-sizes are already calculated correctly at this point
+ if (!_isTextarea) {
+ contentSize = {
+ //use clientSize because natively overlaidScrollbars add borders
+ w: contentMeasureElement[LEXICON.cW],
+ h: contentMeasureElement[LEXICON.cH]
+ };
+ }
+ }
+ var textareaCoverCSS = {};
+ var setContentGlueElementCSSfunction = function (horizontal) {
+ var scrollbarVars = getScrollbarVars(horizontal);
+ var wh = scrollbarVars._w_h;
+ var strWH = scrollbarVars._width_height;
+ var autoSize = horizontal ? widthAuto : heightAuto;
+ var borderSize = horizontal ? _borderX : _borderY;
+ var paddingSize = horizontal ? _paddingX : _paddingY;
+ var marginSize = horizontal ? _marginX : _marginY;
+ var maxSize = contentGlueElementCSS[strWH] + (_isBorderBox ? borderSize : -paddingSize);
+
+ //make contentGlue size -1 if element is not auto sized, to make sure that a resize event happens when the element shrinks
+ if (!autoSize || (!autoSize && border.c))
+ contentGlueElementCSS[strWH] = hostSize[wh] - (_isBorderBox ? 0 : paddingSize + borderSize) - 1 - marginSize;
+
+ //if size is auto and host is same size as max size, make content glue size +1 to make sure size changes will be detected
+ if (autoSize && cssMaxValue['c' + wh] && cssMaxValue['i' + wh] === maxSize)
+ contentGlueElementCSS[strWH] = maxSize + (_isBorderBox ? 0 : paddingSize) + 1;
+
+ //if size is auto and host is smaller than size as min size, make content glue size -1 to make sure size changes will be detected (this is only needed if padding is 0)
+ if (autoSize && (contentSize[wh] < _viewportSize[wh]) && (horizontal && _isTextarea ? !textareaAutoWrapping : true)) {
+ if (_isTextarea)
+ textareaCoverCSS[strWH] = parseToZeroOrNumber(_textareaCoverElement.css(strWH)) - 1;
+ contentGlueElementCSS[strWH] -= 1;
+ }
+
+ //make sure content glue size is at least 1
+ if (contentSize[wh] > 0)
+ contentGlueElementCSS[strWH] = MATH.max(1, contentGlueElementCSS[strWH]);
+ };
+ setContentGlueElementCSSfunction(true);
+ setContentGlueElementCSSfunction(false);
+
+ if (_isTextarea)
+ _textareaCoverElement.css(textareaCoverCSS);
+ _contentGlueElement.css(contentGlueElementCSS);
+ }
+ if (widthAuto)
+ contentElementCSS[_strWidth] = _strHundredPercent;
+ if (widthAuto && !_isBorderBox && !_mutationObserversConnected)
+ contentElementCSS[_strFloat] = 'none';
+
+ //apply and reset content style
+ _contentElement.css(contentElementCSS);
+ contentElementCSS = {};
+
+ //measure again, but this time all correct sizes:
+ var contentScrollSize = {
+ w: contentMeasureElement[LEXICON.sW],
+ h: contentMeasureElement[LEXICON.sH],
+ };
+ contentScrollSize.c = contentSizeChanged = checkCacheAutoForce(contentScrollSize, _contentScrollSizeCache);
+ _contentScrollSizeCache = contentScrollSize;
+
+ //refresh viewport size after correct measuring
+ _viewportSize = getViewportSize();
+
+ hostSize = getHostSize();
+ hostSizeChanged = checkCacheAutoForce(hostSize, _hostSizeCache);
+ _hostSizeCache = hostSize;
+
+ var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0);
+ var previousOverflowAmount = _overflowAmountCache;
+ var overflowBehaviorIsVS = {};
+ var overflowBehaviorIsVH = {};
+ var overflowBehaviorIsS = {};
+ var overflowAmount = {};
+ var hasOverflow = {};
+ var hideOverflow = {};
+ var canScroll = {};
+ var viewportRect = _paddingElementNative[LEXICON.bCR]();
+ var setOverflowVariables = function (horizontal) {
+ var scrollbarVars = getScrollbarVars(horizontal);
+ var scrollbarVarsInverted = getScrollbarVars(!horizontal);
+ var xyI = scrollbarVarsInverted._x_y;
+ var xy = scrollbarVars._x_y;
+ var wh = scrollbarVars._w_h;
+ var widthHeight = scrollbarVars._width_height;
+ var scrollMax = _strScroll + scrollbarVars._Left_Top + 'Max';
+ var fractionalOverflowAmount = viewportRect[widthHeight] ? MATH.abs(viewportRect[widthHeight] - _viewportSize[wh]) : 0;
+ var checkFractionalOverflowAmount = previousOverflowAmount && previousOverflowAmount[xy] > 0 && _viewportElementNative[scrollMax] === 0;
+ overflowBehaviorIsVS[xy] = overflowBehavior[xy] === 'v-s';
+ overflowBehaviorIsVH[xy] = overflowBehavior[xy] === 'v-h';
+ overflowBehaviorIsS[xy] = overflowBehavior[xy] === 's';
+ overflowAmount[xy] = MATH.max(0, MATH.round((contentScrollSize[wh] - _viewportSize[wh]) * 100) / 100);
+ overflowAmount[xy] *= (hideOverflowForceTextarea || (checkFractionalOverflowAmount && fractionalOverflowAmount > 0 && fractionalOverflowAmount < 1)) ? 0 : 1;
+ hasOverflow[xy] = overflowAmount[xy] > 0;
+
+ //hideOverflow:
+ //x || y : true === overflow is hidden by "overflow: scroll" OR "overflow: hidden"
+ //xs || ys : true === overflow is hidden by "overflow: scroll"
+ hideOverflow[xy] = overflowBehaviorIsVS[xy] || overflowBehaviorIsVH[xy] ? (hasOverflow[xyI] && !overflowBehaviorIsVS[xyI] && !overflowBehaviorIsVH[xyI]) : hasOverflow[xy];
+ hideOverflow[xy + 's'] = hideOverflow[xy] ? (overflowBehaviorIsS[xy] || overflowBehaviorIsVS[xy]) : false;
+
+ canScroll[xy] = hasOverflow[xy] && hideOverflow[xy + 's'];
+ };
+ setOverflowVariables(true);
+ setOverflowVariables(false);
+
+ overflowAmount.c = checkCacheAutoForce(overflowAmount, _overflowAmountCache);
+ _overflowAmountCache = overflowAmount;
+ hasOverflow.c = checkCacheAutoForce(hasOverflow, _hasOverflowCache);
+ _hasOverflowCache = hasOverflow;
+ hideOverflow.c = checkCacheAutoForce(hideOverflow, _hideOverflowCache);
+ _hideOverflowCache = hideOverflow;
+
+ //if native scrollbar is overlay at x OR y axis, prepare DOM
+ if (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) {
+ var borderDesign = 'px solid transparent';
+ var contentArrangeElementCSS = {};
+ var arrangeContent = {};
+ var arrangeChanged = force;
+ var setContentElementCSS;
+
+ if (hasOverflow.x || hasOverflow.y) {
+ arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty;
+ arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty;
+ arrangeChanged = checkCacheAutoForce(arrangeContent, _arrangeContentSizeCache);
+ _arrangeContentSizeCache = arrangeContent;
+ }
+
+ if (hasOverflow.c || hideOverflow.c || contentScrollSize.c || cssDirectionChanged || widthAutoChanged || heightAutoChanged || widthAuto || heightAuto || ignoreOverlayScrollbarHidingChanged) {
+ contentElementCSS[_strMarginMinus + isRTLRight] = contentElementCSS[_strBorderMinus + isRTLRight] = _strEmpty;
+ setContentElementCSS = function (horizontal) {
+ var scrollbarVars = getScrollbarVars(horizontal);
+ var scrollbarVarsInverted = getScrollbarVars(!horizontal);
+ var xy = scrollbarVars._x_y;
+ var strDirection = horizontal ? _strBottom : isRTLLeft;
+ var invertedAutoSize = horizontal ? heightAuto : widthAuto;
+
+ if (_nativeScrollbarIsOverlaid[xy] && hasOverflow[xy] && hideOverflow[xy + 's']) {
+ contentElementCSS[_strMarginMinus + strDirection] = invertedAutoSize ? (ignoreOverlayScrollbarHiding ? _strEmpty : _overlayScrollbarDummySize[xy]) : _strEmpty;
+ contentElementCSS[_strBorderMinus + strDirection] = ((horizontal ? !invertedAutoSize : true) && !ignoreOverlayScrollbarHiding) ? (_overlayScrollbarDummySize[xy] + borderDesign) : _strEmpty;
+ }
+ else {
+ arrangeContent[scrollbarVarsInverted._w_h] =
+ contentElementCSS[_strMarginMinus + strDirection] =
+ contentElementCSS[_strBorderMinus + strDirection] = _strEmpty;
+ arrangeChanged = true;
+ }
+ };
+
+ if (_nativeScrollbarStyling) {
+ if (ignoreOverlayScrollbarHiding)
+ removeClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
+ else
+ addClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
+ }
+ else {
+ setContentElementCSS(true);
+ setContentElementCSS(false);
+ }
+ }
+ if (ignoreOverlayScrollbarHiding) {
+ arrangeContent.w = arrangeContent.h = _strEmpty;
+ arrangeChanged = true;
+ }
+ if (arrangeChanged && !_nativeScrollbarStyling) {
+ contentArrangeElementCSS[_strWidth] = hideOverflow.y ? arrangeContent.w : _strEmpty;
+ contentArrangeElementCSS[_strHeight] = hideOverflow.x ? arrangeContent.h : _strEmpty;
+
+ if (!_contentArrangeElement) {
+ _contentArrangeElement = FRAMEWORK(generateDiv(_classNameContentArrangeElement));
+ _viewportElement.prepend(_contentArrangeElement);
+ }
+ _contentArrangeElement.css(contentArrangeElementCSS);
+ }
+ _contentElement.css(contentElementCSS);
+ }
+
+ var viewportElementCSS = {};
+ var paddingElementCSS = {};
+ var setViewportCSS;
+ if (hostSizeChanged || hasOverflow.c || hideOverflow.c || contentScrollSize.c || overflowBehaviorChanged || boxSizingChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged || clipAlwaysChanged || heightAutoChanged) {
+ viewportElementCSS[isRTLRight] = _strEmpty;
+ setViewportCSS = function (horizontal) {
+ var scrollbarVars = getScrollbarVars(horizontal);
+ var scrollbarVarsInverted = getScrollbarVars(!horizontal);
+ var xy = scrollbarVars._x_y;
+ var XY = scrollbarVars._X_Y;
+ var strDirection = horizontal ? _strBottom : isRTLLeft;
+
+ var reset = function () {
+ viewportElementCSS[strDirection] = _strEmpty;
+ _contentBorderSize[scrollbarVarsInverted._w_h] = 0;
+ };
+ if (hasOverflow[xy] && hideOverflow[xy + 's']) {
+ viewportElementCSS[strOverflow + XY] = _strScroll;
+ if (ignoreOverlayScrollbarHiding || _nativeScrollbarStyling) {
+ reset();
+ }
+ else {
+ viewportElementCSS[strDirection] = -(_nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[xy] : _nativeScrollbarSize[xy]);
+ _contentBorderSize[scrollbarVarsInverted._w_h] = _nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[scrollbarVarsInverted._x_y] : 0;
+ }
+ } else {
+ viewportElementCSS[strOverflow + XY] = _strEmpty;
+ reset();
+ }
+ };
+ setViewportCSS(true);
+ setViewportCSS(false);
+
+ // if the scroll container is too small and if there is any overflow with no overlay scrollbar (and scrollbar styling isn't possible),
+ // make viewport element greater in size (Firefox hide Scrollbars fix)
+ // because firefox starts hiding scrollbars on too small elements
+ // with this behavior the overflow calculation may be incorrect or the scrollbars would appear suddenly
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=292284
+ if (!_nativeScrollbarStyling
+ && (_viewportSize.h < _nativeScrollbarMinSize.x || _viewportSize.w < _nativeScrollbarMinSize.y)
+ && ((hasOverflow.x && hideOverflow.x && !_nativeScrollbarIsOverlaid.x) || (hasOverflow.y && hideOverflow.y && !_nativeScrollbarIsOverlaid.y))) {
+ viewportElementCSS[_strPaddingMinus + _strTop] = _nativeScrollbarMinSize.x;
+ viewportElementCSS[_strMarginMinus + _strTop] = -_nativeScrollbarMinSize.x;
+
+ viewportElementCSS[_strPaddingMinus + isRTLRight] = _nativeScrollbarMinSize.y;
+ viewportElementCSS[_strMarginMinus + isRTLRight] = -_nativeScrollbarMinSize.y;
+ }
+ else {
+ viewportElementCSS[_strPaddingMinus + _strTop] =
+ viewportElementCSS[_strMarginMinus + _strTop] =
+ viewportElementCSS[_strPaddingMinus + isRTLRight] =
+ viewportElementCSS[_strMarginMinus + isRTLRight] = _strEmpty;
+ }
+ viewportElementCSS[_strPaddingMinus + isRTLLeft] =
+ viewportElementCSS[_strMarginMinus + isRTLLeft] = _strEmpty;
+
+ //if there is any overflow (x OR y axis) and this overflow shall be hidden, make overflow hidden, else overflow visible
+ if ((hasOverflow.x && hideOverflow.x) || (hasOverflow.y && hideOverflow.y) || hideOverflowForceTextarea) {
+ //only hide if is Textarea
+ if (_isTextarea && hideOverflowForceTextarea) {
+ paddingElementCSS[strOverflowX] =
+ paddingElementCSS[strOverflowY] = strHidden;
+ }
+ }
+ else {
+ if (!clipAlways || (overflowBehaviorIsVH.x || overflowBehaviorIsVS.x || overflowBehaviorIsVH.y || overflowBehaviorIsVS.y)) {
+ //only un-hide if Textarea
+ if (_isTextarea) {
+ paddingElementCSS[strOverflowX] =
+ paddingElementCSS[strOverflowY] = _strEmpty;
+ }
+ viewportElementCSS[strOverflowX] =
+ viewportElementCSS[strOverflowY] = strVisible;
+ }
+ }
+
+ _paddingElement.css(paddingElementCSS);
+ _viewportElement.css(viewportElementCSS);
+ viewportElementCSS = {};
+
+ //force soft redraw in webkit because without the scrollbars will may appear because DOM wont be redrawn under special conditions
+ if ((hasOverflow.c || boxSizingChanged || widthAutoChanged || heightAutoChanged) && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
+ var elementStyle = _contentElementNative[LEXICON.s];
+ var dump;
+ elementStyle.webkitTransform = 'scale(1)';
+ elementStyle.display = 'run-in';
+ dump = _contentElementNative[LEXICON.oH];
+ elementStyle.display = _strEmpty; //|| dump; //use dump to prevent it from deletion if minify
+ elementStyle.webkitTransform = _strEmpty;
+ }
+ /*
+ //force hard redraw in webkit if native overlaid scrollbars shall appear
+ if (ignoreOverlayScrollbarHidingChanged && ignoreOverlayScrollbarHiding) {
+ _hostElement.hide();
+ var dump = _hostElementNative[LEXICON.oH];
+ _hostElement.show();
+ }
+ */
+ }
+
+ //change to direction RTL and width auto Bugfix in Webkit
+ //without this fix, the DOM still thinks the scrollbar is LTR and thus the content is shifted to the left
+ contentElementCSS = {};
+ if (cssDirectionChanged || widthAutoChanged || heightAutoChanged) {
+ if (_isRTL && widthAuto) {
+ var floatTmp = _contentElement.css(_strFloat);
+ var posLeftWithoutFloat = MATH.round(_contentElement.css(_strFloat, _strEmpty).css(_strLeft, _strEmpty).position().left);
+ _contentElement.css(_strFloat, floatTmp);
+ var posLeftWithFloat = MATH.round(_contentElement.position().left);
+
+ if (posLeftWithoutFloat !== posLeftWithFloat)
+ contentElementCSS[_strLeft] = posLeftWithoutFloat;
+ }
+ else {
+ contentElementCSS[_strLeft] = _strEmpty;
+ }
+ }
+ _contentElement.css(contentElementCSS);
+
+ //handle scroll position
+ if (_isTextarea && contentSizeChanged) {
+ var textareaInfo = getTextareaInfo();
+ if (textareaInfo) {
+ var textareaRowsChanged = _textareaInfoCache === undefined ? true : textareaInfo._rows !== _textareaInfoCache._rows;
+ var cursorRow = textareaInfo._cursorRow;
+ var cursorCol = textareaInfo._cursorColumn;
+ var widestRow = textareaInfo._widestRow;
+ var lastRow = textareaInfo._rows;
+ var lastCol = textareaInfo._columns;
+ var cursorPos = textareaInfo._cursorPosition;
+ var cursorMax = textareaInfo._cursorMax;
+ var cursorIsLastPosition = (cursorPos >= cursorMax && _textareaHasFocus);
+ var textareaScrollAmount = {
+ x: (!textareaAutoWrapping && (cursorCol === lastCol && cursorRow === widestRow)) ? _overflowAmountCache.x : -1,
+ y: (textareaAutoWrapping ? cursorIsLastPosition || textareaRowsChanged && (previousOverflowAmount ? (currScroll.y === previousOverflowAmount.y) : false) : (cursorIsLastPosition || textareaRowsChanged) && cursorRow === lastRow) ? _overflowAmountCache.y : -1
+ };
+ currScroll.x = textareaScrollAmount.x > -1 ? (_isRTL && _normalizeRTLCache && _rtlScrollBehavior.i ? 0 : textareaScrollAmount.x) : currScroll.x; //if inverted, scroll to 0 -> normalized this means to max scroll offset.
+ currScroll.y = textareaScrollAmount.y > -1 ? textareaScrollAmount.y : currScroll.y;
+ }
+ _textareaInfoCache = textareaInfo;
+ }
+ if (_isRTL && _rtlScrollBehavior.i && _nativeScrollbarIsOverlaid.y && hasOverflow.x && _normalizeRTLCache)
+ currScroll.x += _contentBorderSize.w || 0;
+ if (widthAuto)
+ _hostElement[_strScrollLeft](0);
+ if (heightAuto)
+ _hostElement[_strScrollTop](0);
+ _viewportElement[_strScrollLeft](currScroll.x)[_strScrollTop](currScroll.y);
+
+ //scrollbars management:
+ var scrollbarsVisibilityVisible = scrollbarsVisibility === 'v';
+ var scrollbarsVisibilityHidden = scrollbarsVisibility === 'h';
+ var scrollbarsVisibilityAuto = scrollbarsVisibility === 'a';
+
+ var showScrollbarH = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, true, true, canScroll.x);
+ var showScrollbarV = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, false, true, canScroll.y);
+ var hideScrollbarH = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, true, false, canScroll.x);
+ var hideScrollbarV = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, false, false, canScroll.y);
+
+ //manage class name which indicates scrollable overflow
+ if (hideOverflow.x || hideOverflow.y)
+ addClass(_hostElement, _classNameHostOverflow);
+ else
+ removeClass(_hostElement, _classNameHostOverflow);
+ if (hideOverflow.x)
+ addClass(_hostElement, _classNameHostOverflowX);
+ else
+ removeClass(_hostElement, _classNameHostOverflowX);
+ if (hideOverflow.y)
+ addClass(_hostElement, _classNameHostOverflowY);
+ else
+ removeClass(_hostElement, _classNameHostOverflowY);
+
+ //add or remove rtl class name for styling purposes
+ if (cssDirectionChanged) {
+ if (_isRTL)
+ addClass(_hostElement, _classNameHostRTL);
+ else
+ removeClass(_hostElement, _classNameHostRTL);
+ }
+
+ //manage the resize feature (CSS3 resize "polyfill" for this plugin)
+ if (_isBody)
+ addClass(_hostElement, _classNameHostResizeDisabled);
+ if (resizeChanged) {
+ removeClass(_scrollbarCornerElement, [
+ _classNameScrollbarCornerResize,
+ _classNameScrollbarCornerResizeB,
+ _classNameScrollbarCornerResizeH,
+ _classNameScrollbarCornerResizeV].join(_strSpace));
+ if (_resizeNone) {
+ addClass(_hostElement, _classNameHostResizeDisabled);
+ }
+ else {
+ removeClass(_hostElement, _classNameHostResizeDisabled);
+ addClass(_scrollbarCornerElement, _classNameScrollbarCornerResize);
+ if (_resizeBoth)
+ addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeB);
+ else if (_resizeHorizontal)
+ addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeH);
+ else if (_resizeVertical)
+ addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV);
+ }
+ }
+
+ //manage the scrollbars general visibility + the scrollbar interactivity (unusable class name)
+ if (scrollbarsVisibilityChanged || overflowBehaviorChanged || hideOverflow.c || hasOverflow.c || ignoreOverlayScrollbarHidingChanged) {
+ if (ignoreOverlayScrollbarHiding) {
+ if (ignoreOverlayScrollbarHidingChanged) {
+ removeClass(_hostElement, _classNameHostScrolling);
+ if (ignoreOverlayScrollbarHiding) {
+ hideScrollbarH();
+ hideScrollbarV();
+ }
+ }
+ }
+ else if (scrollbarsVisibilityAuto) {
+ if (canScroll.x)
+ showScrollbarH();
+ else
+ hideScrollbarH();
+
+ if (canScroll.y)
+ showScrollbarV();
+ else
+ hideScrollbarV();
+ }
+ else if (scrollbarsVisibilityVisible) {
+ showScrollbarH();
+ showScrollbarV();
+ }
+ else if (scrollbarsVisibilityHidden) {
+ hideScrollbarH();
+ hideScrollbarV();
+ }
+ }
+
+ //manage the scrollbars auto hide feature (auto hide them after specific actions)
+ if (scrollbarsAutoHideChanged || ignoreOverlayScrollbarHidingChanged) {
+ if (_scrollbarsAutoHideLeave || _scrollbarsAutoHideMove) {
+ setupHostMouseTouchEvents(true);
+ setupHostMouseTouchEvents();
+ }
+ else {
+ setupHostMouseTouchEvents(true);
+ }
+
+ if (_scrollbarsAutoHideNever)
+ refreshScrollbarsAutoHide(true);
+ else
+ refreshScrollbarsAutoHide(false, true);
+ }
+
+ //manage scrollbars handle length & offset - don't remove!
+ if (hostSizeChanged || overflowAmount.c || heightAutoChanged || widthAutoChanged || resizeChanged || boxSizingChanged || paddingAbsoluteChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged) {
+ refreshScrollbarHandleLength(true);
+ refreshScrollbarHandleOffset(true);
+ refreshScrollbarHandleLength(false);
+ refreshScrollbarHandleOffset(false);
+ }
+
+ //manage interactivity
+ if (scrollbarsClickScrollingChanged)
+ refreshScrollbarsInteractive(true, scrollbarsClickScrolling);
+ if (scrollbarsDragScrollingChanged)
+ refreshScrollbarsInteractive(false, scrollbarsDragScrolling);
+
+ //callbacks:
+ if (cssDirectionChanged) {
+ dispatchCallback('onDirectionChanged', {
+ isRTL: _isRTL,
+ dir: cssDirection
+ });
+ }
+ if (hostSizeChanged) {
+ dispatchCallback('onHostSizeChanged', {
+ width: _hostSizeCache.w,
+ height: _hostSizeCache.h
+ });
+ }
+ if (contentSizeChanged) {
+ dispatchCallback('onContentSizeChanged', {
+ width: _contentScrollSizeCache.w,
+ height: _contentScrollSizeCache.h
+ });
+ }
+ if (hasOverflow.c || hideOverflow.c) {
+ dispatchCallback('onOverflowChanged', {
+ x: hasOverflow.x,
+ y: hasOverflow.y,
+ xScrollable: hideOverflow.xs,
+ yScrollable: hideOverflow.ys,
+ clipped: hideOverflow.x || hideOverflow.y
+ });
+ }
+ if (overflowAmount.c) {
+ dispatchCallback('onOverflowAmountChanged', {
+ x: overflowAmount.x,
+ y: overflowAmount.y
+ });
+ }
+ }
+
+ //fix body min size
+ if (_isBody && _bodyMinSizeCache && (_hasOverflowCache.c || _bodyMinSizeCache.c)) {
+ //its possible that no min size was measured until now, because the content arrange element was just added now, in this case, measure now the min size.
+ if (!_bodyMinSizeCache.f)
+ bodyMinSizeChanged();
+ if (_nativeScrollbarIsOverlaid.y && _hasOverflowCache.x)
+ _contentElement.css(_strMinMinus + _strWidth, _bodyMinSizeCache.w + _overlayScrollbarDummySize.y);
+ if (_nativeScrollbarIsOverlaid.x && _hasOverflowCache.y)
+ _contentElement.css(_strMinMinus + _strHeight, _bodyMinSizeCache.h + _overlayScrollbarDummySize.x);
+ _bodyMinSizeCache.c = false;
+ }
+
+ //freezeResizeObserver(_sizeObserverElement, false);
+ //freezeResizeObserver(_sizeAutoObserverElement, false);
+
+ dispatchCallback('onUpdated', { forced: force });
+ }
+
+
+ //==== Options ====//
+
+ /**
+ * Sets new options but doesn't call the update method.
+ * @param newOptions The object which contains the new options.
+ * @returns {*} A object which contains the changed options.
+ */
+ function setOptions(newOptions) {
+ var validatedOpts = _pluginsOptions._validate(newOptions, _pluginsOptions._template, true, _currentOptions)
+
+ _currentOptions = extendDeep({}, _currentOptions, validatedOpts._default);
+ _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, validatedOpts._prepared);
+
+ return validatedOpts._prepared;
+ }
+
+
+ //==== Structure ====//
+
+ /**
+ * Builds or destroys the wrapper and helper DOM elements.
+ * @param destroy Indicates whether the DOM shall be build or destroyed.
+ */
+ function setupStructureDOM(destroy) {
+ var strParent = 'parent';
+ var classNameResizeObserverHost = 'os-resize-observer-host';
+ var classNameTextareaElementFull = _classNameTextareaElement + _strSpace + _classNameTextInherit;
+ var textareaClass = _isTextarea ? _strSpace + _classNameTextInherit : _strEmpty;
+ var adoptAttrs = _currentPreparedOptions.textarea.inheritedAttrs;
+ var adoptAttrsMap = {};
+ var applyAdoptedAttrs = function () {
+ var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement;
+ each(adoptAttrsMap, function (key, value) {
+ if (type(value) == TYPES.s) {
+ if (key == LEXICON.c)
+ applyAdoptedAttrsElm.addClass(value);
+ else
+ applyAdoptedAttrsElm.attr(key, value);
+ }
+ });
+ };
+ var hostElementClassNames = [
+ _classNameHostElement,
+ _classNameHostTextareaElement,
+ _classNameHostResizeDisabled,
+ _classNameHostRTL,
+ _classNameHostScrollbarHorizontalHidden,
+ _classNameHostScrollbarVerticalHidden,
+ _classNameHostTransition,
+ _classNameHostScrolling,
+ _classNameHostOverflow,
+ _classNameHostOverflowX,
+ _classNameHostOverflowY,
+ _classNameThemeNone,
+ _classNameTextareaElement,
+ _classNameTextInherit,
+ _classNameCache].join(_strSpace);
+ var hostElementCSS = {};
+
+ //get host element as first element, because that's the most upper element and required for the other elements
+ _hostElement = _hostElement || (_isTextarea ? (_domExists ? _targetElement[strParent]()[strParent]()[strParent]()[strParent]() : FRAMEWORK(generateDiv(_classNameHostTextareaElement))) : _targetElement);
+ _contentElement = _contentElement || selectOrGenerateDivByClass(_classNameContentElement + textareaClass);
+ _viewportElement = _viewportElement || selectOrGenerateDivByClass(_classNameViewportElement + textareaClass);
+ _paddingElement = _paddingElement || selectOrGenerateDivByClass(_classNamePaddingElement + textareaClass);
+ _sizeObserverElement = _sizeObserverElement || selectOrGenerateDivByClass(classNameResizeObserverHost);
+ _textareaCoverElement = _textareaCoverElement || (_isTextarea ? selectOrGenerateDivByClass(_classNameTextareaCoverElement) : undefined);
+
+ //on destroy, remove all generated class names from the host element before collecting the adopted attributes
+ //to prevent adopting generated class names
+ if (destroy)
+ removeClass(_hostElement, hostElementClassNames);
+
+ //collect all adopted attributes
+ adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(_strSpace) : adoptAttrs;
+ if (type(adoptAttrs) == TYPES.a && _isTextarea) {
+ each(adoptAttrs, function (i, v) {
+ if (type(v) == TYPES.s) {
+ adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v);
+ }
+ });
+ }
+
+ if (!destroy) {
+ if (_isTextarea) {
+ if (!_currentPreparedOptions.sizeAutoCapable) {
+ hostElementCSS[_strWidth] = _targetElement.css(_strWidth);
+ hostElementCSS[_strHeight] = _targetElement.css(_strHeight);
+ }
+
+ if (!_domExists)
+ _targetElement.addClass(_classNameTextInherit).wrap(_hostElement);
+
+ //jQuery clones elements in wrap functions, so we have to select them again
+ _hostElement = _targetElement[strParent]().css(hostElementCSS);
+ }
+
+ if (!_domExists) {
+ //add the correct class to the target element
+ addClass(_targetElement, _isTextarea ? classNameTextareaElementFull : _classNameHostElement);
+
+ //wrap the content into the generated elements to create the required DOM
+ _hostElement.wrapInner(_contentElement)
+ .wrapInner(_viewportElement)
+ .wrapInner(_paddingElement)
+ .prepend(_sizeObserverElement);
+
+ //jQuery clones elements in wrap functions, so we have to select them again
+ _contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);
+ _viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);
+ _paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);
+
+ if (_isTextarea) {
+ _contentElement.prepend(_textareaCoverElement);
+ applyAdoptedAttrs();
+ }
+ }
+
+ if (_nativeScrollbarStyling)
+ addClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
+ if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)
+ addClass(_viewportElement, _classNameViewportNativeScrollbarsOverlaid);
+ if (_isBody)
+ addClass(_htmlElement, _classNameHTMLElement);
+
+ _sizeObserverElementNative = _sizeObserverElement[0];
+ _hostElementNative = _hostElement[0];
+ _paddingElementNative = _paddingElement[0];
+ _viewportElementNative = _viewportElement[0];
+ _contentElementNative = _contentElement[0];
+
+ updateViewportAttrsFromTarget();
+ }
+ else {
+ if (_domExists && _initialized) {
+ //clear size observer
+ _sizeObserverElement.children().remove();
+
+ //remove the style property and classes from already generated elements
+ each([_paddingElement, _viewportElement, _contentElement, _textareaCoverElement], function (i, elm) {
+ if (elm) {
+ removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
+ }
+ });
+
+ //add classes to the host element which was removed previously to match the expected DOM
+ addClass(_hostElement, _isTextarea ? _classNameHostTextareaElement : _classNameHostElement);
+ }
+ else {
+ //remove size observer
+ remove(_sizeObserverElement);
+
+ //unwrap the content to restore DOM
+ _contentElement.contents()
+ .unwrap()
+ .unwrap()
+ .unwrap();
+
+ if (_isTextarea) {
+ _targetElement.unwrap();
+ remove(_hostElement);
+ remove(_textareaCoverElement);
+ applyAdoptedAttrs();
+ }
+ }
+
+ if (_isTextarea)
+ _targetElement.removeAttr(LEXICON.s);
+
+ if (_isBody)
+ removeClass(_htmlElement, _classNameHTMLElement);
+ }
+ }
+
+ /**
+ * Adds or removes all wrapper elements interactivity events.
+ * @param destroy Indicates whether the Events shall be added or removed.
+ */
+ function setupStructureEvents() {
+ var textareaKeyDownRestrictedKeyCodes = [
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, //F1 to F12
+ 33, 34, //page up, page down
+ 37, 38, 39, 40, //left, up, right, down arrows
+ 16, 17, 18, 19, 20, 144 //Shift, Ctrl, Alt, Pause, CapsLock, NumLock
+ ];
+ var textareaKeyDownKeyCodesList = [];
+ var textareaUpdateIntervalID;
+ var scrollStopTimeoutId;
+ var scrollStopDelay = 175;
+ var strFocus = 'focus';
+
+ function updateTextarea(doClearInterval) {
+ textareaUpdate();
+ _base.update(_strAuto);
+ if (doClearInterval && _autoUpdateRecommended)
+ clearInterval(textareaUpdateIntervalID);
+ }
+ function textareaOnScroll(event) {
+ _targetElement[_strScrollLeft](_rtlScrollBehavior.i && _normalizeRTLCache ? 9999999 : 0);
+ _targetElement[_strScrollTop](0);
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ return false;
+ }
+ function textareaOnDrop(event) {
+ setTimeout(function () {
+ if (!_destroyed)
+ updateTextarea();
+ }, 50);
+ }
+ function textareaOnFocus() {
+ _textareaHasFocus = true;
+ addClass(_hostElement, strFocus);
+ }
+ function textareaOnFocusout() {
+ _textareaHasFocus = false;
+ textareaKeyDownKeyCodesList = [];
+ removeClass(_hostElement, strFocus);
+ updateTextarea(true);
+ }
+ function textareaOnKeyDown(event) {
+ var keyCode = event.keyCode;
+
+ if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {
+ if (!textareaKeyDownKeyCodesList[LEXICON.l]) {
+ updateTextarea();
+ textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60);
+ }
+ if (inArray(keyCode, textareaKeyDownKeyCodesList) < 0)
+ textareaKeyDownKeyCodesList.push(keyCode);
+ }
+ }
+ function textareaOnKeyUp(event) {
+ var keyCode = event.keyCode;
+ var index = inArray(keyCode, textareaKeyDownKeyCodesList);
+
+ if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {
+ if (index > -1)
+ textareaKeyDownKeyCodesList.splice(index, 1);
+ if (!textareaKeyDownKeyCodesList[LEXICON.l])
+ updateTextarea(true);
+ }
+ }
+ function contentOnTransitionEnd(event) {
+ if (_autoUpdateCache === true)
+ return;
+ event = event.originalEvent || event;
+ if (isSizeAffectingCSSProperty(event.propertyName))
+ _base.update(_strAuto);
+ }
+ function viewportOnScroll(event) {
+ if (!_sleeping) {
+ if (scrollStopTimeoutId !== undefined)
+ clearTimeout(scrollStopTimeoutId);
+ else {
+ if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
+ refreshScrollbarsAutoHide(true);
+
+ if (!nativeOverlayScrollbarsAreActive())
+ addClass(_hostElement, _classNameHostScrolling);
+
+ dispatchCallback('onScrollStart', event);
+ }
+
+ //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset
+ //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point
+ //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove
+ if (!_scrollbarsHandlesDefineScrollPos) {
+ refreshScrollbarHandleOffset(true);
+ refreshScrollbarHandleOffset(false);
+ }
+ dispatchCallback('onScroll', event);
+
+ scrollStopTimeoutId = setTimeout(function () {
+ if (!_destroyed) {
+ //OnScrollStop:
+ clearTimeout(scrollStopTimeoutId);
+ scrollStopTimeoutId = undefined;
+
+ if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
+ refreshScrollbarsAutoHide(false);
+
+ if (!nativeOverlayScrollbarsAreActive())
+ removeClass(_hostElement, _classNameHostScrolling);
+
+ dispatchCallback('onScrollStop', event);
+ }
+ }, scrollStopDelay);
+ }
+ }
+
+
+ if (_isTextarea) {
+ if (_msieVersion > 9 || !_autoUpdateRecommended) {
+ addDestroyEventListener(_targetElement, 'input', updateTextarea);
+ }
+ else {
+ addDestroyEventListener(_targetElement,
+ [_strKeyDownEvent, _strKeyUpEvent],
+ [textareaOnKeyDown, textareaOnKeyUp]);
+ }
+
+ addDestroyEventListener(_targetElement,
+ [_strScroll, 'drop', strFocus, strFocus + 'out'],
+ [textareaOnScroll, textareaOnDrop, textareaOnFocus, textareaOnFocusout]);
+ }
+ else {
+ addDestroyEventListener(_contentElement, _strTransitionEndEvent, contentOnTransitionEnd);
+ }
+ addDestroyEventListener(_viewportElement, _strScroll, viewportOnScroll, true);
+ }
+
+
+ //==== Scrollbars ====//
+
+ /**
+ * Builds or destroys all scrollbar DOM elements (scrollbar, track, handle)
+ * @param destroy Indicates whether the DOM shall be build or destroyed.
+ */
+ function setupScrollbarsDOM(destroy) {
+ var selectOrGenerateScrollbarDOM = function (isHorizontal) {
+ var scrollbarClassName = isHorizontal ? _classNameScrollbarHorizontal : _classNameScrollbarVertical;
+ var scrollbar = selectOrGenerateDivByClass(_classNameScrollbar + _strSpace + scrollbarClassName, true);
+ var track = selectOrGenerateDivByClass(_classNameScrollbarTrack, scrollbar);
+ var handle = selectOrGenerateDivByClass(_classNameScrollbarHandle, scrollbar);
+
+ if (!_domExists && !destroy) {
+ scrollbar.append(track);
+ track.append(handle);
+ }
+
+ return {
+ _scrollbar: scrollbar,
+ _track: track,
+ _handle: handle
+ };
+ };
+ function resetScrollbarDOM(isHorizontal) {
+ var scrollbarVars = getScrollbarVars(isHorizontal);
+ var scrollbar = scrollbarVars._scrollbar;
+ var track = scrollbarVars._track;
+ var handle = scrollbarVars._handle;
+
+ if (_domExists && _initialized) {
+ each([scrollbar, track, handle], function (i, elm) {
+ removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
+ });
+ }
+ else {
+ remove(scrollbar || selectOrGenerateScrollbarDOM(isHorizontal)._scrollbar);
+ }
+ }
+ var horizontalElements;
+ var verticalElements;
+
+ if (!destroy) {
+ horizontalElements = selectOrGenerateScrollbarDOM(true);
+ verticalElements = selectOrGenerateScrollbarDOM();
+
+ _scrollbarHorizontalElement = horizontalElements._scrollbar;
+ _scrollbarHorizontalTrackElement = horizontalElements._track;
+ _scrollbarHorizontalHandleElement = horizontalElements._handle;
+ _scrollbarVerticalElement = verticalElements._scrollbar;
+ _scrollbarVerticalTrackElement = verticalElements._track;
+ _scrollbarVerticalHandleElement = verticalElements._handle;
+
+ if (!_domExists) {
+ _paddingElement.after(_scrollbarVerticalElement);
+ _paddingElement.after(_scrollbarHorizontalElement);
+ }
+ }
+ else {
+ resetScrollbarDOM(true);
+ resetScrollbarDOM();
+ }
+ }
+
+ /**
+ * Initializes all scrollbar interactivity events. (track and handle dragging, clicking, scrolling)
+ * @param isHorizontal True if the target scrollbar is the horizontal scrollbar, false if the target scrollbar is the vertical scrollbar.
+ */
+ function setupScrollbarEvents(isHorizontal) {
+ var scrollbarVars = getScrollbarVars(isHorizontal);
+ var scrollbarVarsInfo = scrollbarVars._info;
+ var insideIFrame = _windowElementNative.top !== _windowElementNative;
+ var xy = scrollbarVars._x_y;
+ var XY = scrollbarVars._X_Y;
+ var scroll = _strScroll + scrollbarVars._Left_Top;
+ var strActive = 'active';
+ var strSnapHandle = 'snapHandle';
+ var scrollDurationFactor = 1;
+ var increaseDecreaseScrollAmountKeyCodes = [16, 17]; //shift, ctrl
+ var trackTimeout;
+ var mouseDownScroll;
+ var mouseDownOffset;
+ var mouseDownInvertedScale;
+
+ function getPointerPosition(event) {
+ return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames.
+ }
+ function getPreparedScrollbarsOption(name) {
+ return _currentPreparedOptions.scrollbars[name];
+ }
+ function increaseTrackScrollAmount() {
+ scrollDurationFactor = 0.5;
+ }
+ function decreaseTrackScrollAmount() {
+ scrollDurationFactor = 1;
+ }
+ function documentKeyDown(event) {
+ if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
+ increaseTrackScrollAmount();
+ }
+ function documentKeyUp(event) {
+ if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
+ decreaseTrackScrollAmount();
+ }
+ function onMouseTouchDownContinue(event) {
+ var originalEvent = event.originalEvent || event;
+ var isTouchEvent = originalEvent.touches !== undefined;
+ return _sleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
+ }
+ function documentDragMove(event) {
+ if (onMouseTouchDownContinue(event)) {
+ var trackLength = scrollbarVarsInfo._trackLength;
+ var handleLength = scrollbarVarsInfo._handleLength;
+ var scrollRange = scrollbarVarsInfo._maxScroll;
+ var scrollRaw = (getPointerPosition(event) - mouseDownOffset) * mouseDownInvertedScale;
+ var scrollDeltaPercent = scrollRaw / (trackLength - handleLength);
+ var scrollDelta = (scrollRange * scrollDeltaPercent);
+ scrollDelta = isFinite(scrollDelta) ? scrollDelta : 0;
+ if (_isRTL && isHorizontal && !_rtlScrollBehavior.i)
+ scrollDelta *= -1;
+
+ _viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta));
+
+ if (_scrollbarsHandlesDefineScrollPos)
+ refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta);
+
+ if (!_supportPassiveEvents)
+ COMPATIBILITY.prvD(event);
+ }
+ else
+ documentMouseTouchUp(event);
+ }
+ function documentMouseTouchUp(event) {
+ event = event || event.originalEvent;
+
+ setupResponsiveEventListener(_documentElement,
+ [_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],
+ [documentDragMove, documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart],
+ true);
+
+ if (_scrollbarsHandlesDefineScrollPos)
+ refreshScrollbarHandleOffset(isHorizontal, true);
+
+ _scrollbarsHandlesDefineScrollPos = false;
+ removeClass(_bodyElement, _classNameDragging);
+ removeClass(scrollbarVars._handle, strActive);
+ removeClass(scrollbarVars._track, strActive);
+ removeClass(scrollbarVars._scrollbar, strActive);
+
+ mouseDownScroll = undefined;
+ mouseDownOffset = undefined;
+ mouseDownInvertedScale = 1;
+
+ decreaseTrackScrollAmount();
+
+ if (trackTimeout !== undefined) {
+ _base.scrollStop();
+ clearTimeout(trackTimeout);
+ trackTimeout = undefined;
+ }
+
+ if (event) {
+ var rect = _hostElementNative[LEXICON.bCR]();
+ var mouseInsideHost = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
+
+ //if mouse is outside host element
+ if (!mouseInsideHost)
+ hostOnMouseLeave();
+
+ if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
+ refreshScrollbarsAutoHide(false);
+ }
+ }
+ function onHandleMouseTouchDown(event) {
+ if (onMouseTouchDownContinue(event))
+ onHandleMouseTouchDownAction(event);
+ }
+ function onHandleMouseTouchDownAction(event) {
+ mouseDownScroll = _viewportElement[scroll]();
+ mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll;
+ if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL)
+ mouseDownScroll = mouseDownScroll < 0 ? 0 : mouseDownScroll;
+
+ mouseDownInvertedScale = getHostElementInvertedScale()[xy];
+ mouseDownOffset = getPointerPosition(event);
+
+ _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);
+ addClass(_bodyElement, _classNameDragging);
+ addClass(scrollbarVars._handle, strActive);
+ addClass(scrollbarVars._scrollbar, strActive);
+
+ setupResponsiveEventListener(_documentElement,
+ [_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strSelectStartEvent],
+ [documentDragMove, documentMouseTouchUp, documentOnSelectStart]);
+
+ if (_msieVersion || !_documentMixed)
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ }
+ function onTrackMouseTouchDown(event) {
+ if (onMouseTouchDownContinue(event)) {
+ var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h]);
+ var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top];
+ var ctrlKey = event.ctrlKey;
+ var instantScroll = event.shiftKey;
+ var instantScrollTransition = instantScroll && ctrlKey;
+ var isFirstIteration = true;
+ var easing = 'linear';
+ var decreaseScroll;
+ var finishedCondition;
+ var scrollActionFinsished = function (transition) {
+ if (_scrollbarsHandlesDefineScrollPos)
+ refreshScrollbarHandleOffset(isHorizontal, transition);
+ };
+ var scrollActionInstantFinished = function () {
+ scrollActionFinsished();
+ onHandleMouseTouchDownAction(event);
+ };
+ var scrollAction = function () {
+ if (!_destroyed) {
+ var mouseOffset = (mouseDownOffset - trackOffset) * mouseDownInvertedScale;
+ var handleOffset = scrollbarVarsInfo._handleOffset;
+ var trackLength = scrollbarVarsInfo._trackLength;
+ var handleLength = scrollbarVarsInfo._handleLength;
+ var scrollRange = scrollbarVarsInfo._maxScroll;
+ var currScroll = scrollbarVarsInfo._currentScroll;
+ var scrollDuration = 270 * scrollDurationFactor;
+ var timeoutDelay = isFirstIteration ? MATH.max(400, scrollDuration) : scrollDuration;
+ var instantScrollPosition = scrollRange * ((mouseOffset - (handleLength / 2)) / (trackLength - handleLength)); // 100% * positionPercent
+ var rtlIsNormal = _isRTL && isHorizontal && ((!_rtlScrollBehavior.i && !_rtlScrollBehavior.n) || _normalizeRTLCache);
+ var decreaseScrollCondition = rtlIsNormal ? handleOffset < mouseOffset : handleOffset > mouseOffset;
+ var scrollObj = {};
+ var animationObj = {
+ easing: easing,
+ step: function (now) {
+ if (_scrollbarsHandlesDefineScrollPos) {
+ _viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/4340
+ refreshScrollbarHandleOffset(isHorizontal, now);
+ }
+ }
+ };
+ instantScrollPosition = isFinite(instantScrollPosition) ? instantScrollPosition : 0;
+ instantScrollPosition = _isRTL && isHorizontal && !_rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
+
+ //_base.scrollStop();
+
+ if (instantScroll) {
+ _viewportElement[scroll](instantScrollPosition); //scroll instantly to new position
+ if (instantScrollTransition) {
+ //get the scroll position after instant scroll (in case CSS Snap Points are used) to get the correct snapped scroll position
+ //and the animation stops at the correct point
+ instantScrollPosition = _viewportElement[scroll]();
+ //scroll back to the position before instant scrolling so animation can be performed
+ _viewportElement[scroll](currScroll);
+
+ instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
+ instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.n ? -instantScrollPosition : instantScrollPosition;
+
+ scrollObj[xy] = instantScrollPosition;
+ _base.scroll(scrollObj, extendDeep(animationObj, {
+ duration: 130,
+ complete: scrollActionInstantFinished
+ }));
+ }
+ else
+ scrollActionInstantFinished();
+ }
+ else {
+ decreaseScroll = isFirstIteration ? decreaseScrollCondition : decreaseScroll;
+ finishedCondition = rtlIsNormal
+ ? (decreaseScroll ? handleOffset + handleLength >= mouseOffset : handleOffset <= mouseOffset)
+ : (decreaseScroll ? handleOffset <= mouseOffset : handleOffset + handleLength >= mouseOffset);
+
+ if (finishedCondition) {
+ clearTimeout(trackTimeout);
+ _base.scrollStop();
+ trackTimeout = undefined;
+ scrollActionFinsished(true);
+ }
+ else {
+ trackTimeout = setTimeout(scrollAction, timeoutDelay);
+
+ scrollObj[xy] = (decreaseScroll ? '-=' : '+=') + scrollDistance;
+ _base.scroll(scrollObj, extendDeep(animationObj, {
+ duration: scrollDuration
+ }));
+ }
+ isFirstIteration = false;
+ }
+ }
+ };
+ if (ctrlKey)
+ increaseTrackScrollAmount();
+
+ mouseDownInvertedScale = getHostElementInvertedScale()[xy];
+ mouseDownOffset = COMPATIBILITY.page(event)[xy];
+
+ _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);
+ addClass(_bodyElement, _classNameDragging);
+ addClass(scrollbarVars._track, strActive);
+ addClass(scrollbarVars._scrollbar, strActive);
+
+ setupResponsiveEventListener(_documentElement,
+ [_strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],
+ [documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart]);
+
+ scrollAction();
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ }
+ }
+ function onTrackMouseTouchEnter(event) {
+ //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move".
+ _scrollbarsHandleHovered = true;
+ if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
+ refreshScrollbarsAutoHide(true);
+ }
+ function onTrackMouseTouchLeave(event) {
+ _scrollbarsHandleHovered = false;
+ if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
+ refreshScrollbarsAutoHide(false);
+ }
+ function onScrollbarMouseTouchDown(event) {
+ COMPATIBILITY.stpP(event);
+ }
+
+ addDestroyEventListener(scrollbarVars._handle,
+ _strMouseTouchDownEvent,
+ onHandleMouseTouchDown);
+ addDestroyEventListener(scrollbarVars._track,
+ [_strMouseTouchDownEvent, _strMouseTouchEnter, _strMouseTouchLeave],
+ [onTrackMouseTouchDown, onTrackMouseTouchEnter, onTrackMouseTouchLeave]);
+ addDestroyEventListener(scrollbarVars._scrollbar,
+ _strMouseTouchDownEvent,
+ onScrollbarMouseTouchDown);
+
+ if (_supportTransition) {
+ addDestroyEventListener(scrollbarVars._scrollbar, _strTransitionEndEvent, function (event) {
+ if (event.target !== scrollbarVars._scrollbar[0])
+ return;
+ refreshScrollbarHandleLength(isHorizontal);
+ refreshScrollbarHandleOffset(isHorizontal);
+ });
+ }
+ }
+
+ /**
+ * Shows or hides the given scrollbar and applied a class name which indicates if the scrollbar is scrollable or not.
+ * @param isHorizontal True if the horizontal scrollbar is the target, false if the vertical scrollbar is the target.
+ * @param shallBeVisible True if the scrollbar shall be shown, false if hidden.
+ * @param canScroll True if the scrollbar is scrollable, false otherwise.
+ */
+ function refreshScrollbarAppearance(isHorizontal, shallBeVisible, canScroll) {
+ var scrollbarClassName = isHorizontal ? _classNameHostScrollbarHorizontalHidden : _classNameHostScrollbarVerticalHidden;
+ var scrollbarElement = isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement;
+
+ if (shallBeVisible)
+ removeClass(_hostElement, scrollbarClassName);
+ else
+ addClass(_hostElement, scrollbarClassName);
+
+ if (canScroll)
+ removeClass(scrollbarElement, _classNameScrollbarUnusable);
+ else
+ addClass(scrollbarElement, _classNameScrollbarUnusable);
+ }
+
+ /**
+ * Autoshows / autohides both scrollbars with.
+ * @param shallBeVisible True if the scrollbars shall be autoshown (only the case if they are hidden by a autohide), false if the shall be auto hidden.
+ * @param delayfree True if the scrollbars shall be hidden without a delay, false or undefined otherwise.
+ */
+ function refreshScrollbarsAutoHide(shallBeVisible, delayfree) {
+ clearTimeout(_scrollbarsAutoHideTimeoutId);
+ if (shallBeVisible) {
+ //if(_hasOverflowCache.x && _hideOverflowCache.xs)
+ removeClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
+ //if(_hasOverflowCache.y && _hideOverflowCache.ys)
+ removeClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
+ }
+ else {
+ var anyActive;
+ var strActive = 'active';
+ var hide = function () {
+ if (!_scrollbarsHandleHovered && !_destroyed) {
+ anyActive = _scrollbarHorizontalHandleElement.hasClass(strActive) || _scrollbarVerticalHandleElement.hasClass(strActive);
+ if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
+ addClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
+ if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
+ addClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
+ }
+ };
+ if (_scrollbarsAutoHideDelay > 0 && delayfree !== true)
+ _scrollbarsAutoHideTimeoutId = setTimeout(hide, _scrollbarsAutoHideDelay);
+ else
+ hide();
+ }
+ }
+
+ /**
+ * Refreshes the handle length of the given scrollbar.
+ * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
+ */
+ function refreshScrollbarHandleLength(isHorizontal) {
+ var handleCSS = {};
+ var scrollbarVars = getScrollbarVars(isHorizontal);
+ var scrollbarVarsInfo = scrollbarVars._info;
+ var digit = 1000000;
+ //get and apply intended handle length
+ var handleRatio = MATH.min(1, (_hostSizeCache[scrollbarVars._w_h] - (_paddingAbsoluteCache ? (isHorizontal ? _paddingX : _paddingY) : 0)) / _contentScrollSizeCache[scrollbarVars._w_h]);
+ handleCSS[scrollbarVars._width_height] = (MATH.floor(handleRatio * 100 * digit) / digit) + '%'; //the last * digit / digit is for flooring to the 4th digit
+
+ if (!nativeOverlayScrollbarsAreActive())
+ scrollbarVars._handle.css(handleCSS);
+
+ //measure the handle length to respect min & max length
+ scrollbarVarsInfo._handleLength = scrollbarVars._handle[0]['offset' + scrollbarVars._Width_Height];
+ scrollbarVarsInfo._handleLengthRatio = handleRatio;
+ }
+
+ /**
+ * Refreshes the handle offset of the given scrollbar.
+ * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
+ * @param scrollOrTransition The scroll position of the given scrollbar axis to which the handle shall be moved or a boolean which indicates whether a transition shall be applied. If undefined or boolean if the current scroll-offset is taken. (if isHorizontal ? scrollLeft : scrollTop)
+ */
+ function refreshScrollbarHandleOffset(isHorizontal, scrollOrTransition) {
+ var transition = type(scrollOrTransition) == TYPES.b;
+ var transitionDuration = 250;
+ var isRTLisHorizontal = _isRTL && isHorizontal;
+ var scrollbarVars = getScrollbarVars(isHorizontal);
+ var scrollbarVarsInfo = scrollbarVars._info;
+ var strTranslateBrace = 'translate(';
+ var strTransform = VENDORS._cssProperty('transform');
+ var strTransition = VENDORS._cssProperty('transition');
+ var nativeScroll = isHorizontal ? _viewportElement[_strScrollLeft]() : _viewportElement[_strScrollTop]();
+ var currentScroll = scrollOrTransition === undefined || transition ? nativeScroll : scrollOrTransition;
+
+ //measure the handle length to respect min & max length
+ var handleLength = scrollbarVarsInfo._handleLength;
+ var trackLength = scrollbarVars._track[0]['offset' + scrollbarVars._Width_Height];
+ var handleTrackDiff = trackLength - handleLength;
+ var handleCSS = {};
+ var transformOffset;
+ var translateValue;
+
+ //DONT use the variable '_contentScrollSizeCache[scrollbarVars._w_h]' instead of '_viewportElement[0]['scroll' + scrollbarVars._Width_Height]'
+ // because its a bit behind during the small delay when content size updates
+ //(delay = mutationObserverContentLag, if its 0 then this var could be used)
+ var maxScroll = (_viewportElementNative[_strScroll + scrollbarVars._Width_Height] - _viewportElementNative['client' + scrollbarVars._Width_Height]) * (_rtlScrollBehavior.n && isRTLisHorizontal ? -1 : 1); //* -1 if rtl scroll max is negative
+ var getScrollRatio = function (base) {
+ return isNaN(base / maxScroll) ? 0 : MATH.max(0, MATH.min(1, base / maxScroll));
+ };
+ var getHandleOffset = function (scrollRatio) {
+ var offset = handleTrackDiff * scrollRatio;
+ offset = isNaN(offset) ? 0 : offset;
+ offset = (isRTLisHorizontal && !_rtlScrollBehavior.i) ? (trackLength - handleLength - offset) : offset;
+ offset = MATH.max(0, offset);
+ return offset;
+ };
+ var scrollRatio = getScrollRatio(nativeScroll);
+ var unsnappedScrollRatio = getScrollRatio(currentScroll);
+ var handleOffset = getHandleOffset(unsnappedScrollRatio);
+ var snappedHandleOffset = getHandleOffset(scrollRatio);
+
+ scrollbarVarsInfo._maxScroll = maxScroll;
+ scrollbarVarsInfo._currentScroll = nativeScroll;
+ scrollbarVarsInfo._currentScrollRatio = scrollRatio;
+
+ if (_supportTransform) {
+ transformOffset = isRTLisHorizontal ? -(trackLength - handleLength - handleOffset) : handleOffset; //in px
+ //transformOffset = (transformOffset / trackLength * 100) * (trackLength / handleLength); //in %
+ translateValue = isHorizontal ? strTranslateBrace + transformOffset + 'px, 0)' : strTranslateBrace + '0, ' + transformOffset + 'px)';
+
+ handleCSS[strTransform] = translateValue;
+
+ //apply or clear up transition
+ if (_supportTransition)
+ handleCSS[strTransition] = transition && MATH.abs(handleOffset - scrollbarVarsInfo._handleOffset) > 1 ? getCSSTransitionString(scrollbarVars._handle) + ', ' + (strTransform + _strSpace + transitionDuration + 'ms') : _strEmpty;
+ }
+ else
+ handleCSS[scrollbarVars._left_top] = handleOffset;
+
+
+ //only apply css if offset has changed and overflow exists.
+ if (!nativeOverlayScrollbarsAreActive()) {
+ scrollbarVars._handle.css(handleCSS);
+
+ //clear up transition
+ if (_supportTransform && _supportTransition && transition) {
+ scrollbarVars._handle.one(_strTransitionEndEvent, function () {
+ if (!_destroyed)
+ scrollbarVars._handle.css(strTransition, _strEmpty);
+ });
+ }
+ }
+
+ scrollbarVarsInfo._handleOffset = handleOffset;
+ scrollbarVarsInfo._snappedHandleOffset = snappedHandleOffset;
+ scrollbarVarsInfo._trackLength = trackLength;
+ }
+
+ /**
+ * Refreshes the interactivity of the given scrollbar element.
+ * @param isTrack True if the track element is the target, false if the handle element is the target.
+ * @param value True for interactivity false for no interactivity.
+ */
+ function refreshScrollbarsInteractive(isTrack, value) {
+ var action = value ? 'removeClass' : 'addClass';
+ var element1 = isTrack ? _scrollbarHorizontalTrackElement : _scrollbarHorizontalHandleElement;
+ var element2 = isTrack ? _scrollbarVerticalTrackElement : _scrollbarVerticalHandleElement;
+ var className = isTrack ? _classNameScrollbarTrackOff : _classNameScrollbarHandleOff;
+
+ element1[action](className);
+ element2[action](className);
+ }
+
+ /**
+ * Returns a object which is used for fast access for specific variables.
+ * @param isHorizontal True if the horizontal scrollbar vars shall be accessed, false if the vertical scrollbar vars shall be accessed.
+ * @returns {{wh: string, WH: string, lt: string, _wh: string, _lt: string, t: *, h: *, c: {}, s: *}}
+ */
+ function getScrollbarVars(isHorizontal) {
+ return {
+ _width_height: isHorizontal ? _strWidth : _strHeight,
+ _Width_Height: isHorizontal ? 'Width' : 'Height',
+ _left_top: isHorizontal ? _strLeft : _strTop,
+ _Left_Top: isHorizontal ? 'Left' : 'Top',
+ _x_y: isHorizontal ? _strX : _strY,
+ _X_Y: isHorizontal ? 'X' : 'Y',
+ _w_h: isHorizontal ? 'w' : 'h',
+ _l_t: isHorizontal ? 'l' : 't',
+ _track: isHorizontal ? _scrollbarHorizontalTrackElement : _scrollbarVerticalTrackElement,
+ _handle: isHorizontal ? _scrollbarHorizontalHandleElement : _scrollbarVerticalHandleElement,
+ _scrollbar: isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement,
+ _info: isHorizontal ? _scrollHorizontalInfo : _scrollVerticalInfo
+ };
+ }
+
+
+ //==== Scrollbar Corner ====//
+
+ /**
+ * Builds or destroys the scrollbar corner DOM element.
+ * @param destroy Indicates whether the DOM shall be build or destroyed.
+ */
+ function setupScrollbarCornerDOM(destroy) {
+ _scrollbarCornerElement = _scrollbarCornerElement || selectOrGenerateDivByClass(_classNameScrollbarCorner, true);
+
+ if (!destroy) {
+ if (!_domExists) {
+ _hostElement.append(_scrollbarCornerElement);
+ }
+ }
+ else {
+ if (_domExists && _initialized) {
+ removeClass(_scrollbarCornerElement.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
+ }
+ else {
+ remove(_scrollbarCornerElement);
+ }
+ }
+ }
+
+ /**
+ * Initializes all scrollbar corner interactivity events.
+ */
+ function setupScrollbarCornerEvents() {
+ var insideIFrame = _windowElementNative.top !== _windowElementNative;
+ var mouseDownPosition = {};
+ var mouseDownSize = {};
+ var mouseDownInvertedScale = {};
+ var reconnectMutationObserver;
+
+ function documentDragMove(event) {
+ if (onMouseTouchDownContinue(event)) {
+ var pageOffset = getCoordinates(event);
+ var hostElementCSS = {};
+ if (_resizeHorizontal || _resizeBoth)
+ hostElementCSS[_strWidth] = (mouseDownSize.w + (pageOffset.x - mouseDownPosition.x) * mouseDownInvertedScale.x);
+ if (_resizeVertical || _resizeBoth)
+ hostElementCSS[_strHeight] = (mouseDownSize.h + (pageOffset.y - mouseDownPosition.y) * mouseDownInvertedScale.y);
+ _hostElement.css(hostElementCSS);
+ COMPATIBILITY.stpP(event);
+ }
+ else {
+ documentMouseTouchUp(event);
+ }
+ }
+ function documentMouseTouchUp(event) {
+ var eventIsTrusted = event !== undefined;
+
+ setupResponsiveEventListener(_documentElement,
+ [_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],
+ [documentOnSelectStart, documentDragMove, documentMouseTouchUp],
+ true);
+
+ removeClass(_bodyElement, _classNameDragging);
+ if (_scrollbarCornerElement.releaseCapture)
+ _scrollbarCornerElement.releaseCapture();
+
+ if (eventIsTrusted) {
+ if (reconnectMutationObserver)
+ connectMutationObservers();
+ _base.update(_strAuto);
+ }
+ reconnectMutationObserver = false;
+ }
+ function onMouseTouchDownContinue(event) {
+ var originalEvent = event.originalEvent || event;
+ var isTouchEvent = originalEvent.touches !== undefined;
+ return _sleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
+ }
+ function getCoordinates(event) {
+ return _msieVersion && insideIFrame ? { x: event.screenX, y: event.screenY } : COMPATIBILITY.page(event);
+ }
+
+ addDestroyEventListener(_scrollbarCornerElement, _strMouseTouchDownEvent, function (event) {
+ if (onMouseTouchDownContinue(event) && !_resizeNone) {
+ if (_mutationObserversConnected) {
+ reconnectMutationObserver = true;
+ disconnectMutationObservers();
+ }
+
+ mouseDownPosition = getCoordinates(event);
+
+ mouseDownSize.w = _hostElementNative[LEXICON.oW] - (!_isBorderBox ? _paddingX : 0);
+ mouseDownSize.h = _hostElementNative[LEXICON.oH] - (!_isBorderBox ? _paddingY : 0);
+ mouseDownInvertedScale = getHostElementInvertedScale();
+
+ setupResponsiveEventListener(_documentElement,
+ [_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],
+ [documentOnSelectStart, documentDragMove, documentMouseTouchUp]);
+
+ addClass(_bodyElement, _classNameDragging);
+ if (_scrollbarCornerElement.setCapture)
+ _scrollbarCornerElement.setCapture();
+
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ }
+ });
+ }
+
+
+ //==== Utils ====//
+
+ /**
+ * Calls the callback with the given name. The Context of this callback is always _base (this).
+ * @param name The name of the target which shall be called.
+ * @param args The args with which the callback shall be called.
+ */
+ function dispatchCallback(name, args) {
+ if (_initialized) {
+ var callback = _currentPreparedOptions.callbacks[name];
+ var extensionOnName = name;
+ var ext;
+
+ if (extensionOnName.substr(0, 2) === 'on')
+ extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3);
+
+ if (type(callback) == TYPES.f)
+ callback.call(_base, args);
+
+ each(_extensions, function () {
+ ext = this;
+ if (type(ext.on) == TYPES.f)
+ ext.on(extensionOnName, args);
+ });
+ }
+ else if (!_destroyed)
+ _callbacksInitQeueue.push({ n: name, a: args });
+ }
+
+ /**
+ * Sets the "top, right, bottom, left" properties, with a given prefix, of the given css object.
+ * @param targetCSSObject The css object to which the values shall be applied.
+ * @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
+ * @param values A array of values which shall be applied to the "top, right, bottom, left" -properties. The array order is [top, right, bottom, left].
+ * If this argument is undefined the value '' (empty string) will be applied to all properties.
+ */
+ function setTopRightBottomLeft(targetCSSObject, prefix, values) {
+ if (values === undefined)
+ values = [_strEmpty, _strEmpty, _strEmpty, _strEmpty];
+
+ targetCSSObject[prefix + _strTop] = values[0];
+ targetCSSObject[prefix + _strRight] = values[1];
+ targetCSSObject[prefix + _strBottom] = values[2];
+ targetCSSObject[prefix + _strLeft] = values[3];
+ }
+
+ /**
+ * Returns the computed CSS transition string from the given element.
+ * @param element The element from which the transition string shall be returned.
+ * @returns {string} The CSS transition string from the given element.
+ */
+ function getCSSTransitionString(element) {
+ var transitionStr = VENDORS._cssProperty('transition');
+ var assembledValue = element.css(transitionStr);
+ if (assembledValue)
+ return assembledValue;
+ var regExpString = '\\s*(' + '([^,(]+(\\(.+?\\))?)+' + ')[\\s,]*';
+ var regExpMain = new RegExp(regExpString);
+ var regExpValidate = new RegExp('^(' + regExpString + ')+$');
+ var properties = 'property duration timing-function delay'.split(' ');
+ var result = [];
+ var strResult;
+ var valueArray;
+ var i = 0;
+ var j;
+ var splitCssStyleByComma = function (str) {
+ strResult = [];
+ if (!str.match(regExpValidate))
+ return str;
+ while (str.match(regExpMain)) {
+ strResult.push(RegExp.$1);
+ str = str.replace(regExpMain, _strEmpty);
+ }
+
+ return strResult;
+ };
+ for (; i < properties[LEXICON.l]; i++) {
+ valueArray = splitCssStyleByComma(element.css(transitionStr + '-' + properties[i]));
+ for (j = 0; j < valueArray[LEXICON.l]; j++)
+ result[j] = (result[j] ? result[j] + _strSpace : _strEmpty) + valueArray[j];
+ }
+ return result.join(', ');
+ }
+
+ /**
+ * Calculates the host-elements inverted scale. (invertedScale = 1 / scale)
+ * @returns {{x: number, y: number}} The scale of the host-element.
+ */
+ function getHostElementInvertedScale() {
+ var rect = _paddingElementNative[LEXICON.bCR]();
+ return {
+ x: _supportTransform ? 1 / (MATH.round(rect.width) / _paddingElementNative[LEXICON.oW]) || 1 : 1,
+ y: _supportTransform ? 1 / (MATH.round(rect.height) / _paddingElementNative[LEXICON.oH]) || 1 : 1
+ };
+ }
+
+ /**
+ * Checks whether the given object is a HTMLElement.
+ * @param o The object which shall be checked.
+ * @returns {boolean} True the given object is a HTMLElement, false otherwise.
+ */
+ function isHTMLElement(o) {
+ var strOwnerDocument = 'ownerDocument';
+ var strHTMLElement = 'HTMLElement';
+ var wnd = o && o[strOwnerDocument] ? (o[strOwnerDocument].parentWindow || window) : window;
+ return (
+ typeof wnd[strHTMLElement] == TYPES.o ? o instanceof wnd[strHTMLElement] : //DOM2
+ o && typeof o == TYPES.o && o !== null && o.nodeType === 1 && typeof o.nodeName == TYPES.s
+ );
+ }
+
+ /**
+ * Compares 2 arrays and returns the differences between them as a array.
+ * @param a1 The first array which shall be compared.
+ * @param a2 The second array which shall be compared.
+ * @returns {Array} The differences between the two arrays.
+ */
+ function getArrayDifferences(a1, a2) {
+ var a = [];
+ var diff = [];
+ var i;
+ var k;
+ for (i = 0; i < a1.length; i++)
+ a[a1[i]] = true;
+ for (i = 0; i < a2.length; i++) {
+ if (a[a2[i]])
+ delete a[a2[i]];
+ else
+ a[a2[i]] = true;
+ }
+ for (k in a)
+ diff.push(k);
+ return diff;
+ }
+
+ /**
+ * Returns Zero or the number to which the value can be parsed.
+ * @param value The value which shall be parsed.
+ * @param toFloat Indicates whether the number shall be parsed to a float.
+ */
+ function parseToZeroOrNumber(value, toFloat) {
+ var num = toFloat ? parseFloat(value) : parseInt(value, 10);
+ return isNaN(num) ? 0 : num;
+ }
+
+ /**
+ * Gets several information of the textarea and returns them as a object or undefined if the browser doesn't support it.
+ * @returns {{cursorRow: Number, cursorCol, rows: Number, cols: number, wRow: number, pos: number, max : number}} or undefined if not supported.
+ */
+ function getTextareaInfo() {
+ //read needed values
+ var textareaCursorPosition = _targetElementNative.selectionStart;
+ if (textareaCursorPosition === undefined)
+ return;
+
+ var textareaValue = _targetElement.val();
+ var textareaLength = textareaValue[LEXICON.l];
+ var textareaRowSplit = textareaValue.split('\n');
+ var textareaLastRow = textareaRowSplit[LEXICON.l];
+ var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split('\n');
+ var widestRow = 0;
+ var textareaLastCol = 0;
+ var cursorRow = textareaCurrentCursorRowSplit[LEXICON.l];
+ var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[LEXICON.l] - 1][LEXICON.l];
+ var rowCols;
+ var i;
+
+ //get widest Row and the last column of the textarea
+ for (i = 0; i < textareaRowSplit[LEXICON.l]; i++) {
+ rowCols = textareaRowSplit[i][LEXICON.l];
+ if (rowCols > textareaLastCol) {
+ widestRow = i + 1;
+ textareaLastCol = rowCols;
+ }
+ }
+
+ return {
+ _cursorRow: cursorRow, //cursorRow
+ _cursorColumn: cursorCol, //cursorCol
+ _rows: textareaLastRow, //rows
+ _columns: textareaLastCol, //cols
+ _widestRow: widestRow, //wRow
+ _cursorPosition: textareaCursorPosition, //pos
+ _cursorMax: textareaLength //max
+ };
+ }
+
+ /**
+ * Determines whether native overlay scrollbars are active.
+ * @returns {boolean} True if native overlay scrollbars are active, false otherwise.
+ */
+ function nativeOverlayScrollbarsAreActive() {
+ return (_ignoreOverlayScrollbarHidingCache && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y));
+ }
+
+ /**
+ * Gets the element which is used to measure the content size.
+ * @returns {*} TextareaCover if target element is textarea else the ContentElement.
+ */
+ function getContentMeasureElement() {
+ return _isTextarea ? _textareaCoverElement[0] : _contentElementNative;
+ }
+
+ /**
+ * Generates a string which represents a HTML div with the given classes or attributes.
+ * @param classesOrAttrs The class of the div as string or a object which represents the attributes of the div. (The class attribute can also be written as "className".)
+ * @param content The content of the div as string.
+ * @returns {string} The concated string which represents a HTML div and its content.
+ */
+ function generateDiv(classesOrAttrs, content) {
+ return '
' +
+ (content || _strEmpty) +
+ '
';
+ }
+
+ /**
+ * Selects or generates a div with the given class attribute.
+ * @param className The class names (divided by spaces) of the div which shall be selected or generated.
+ * @param selectParentOrOnlyChildren The parent element from which of the element shall be selected. (if undefined or boolean its hostElement)
+ * If its a boolean it decides whether only the children of the host element shall be selected.
+ * @returns {*} The generated or selected element.
+ */
+ function selectOrGenerateDivByClass(className, selectParentOrOnlyChildren) {
+ var onlyChildren = type(selectParentOrOnlyChildren) == TYPES.b;
+ var selectParent = onlyChildren ? _hostElement : (selectParentOrOnlyChildren || _hostElement);
+
+ return (_domExists && !selectParent[LEXICON.l])
+ ? null
+ : _domExists
+ ? selectParent[onlyChildren ? 'children' : 'find'](_strDot + className.replace(/\s/g, _strDot)).eq(0)
+ : FRAMEWORK(generateDiv(className))
+ }
+
+ /**
+ * Gets the value of the given property from the given object.
+ * @param obj The object from which the property value shall be got.
+ * @param path The property of which the value shall be got.
+ * @returns {*} Returns the value of the searched property or undefined of the property wasn't found.
+ */
+ function getObjectPropVal(obj, path) {
+ var splits = path.split(_strDot);
+ var i = 0;
+ var val;
+ for (; i < splits.length; i++) {
+ if (!obj[LEXICON.hOP](splits[i]))
+ return;
+ val = obj[splits[i]];
+ if (i < splits.length && type(val) == TYPES.o)
+ obj = val;
+ }
+ return val;
+ }
+
+ /**
+ * Sets the value of the given property from the given object.
+ * @param obj The object from which the property value shall be set.
+ * @param path The property of which the value shall be set.
+ * @param val The value of the property which shall be set.
+ */
+ function setObjectPropVal(obj, path, val) {
+ var splits = path.split(_strDot);
+ var splitsLength = splits.length;
+ var i = 0;
+ var extendObj = {};
+ var extendObjRoot = extendObj;
+ for (; i < splitsLength; i++)
+ extendObj = extendObj[splits[i]] = i + 1 < splitsLength ? {} : val;
+ FRAMEWORK.extend(obj, extendObjRoot, true);
+ }
+
+
+ //==== Utils Cache ====//
+
+ /**
+ * Compares two values or objects and returns true if they aren't equal.
+ * @param current The first value or object which shall be compared.
+ * @param cache The second value or object which shall be compared.
+ * @param force If true the returned value is always true.
+ * @returns {boolean} True if both values or objects aren't equal or force is true, false otherwise.
+ */
+ function checkCache(current, cache, force) {
+ if (force)
+ return force;
+ if (type(current) == TYPES.o && type(cache) == TYPES.o) {
+ for (var prop in current) {
+ if (prop !== 'c') {
+ if (current[LEXICON.hOP](prop) && cache[LEXICON.hOP](prop)) {
+ if (checkCache(current[prop], cache[prop]))
+ return true;
+ }
+ else {
+ return true;
+ }
+ }
+ }
+ }
+ else {
+ return current !== cache;
+ }
+ return false;
+ }
+
+
+ //==== Shortcuts ====//
+
+ /**
+ * jQuery extend method shortcut with a appended "true" as first argument.
+ */
+ function extendDeep() {
+ return FRAMEWORK.extend.apply(this, [true].concat([].slice.call(arguments)));
+ }
+
+ /**
+ * jQuery addClass method shortcut.
+ */
+ function addClass(el, classes) {
+ return _frameworkProto.addClass.call(el, classes);
+ }
+
+ /**
+ * jQuery removeClass method shortcut.
+ */
+ function removeClass(el, classes) {
+ return _frameworkProto.removeClass.call(el, classes);
+ }
+
+ /**
+ * jQuery remove method shortcut.
+ */
+ function remove(el) {
+ return _frameworkProto.remove.call(el);
+ }
+
+ /**
+ * Finds the first child element with the given selector of the given element.
+ * @param el The root element from which the selector shall be valid.
+ * @param selector The selector of the searched element.
+ * @returns {*} The first element which is a child of the given element and matches the givens selector.
+ */
+ function findFirst(el, selector) {
+ return _frameworkProto.find.call(el, selector).eq(0);
+ }
+
+
+ //==== API ====//
+
+ /**
+ * Puts the instance to sleep. It wont respond to any changes in the DOM and won't update. Scrollbar Interactivity is also disabled as well as the resize handle.
+ * This behavior can be reset by calling the update method.
+ */
+ _base.sleep = function () {
+ _sleeping = true;
+ };
+
+ /**
+ * Updates the plugin and DOM to the current options.
+ * This method should only be called if a update is 100% required.
+ * @param force True if every property shall be updated and the cache shall be ignored.
+ * !INTERNAL USAGE! : force can be a string "auto", "sync" or "zoom" too
+ * if "auto" then before a real update the content size and host element attributes gets checked, and if they changed only then the update method will be called.
+ * if "sync" then the async update process (MutationObserver or UpdateLoop) gets synchronized and a corresponding update takes place if one was needed due to pending changes.
+ * if "zoom" then a update takes place where it's assumed that content and host size changed
+ * @returns {boolean|undefined}
+ * If force is "sync" then a boolean is returned which indicates whether a update was needed due to pending changes.
+ * If force is "auto" then a boolean is returned whether a update was needed due to attribute or size changes.
+ * undefined otherwise.
+ */
+ _base.update = function (force) {
+ if (_destroyed)
+ return;
+
+ var attrsChanged;
+ var contentSizeC;
+ var isString = type(force) == TYPES.s;
+ var imgElementSelector = 'img';
+ var imgElementLoadEvent = 'load';
+ var doUpdateAuto;
+ var mutHost;
+ var mutContent;
+
+ if (isString) {
+ if (force === _strAuto) {
+ attrsChanged = meaningfulAttrsChanged();
+ contentSizeC = updateAutoContentSizeChanged();
+ doUpdateAuto = attrsChanged || contentSizeC;
+ if (doUpdateAuto) {
+ update({
+ _contentSizeChanged: contentSizeC,
+ _changedOptions: _initialized ? undefined : _currentPreparedOptions
+ });
+ }
+ }
+ else if (force === _strSync) {
+ if (_mutationObserversConnected) {
+ mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords());
+ mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords());
+ }
+ else {
+ mutHost = _base.update(_strAuto);
+ }
+ }
+ else if (force === 'zoom') {
+ update({
+ _hostSizeChanged: true,
+ _contentSizeChanged: true
+ });
+ }
+ }
+ else {
+ force = _sleeping || force;
+ _sleeping = false;
+ if (!_base.update(_strSync) || force)
+ update({ _force: force });
+ }
+ if (!_isTextarea) {
+ _contentElement.find(imgElementSelector).each(function (i, el) {
+ var index = COMPATIBILITY.inA(el, _imgs);
+ if (index === -1)
+ FRAMEWORK(el).off(imgElementLoadEvent, imgOnLoad).on(imgElementLoadEvent, imgOnLoad);
+ });
+ }
+ return doUpdateAuto || mutHost || mutContent;
+ };
+
+ /**
+ Gets or sets the current options. The update method will be called automatically if new options were set.
+ * @param newOptions If new options are given, then the new options will be set, if new options aren't given (undefined or a not a plain object) then the current options will be returned.
+ * @param value If new options is a property path string, then this value will be used to set the option to which the property path string leads.
+ * @returns {*}
+ */
+ _base.options = function (newOptions, value) {
+ var option = {};
+ var changedOps;
+
+ //return current options if newOptions are undefined or empty
+ if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) {
+ if (type(newOptions) == TYPES.s) {
+ if (arguments.length > 1) {
+ setObjectPropVal(option, newOptions, value);
+ changedOps = setOptions(option);
+ }
+ else
+ return getObjectPropVal(_currentOptions, newOptions);
+ }
+ else
+ return _currentOptions;
+ }
+ else {
+ changedOps = setOptions(newOptions);
+ }
+
+ if (!FRAMEWORK.isEmptyObject(changedOps)) {
+ update({ _changedOptions: changedOps });
+ }
+ };
+
+ /**
+ * Restore the DOM, disconnects all observers, remove all resize observers and put the instance to sleep.
+ */
+ _base.destroy = function () {
+ if (_destroyed)
+ return;
+
+ //remove this instance from auto update loop
+ autoUpdateLoop.remove(_base);
+
+ //disconnect all mutation observers
+ disconnectMutationObservers();
+
+ //remove all resize observers
+ setupResizeObserver(_sizeObserverElement);
+ setupResizeObserver(_sizeAutoObserverElement);
+
+ //remove all extensions
+ for (var extName in _extensions)
+ _base.removeExt(extName);
+
+ //remove all 'destroy' events
+ while (_destroyEvents[LEXICON.l] > 0)
+ _destroyEvents.pop()();
+
+ //remove all events from host element
+ setupHostMouseTouchEvents(true);
+
+ //remove all helper / detection elements
+ if (_contentGlueElement)
+ remove(_contentGlueElement);
+ if (_contentArrangeElement)
+ remove(_contentArrangeElement);
+ if (_sizeAutoObserverAdded)
+ remove(_sizeAutoObserverElement);
+
+ //remove all generated DOM
+ setupScrollbarsDOM(true);
+ setupScrollbarCornerDOM(true);
+ setupStructureDOM(true);
+
+ //remove all generated image load events
+ for (var i = 0; i < _imgs[LEXICON.l]; i++)
+ FRAMEWORK(_imgs[i]).off('load', imgOnLoad);
+ _imgs = undefined;
+
+ _destroyed = true;
+ _sleeping = true;
+
+ //remove this instance from the instances list
+ INSTANCES(pluginTargetElement, 0);
+ dispatchCallback('onDestroyed');
+
+ //remove all properties and methods
+ //for (var property in _base)
+ // delete _base[property];
+ //_base = undefined;
+ };
+
+ /**
+ * Scrolls to a given position or element.
+ * @param coordinates
+ * 1. Can be "coordinates" which looks like:
+ * { x : ?, y : ? } OR Object with x and y properties
+ * { left : ?, top : ? } OR Object with left and top properties
+ * { l : ?, t : ? } OR Object with l and t properties
+ * [ ?, ? ] OR Array where the first two element are the coordinates (first is x, second is y)
+ * ? A single value which stays for both axis
+ * A value can be a number, a string or a calculation.
+ *
+ * Operators:
+ * [NONE] The current scroll will be overwritten by the value.
+ * '+=' The value will be added to the current scroll offset
+ * '-=' The value will be subtracted from the current scroll offset
+ * '*=' The current scroll wil be multiplicated by the value.
+ * '/=' The current scroll wil be divided by the value.
+ *
+ * Units:
+ * [NONE] The value is the final scroll amount. final = (value * 1)
+ * 'px' Same as none
+ * '%' The value is dependent on the current scroll value. final = ((currentScrollValue / 100) * value)
+ * 'vw' The value is multiplicated by the viewport width. final = (value * viewportWidth)
+ * 'vh' The value is multiplicated by the viewport height. final = (value * viewportHeight)
+ *
+ * example final values:
+ * 200, '200px', '50%', '1vw', '1vh', '+=200', '/=1vw', '*=2px', '-=5vh', '+=33%', '+= 50% - 2px', '-= 1vw - 50%'
+ *
+ * 2. Can be a HTML or jQuery element:
+ * The final scroll offset is the offset (without margin) of the given HTML / jQuery element.
+ *
+ * 3. Can be a object with a HTML or jQuery element with additional settings:
+ * {
+ * el : [HTMLElement, jQuery element], MUST be specified, else this object isn't valid.
+ * scroll : [string, array, object], Default value is 'always'.
+ * block : [string, array, object], Default value is 'begin'.
+ * margin : [number, boolean, array, object] Default value is false.
+ * }
+ *
+ * Possible scroll settings are:
+ * 'always' Scrolls always.
+ * 'ifneeded' Scrolls only if the element isnt fully in view.
+ * 'never' Scrolls never.
+ *
+ * Possible block settings are:
+ * 'begin' Both axis shall be docked to the "begin" edge. - The element will be docked to the top and left edge of the viewport.
+ * 'end' Both axis shall be docked to the "end" edge. - The element will be docked to the bottom and right edge of the viewport. (If direction is RTL to the bottom and left edge.)
+ * 'center' Both axis shall be docked to "center". - The element will be centered in the viewport.
+ * 'nearest' The element will be docked to the nearest edge(s).
+ *
+ * Possible margin settings are: -- The actual margin of the element wont be affect, this option affects only the final scroll offset.
+ * [BOOLEAN] If true the css margin of the element will be used, if false no margin will be used.
+ * [NUMBER] The margin will be used for all edges.
+ *
+ * @param duration The duration of the scroll animation, OR a jQuery animation configuration object.
+ * @param easing The animation easing.
+ * @param complete The animation complete callback.
+ * @returns {{
+ * position: {x: number, y: number},
+ * ratio: {x: number, y: number},
+ * max: {x: number, y: number},
+ * handleOffset: {x: number, y: number},
+ * handleLength: {x: number, y: number},
+ * handleLengthRatio: {x: number, y: number}, t
+ * rackLength: {x: number, y: number},
+ * isRTL: boolean,
+ * isRTLNormalized: boolean
+ * }}
+ */
+ _base.scroll = function (coordinates, duration, easing, complete) {
+ if (arguments.length === 0 || coordinates === undefined) {
+ var infoX = _scrollHorizontalInfo;
+ var infoY = _scrollVerticalInfo;
+ var normalizeInvert = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.i;
+ var normalizeNegate = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.n;
+ var scrollX = infoX._currentScroll;
+ var scrollXRatio = infoX._currentScrollRatio;
+ var maxScrollX = infoX._maxScroll;
+ scrollXRatio = normalizeInvert ? 1 - scrollXRatio : scrollXRatio;
+ scrollX = normalizeInvert ? maxScrollX - scrollX : scrollX;
+ scrollX *= normalizeNegate ? -1 : 1;
+ maxScrollX *= normalizeNegate ? -1 : 1;
+
+ return {
+ position: {
+ x: scrollX,
+ y: infoY._currentScroll
+ },
+ ratio: {
+ x: scrollXRatio,
+ y: infoY._currentScrollRatio
+ },
+ max: {
+ x: maxScrollX,
+ y: infoY._maxScroll
+ },
+ handleOffset: {
+ x: infoX._handleOffset,
+ y: infoY._handleOffset
+ },
+ handleLength: {
+ x: infoX._handleLength,
+ y: infoY._handleLength
+ },
+ handleLengthRatio: {
+ x: infoX._handleLengthRatio,
+ y: infoY._handleLengthRatio
+ },
+ trackLength: {
+ x: infoX._trackLength,
+ y: infoY._trackLength
+ },
+ snappedHandleOffset: {
+ x: infoX._snappedHandleOffset,
+ y: infoY._snappedHandleOffset
+ },
+ isRTL: _isRTL,
+ isRTLNormalized: _normalizeRTLCache
+ };
+ }
+
+ _base.update(_strSync);
+
+ var normalizeRTL = _normalizeRTLCache;
+ var coordinatesXAxisProps = [_strX, _strLeft, 'l'];
+ var coordinatesYAxisProps = [_strY, _strTop, 't'];
+ var coordinatesOperators = ['+=', '-=', '*=', '/='];
+ var durationIsObject = type(duration) == TYPES.o;
+ var completeCallback = durationIsObject ? duration.complete : complete;
+ var i;
+ var finalScroll = {};
+ var specialEasing = {};
+ var doScrollLeft;
+ var doScrollTop;
+ var animationOptions;
+ var strEnd = 'end';
+ var strBegin = 'begin';
+ var strCenter = 'center';
+ var strNearest = 'nearest';
+ var strAlways = 'always';
+ var strNever = 'never';
+ var strIfNeeded = 'ifneeded';
+ var strLength = LEXICON.l;
+ var settingsAxis;
+ var settingsScroll;
+ var settingsBlock;
+ var settingsMargin;
+ var finalElement;
+ var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx'];
+ var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest];
+ var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded];
+ var coordinatesIsElementObj = coordinates[LEXICON.hOP]('el');
+ var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates;
+ var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false;
+ var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement);
+ var updateScrollbarInfos = function () {
+ if (doScrollLeft)
+ refreshScrollbarHandleOffset(true);
+ if (doScrollTop)
+ refreshScrollbarHandleOffset(false);
+ };
+ var proxyCompleteCallback = type(completeCallback) != TYPES.f ? undefined : function () {
+ updateScrollbarInfos();
+ completeCallback();
+ };
+ function checkSettingsStringValue(currValue, allowedValues) {
+ for (i = 0; i < allowedValues[strLength]; i++) {
+ if (currValue === allowedValues[i])
+ return true;
+ }
+ return false;
+ }
+ function getRawScroll(isX, coordinates) {
+ var coordinateProps = isX ? coordinatesXAxisProps : coordinatesYAxisProps;
+ coordinates = type(coordinates) == TYPES.s || type(coordinates) == TYPES.n ? [coordinates, coordinates] : coordinates;
+
+ if (type(coordinates) == TYPES.a)
+ return isX ? coordinates[0] : coordinates[1];
+ else if (type(coordinates) == TYPES.o) {
+ //decides RTL normalization "hack" with .n
+ //normalizeRTL = type(coordinates.n) == TYPES.b ? coordinates.n : normalizeRTL;
+ for (i = 0; i < coordinateProps[strLength]; i++)
+ if (coordinateProps[i] in coordinates)
+ return coordinates[coordinateProps[i]];
+ }
+ }
+ function getFinalScroll(isX, rawScroll) {
+ var isString = type(rawScroll) == TYPES.s;
+ var operator;
+ var amount;
+ var scrollInfo = isX ? _scrollHorizontalInfo : _scrollVerticalInfo;
+ var currScroll = scrollInfo._currentScroll;
+ var maxScroll = scrollInfo._maxScroll;
+ var mult = ' * ';
+ var finalValue;
+ var isRTLisX = _isRTL && isX;
+ var normalizeShortcuts = isRTLisX && _rtlScrollBehavior.n && !normalizeRTL;
+ var strReplace = 'replace';
+ var evalFunc = eval;
+ var possibleOperator;
+ if (isString) {
+ //check operator
+ if (rawScroll[strLength] > 2) {
+ possibleOperator = rawScroll.substr(0, 2);
+ if (inArray(possibleOperator, coordinatesOperators) > -1)
+ operator = possibleOperator;
+ }
+
+ //calculate units and shortcuts
+ rawScroll = operator ? rawScroll.substr(2) : rawScroll;
+ rawScroll = rawScroll
+ [strReplace](/min/g, 0) //'min' = 0%
+ [strReplace](//g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'>' = 100%
+ [strReplace](/px/g, _strEmpty)
+ [strReplace](/%/g, mult + (maxScroll * (isRTLisX && _rtlScrollBehavior.n ? -1 : 1) / 100.0))
+ [strReplace](/vw/g, mult + _viewportSize.w)
+ [strReplace](/vh/g, mult + _viewportSize.h);
+ amount = parseToZeroOrNumber(isNaN(rawScroll) ? parseToZeroOrNumber(evalFunc(rawScroll), true).toFixed() : rawScroll);
+ }
+ else {
+ amount = rawScroll;
+ }
+
+ if (amount !== undefined && !isNaN(amount) && type(amount) == TYPES.n) {
+ var normalizeIsRTLisX = normalizeRTL && isRTLisX;
+ var operatorCurrScroll = currScroll * (normalizeIsRTLisX && _rtlScrollBehavior.n ? -1 : 1);
+ var invert = normalizeIsRTLisX && _rtlScrollBehavior.i;
+ var negate = normalizeIsRTLisX && _rtlScrollBehavior.n;
+ operatorCurrScroll = invert ? (maxScroll - operatorCurrScroll) : operatorCurrScroll;
+ switch (operator) {
+ case '+=':
+ finalValue = operatorCurrScroll + amount;
+ break;
+ case '-=':
+ finalValue = operatorCurrScroll - amount;
+ break;
+ case '*=':
+ finalValue = operatorCurrScroll * amount;
+ break;
+ case '/=':
+ finalValue = operatorCurrScroll / amount;
+ break;
+ default:
+ finalValue = amount;
+ break;
+ }
+ finalValue = invert ? maxScroll - finalValue : finalValue;
+ finalValue *= negate ? -1 : 1;
+ finalValue = isRTLisX && _rtlScrollBehavior.n ? MATH.min(0, MATH.max(maxScroll, finalValue)) : MATH.max(0, MATH.min(maxScroll, finalValue));
+ }
+ return finalValue === currScroll ? undefined : finalValue;
+ }
+ function getPerAxisValue(value, valueInternalType, defaultValue, allowedValues) {
+ var resultDefault = [defaultValue, defaultValue];
+ var valueType = type(value);
+ var valueArrLength;
+ var valueArrItem;
+
+ //value can be [ string, or array of two strings ]
+ if (valueType == valueInternalType) {
+ value = [value, value];
+ }
+ else if (valueType == TYPES.a) {
+ valueArrLength = value[strLength];
+ if (valueArrLength > 2 || valueArrLength < 1)
+ value = resultDefault;
+ else {
+ if (valueArrLength === 1)
+ value[1] = defaultValue;
+ for (i = 0; i < valueArrLength; i++) {
+ valueArrItem = value[i];
+ if (type(valueArrItem) != valueInternalType || !checkSettingsStringValue(valueArrItem, allowedValues)) {
+ value = resultDefault;
+ break;
+ }
+ }
+ }
+ }
+ else if (valueType == TYPES.o)
+ value = [value[_strX] || defaultValue, value[_strY] || defaultValue];
+ else
+ value = resultDefault;
+ return { x: value[0], y: value[1] };
+ }
+ function generateMargin(marginTopRightBottomLeftArray) {
+ var result = [];
+ var currValue;
+ var currValueType;
+ var valueDirections = [_strTop, _strRight, _strBottom, _strLeft];
+ for (i = 0; i < marginTopRightBottomLeftArray[strLength]; i++) {
+ if (i === valueDirections[strLength])
+ break;
+ currValue = marginTopRightBottomLeftArray[i];
+ currValueType = type(currValue);
+ if (currValueType == TYPES.b)
+ result.push(currValue ? parseToZeroOrNumber(finalElement.css(_strMarginMinus + valueDirections[i])) : 0);
+ else
+ result.push(currValueType == TYPES.n ? currValue : 0);
+ }
+ return result;
+ }
+
+ if (possibleElementIsJQuery || possibleElementIsHTMLElement) {
+ //get settings
+ var margin = coordinatesIsElementObj ? coordinates.margin : 0;
+ var axis = coordinatesIsElementObj ? coordinates.axis : 0;
+ var scroll = coordinatesIsElementObj ? coordinates.scroll : 0;
+ var block = coordinatesIsElementObj ? coordinates.block : 0;
+ var marginDefault = [0, 0, 0, 0];
+ var marginType = type(margin);
+ var marginLength;
+ finalElement = possibleElementIsJQuery ? possibleElement : FRAMEWORK(possibleElement);
+
+ if (finalElement[strLength] > 0) {
+ //margin can be [ boolean, number, array of 2, array of 4, object ]
+ if (marginType == TYPES.n || marginType == TYPES.b)
+ margin = generateMargin([margin, margin, margin, margin]);
+ else if (marginType == TYPES.a) {
+ marginLength = margin[strLength];
+ if (marginLength === 2)
+ margin = generateMargin([margin[0], margin[1], margin[0], margin[1]]);
+ else if (marginLength >= 4)
+ margin = generateMargin(margin);
+ else
+ margin = marginDefault;
+ }
+ else if (marginType == TYPES.o)
+ margin = generateMargin([margin[_strTop], margin[_strRight], margin[_strBottom], margin[_strLeft]]);
+ else
+ margin = marginDefault;
+
+ //block = type(block) === TYPES.b ? block ? [ strNearest, strBegin ] : [ strNearest, strEnd ] : block;
+ settingsAxis = checkSettingsStringValue(axis, elementObjSettingsAxisValues) ? axis : 'xy';
+ settingsScroll = getPerAxisValue(scroll, TYPES.s, strAlways, elementObjSettingsScrollValues);
+ settingsBlock = getPerAxisValue(block, TYPES.s, strBegin, elementObjSettingsBlockValues);
+ settingsMargin = margin;
+
+ var viewportScroll = {
+ l: _scrollHorizontalInfo._currentScroll,
+ t: _scrollVerticalInfo._currentScroll
+ };
+ // use padding element instead of viewport element because padding element has never padding, margin or position applied.
+ var viewportOffset = _paddingElement.offset();
+
+ //get coordinates
+ var elementOffset = finalElement.offset();
+ var doNotScroll = {
+ x: settingsScroll.x == strNever || settingsAxis == _strY,
+ y: settingsScroll.y == strNever || settingsAxis == _strX
+ };
+ elementOffset[_strTop] -= settingsMargin[0];
+ elementOffset[_strLeft] -= settingsMargin[3];
+ var elementScrollCoordinates = {
+ x: MATH.round(elementOffset[_strLeft] - viewportOffset[_strLeft] + viewportScroll.l),
+ y: MATH.round(elementOffset[_strTop] - viewportOffset[_strTop] + viewportScroll.t)
+ };
+ if (_isRTL) {
+ if (!_rtlScrollBehavior.n && !_rtlScrollBehavior.i)
+ elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + viewportScroll.l);
+ if (_rtlScrollBehavior.n && normalizeRTL)
+ elementScrollCoordinates.x *= -1;
+ if (_rtlScrollBehavior.i && normalizeRTL)
+ elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + (_scrollHorizontalInfo._maxScroll - viewportScroll.l));
+ }
+
+ //measuring is required
+ if (settingsBlock.x != strBegin || settingsBlock.y != strBegin || settingsScroll.x == strIfNeeded || settingsScroll.y == strIfNeeded || _isRTL) {
+ var measuringElm = finalElement[0];
+ var rawElementSize = _supportTransform ? measuringElm[LEXICON.bCR]() : {
+ width: measuringElm[LEXICON.oW],
+ height: measuringElm[LEXICON.oH]
+ };
+ var elementSize = {
+ w: rawElementSize[_strWidth] + settingsMargin[3] + settingsMargin[1],
+ h: rawElementSize[_strHeight] + settingsMargin[0] + settingsMargin[2]
+ };
+ var finalizeBlock = function (isX) {
+ var vars = getScrollbarVars(isX);
+ var wh = vars._w_h;
+ var lt = vars._left_top;
+ var xy = vars._x_y;
+ var blockIsEnd = settingsBlock[xy] == (isX ? _isRTL ? strBegin : strEnd : strEnd);
+ var blockIsCenter = settingsBlock[xy] == strCenter;
+ var blockIsNearest = settingsBlock[xy] == strNearest;
+ var scrollNever = settingsScroll[xy] == strNever;
+ var scrollIfNeeded = settingsScroll[xy] == strIfNeeded;
+ var vpSize = _viewportSize[wh];
+ var vpOffset = viewportOffset[lt];
+ var elSize = elementSize[wh];
+ var elOffset = elementOffset[lt];
+ var divide = blockIsCenter ? 2 : 1;
+ var elementCenterOffset = elOffset + (elSize / 2);
+ var viewportCenterOffset = vpOffset + (vpSize / 2);
+ var isInView =
+ elSize <= vpSize
+ && elOffset >= vpOffset
+ && elOffset + elSize <= vpOffset + vpSize;
+
+ if (scrollNever)
+ doNotScroll[xy] = true;
+ else if (!doNotScroll[xy]) {
+ if (blockIsNearest || scrollIfNeeded) {
+ doNotScroll[xy] = scrollIfNeeded ? isInView : false;
+ blockIsEnd = elSize < vpSize ? elementCenterOffset > viewportCenterOffset : elementCenterOffset < viewportCenterOffset;
+ }
+ elementScrollCoordinates[xy] -= blockIsEnd || blockIsCenter ? ((vpSize / divide) - (elSize / divide)) * (isX && _isRTL && normalizeRTL ? -1 : 1) : 0;
+ }
+ };
+ finalizeBlock(true);
+ finalizeBlock(false);
+ }
+
+ if (doNotScroll.y)
+ delete elementScrollCoordinates.y;
+ if (doNotScroll.x)
+ delete elementScrollCoordinates.x;
+
+ coordinates = elementScrollCoordinates;
+ }
+ }
+
+ finalScroll[_strScrollLeft] = getFinalScroll(true, getRawScroll(true, coordinates));
+ finalScroll[_strScrollTop] = getFinalScroll(false, getRawScroll(false, coordinates));
+ doScrollLeft = finalScroll[_strScrollLeft] !== undefined;
+ doScrollTop = finalScroll[_strScrollTop] !== undefined;
+
+ if ((doScrollLeft || doScrollTop) && (duration > 0 || durationIsObject)) {
+ if (durationIsObject) {
+ duration.complete = proxyCompleteCallback;
+ _viewportElement.animate(finalScroll, duration);
+ }
+ else {
+ animationOptions = {
+ duration: duration,
+ complete: proxyCompleteCallback
+ };
+ if (type(easing) == TYPES.a || FRAMEWORK.isPlainObject(easing)) {
+ specialEasing[_strScrollLeft] = easing[0] || easing.x;
+ specialEasing[_strScrollTop] = easing[1] || easing.y;
+ animationOptions.specialEasing = specialEasing;
+ }
+ else {
+ animationOptions.easing = easing;
+ }
+ _viewportElement.animate(finalScroll, animationOptions);
+ }
+ }
+ else {
+ if (doScrollLeft)
+ _viewportElement[_strScrollLeft](finalScroll[_strScrollLeft]);
+ if (doScrollTop)
+ _viewportElement[_strScrollTop](finalScroll[_strScrollTop]);
+ updateScrollbarInfos();
+ }
+ };
+
+ /**
+ * Stops all scroll animations.
+ * @returns {*} The current OverlayScrollbars instance (for chaining).
+ */
+ _base.scrollStop = function (param1, param2, param3) {
+ _viewportElement.stop(param1, param2, param3);
+ return _base;
+ };
+
+ /**
+ * Returns all relevant elements.
+ * @param elementName The name of the element which shall be returned.
+ * @returns {{target: *, host: *, padding: *, viewport: *, content: *, scrollbarHorizontal: {scrollbar: *, track: *, handle: *}, scrollbarVertical: {scrollbar: *, track: *, handle: *}, scrollbarCorner: *} | *}
+ */
+ _base.getElements = function (elementName) {
+ var obj = {
+ target: _targetElementNative,
+ host: _hostElementNative,
+ padding: _paddingElementNative,
+ viewport: _viewportElementNative,
+ content: _contentElementNative,
+ scrollbarHorizontal: {
+ scrollbar: _scrollbarHorizontalElement[0],
+ track: _scrollbarHorizontalTrackElement[0],
+ handle: _scrollbarHorizontalHandleElement[0]
+ },
+ scrollbarVertical: {
+ scrollbar: _scrollbarVerticalElement[0],
+ track: _scrollbarVerticalTrackElement[0],
+ handle: _scrollbarVerticalHandleElement[0]
+ },
+ scrollbarCorner: _scrollbarCornerElement[0]
+ };
+ return type(elementName) == TYPES.s ? getObjectPropVal(obj, elementName) : obj;
+ };
+
+ /**
+ * Returns a object which describes the current state of this instance.
+ * @param stateProperty A specific property from the state object which shall be returned.
+ * @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *}
+ */
+ _base.getState = function (stateProperty) {
+ function prepare(obj) {
+ if (!FRAMEWORK.isPlainObject(obj))
+ return obj;
+ var extended = extendDeep({}, obj);
+ var changePropertyName = function (from, to) {
+ if (extended[LEXICON.hOP](from)) {
+ extended[to] = extended[from];
+ delete extended[from];
+ }
+ };
+ changePropertyName('w', _strWidth); //change w to width
+ changePropertyName('h', _strHeight); //change h to height
+ delete extended.c; //delete c (the 'changed' prop)
+ return extended;
+ };
+ var obj = {
+ destroyed: !!prepare(_destroyed),
+ sleeping: !!prepare(_sleeping),
+ autoUpdate: prepare(!_mutationObserversConnected),
+ widthAuto: prepare(_widthAutoCache),
+ heightAuto: prepare(_heightAutoCache),
+ padding: prepare(_cssPaddingCache),
+ overflowAmount: prepare(_overflowAmountCache),
+ hideOverflow: prepare(_hideOverflowCache),
+ hasOverflow: prepare(_hasOverflowCache),
+ contentScrollSize: prepare(_contentScrollSizeCache),
+ viewportSize: prepare(_viewportSize),
+ hostSize: prepare(_hostSizeCache),
+ documentMixed: prepare(_documentMixed)
+ };
+ return type(stateProperty) == TYPES.s ? getObjectPropVal(obj, stateProperty) : obj;
+ };
+
+ /**
+ * Gets all or specific extension instance.
+ * @param extName The name of the extension from which the instance shall be got.
+ * @returns {{}} The instance of the extension with the given name or undefined if the instance couldn't be found.
+ */
+ _base.ext = function (extName) {
+ var result;
+ var privateMethods = _extensionsPrivateMethods.split(' ');
+ var i = 0;
+ if (type(extName) == TYPES.s) {
+ if (_extensions[LEXICON.hOP](extName)) {
+ result = extendDeep({}, _extensions[extName]);
+ for (; i < privateMethods.length; i++)
+ delete result[privateMethods[i]];
+ }
+ }
+ else {
+ result = {};
+ for (i in _extensions)
+ result[i] = extendDeep({}, _base.ext(i));
+ }
+ return result;
+ };
+
+ /**
+ * Adds a extension to this instance.
+ * @param extName The name of the extension which shall be added.
+ * @param extensionOptions The extension options which shall be used.
+ * @returns {{}} The instance of the added extension or undefined if the extension couldn't be added properly.
+ */
+ _base.addExt = function (extName, extensionOptions) {
+ var registeredExtensionObj = _plugin.extension(extName);
+ var instance;
+ var instanceAdded;
+ var instanceContract;
+ var contractResult;
+ var contractFulfilled = true;
+ if (registeredExtensionObj) {
+ if (!_extensions[LEXICON.hOP](extName)) {
+ instance = registeredExtensionObj.extensionFactory.call(_base,
+ extendDeep({}, registeredExtensionObj.defaultOptions),
+ FRAMEWORK,
+ COMPATIBILITY);
+
+ if (instance) {
+ instanceContract = instance.contract;
+ if (type(instanceContract) == TYPES.f) {
+ contractResult = instanceContract(window);
+ contractFulfilled = type(contractResult) == TYPES.b ? contractResult : contractFulfilled;
+ }
+ if (contractFulfilled) {
+ _extensions[extName] = instance;
+ instanceAdded = instance.added;
+ if (type(instanceAdded) == TYPES.f)
+ instanceAdded(extensionOptions);
+
+ return _base.ext(extName);
+ }
+ }
+ }
+ else
+ return _base.ext(extName);
+ }
+ else
+ console.warn("A extension with the name \"" + extName + "\" isn't registered.");
+ };
+
+ /**
+ * Removes a extension from this instance.
+ * @param extName The name of the extension which shall be removed.
+ * @returns {boolean} True if the extension was removed, false otherwise e.g. if the extension wasn't added before.
+ */
+ _base.removeExt = function (extName) {
+ var instance = _extensions[extName];
+ var instanceRemoved;
+ if (instance) {
+ delete _extensions[extName];
+
+ instanceRemoved = instance.removed;
+ if (type(instanceRemoved) == TYPES.f)
+ instanceRemoved();
+
+ return true;
+ }
+ return false;
+ };
+
+ /**
+ * Constructs the plugin.
+ * @param targetElement The element to which the plugin shall be applied.
+ * @param options The initial options of the plugin.
+ * @param extensions The extension(s) which shall be added right after the initialization.
+ * @returns {boolean} True if the plugin was successfully initialized, false otherwise.
+ */
+ function construct(targetElement, options, extensions) {
+ _defaultOptions = globals.defaultOptions;
+ _nativeScrollbarStyling = globals.nativeScrollbarStyling;
+ _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
+ _nativeScrollbarIsOverlaid = extendDeep({}, globals.nativeScrollbarIsOverlaid);
+ _overlayScrollbarDummySize = extendDeep({}, globals.overlayScrollbarDummySize);
+ _rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior);
+
+ //parse & set options but don't update
+ setOptions(extendDeep({}, _defaultOptions, options));
+
+ _cssCalc = globals.cssCalc;
+ _msieVersion = globals.msie;
+ _autoUpdateRecommended = globals.autoUpdateRecommended;
+ _supportTransition = globals.supportTransition;
+ _supportTransform = globals.supportTransform;
+ _supportPassiveEvents = globals.supportPassiveEvents;
+ _supportResizeObserver = globals.supportResizeObserver;
+ _supportMutationObserver = globals.supportMutationObserver;
+ _restrictedMeasuring = globals.restrictedMeasuring;
+ _documentElement = FRAMEWORK(targetElement.ownerDocument);
+ _documentElementNative = _documentElement[0];
+ _windowElement = FRAMEWORK(_documentElementNative.defaultView || _documentElementNative.parentWindow);
+ _windowElementNative = _windowElement[0];
+ _htmlElement = findFirst(_documentElement, 'html');
+ _bodyElement = findFirst(_htmlElement, 'body');
+ _targetElement = FRAMEWORK(targetElement);
+ _targetElementNative = _targetElement[0];
+ _isTextarea = _targetElement.is('textarea');
+ _isBody = _targetElement.is('body');
+ _documentMixed = _documentElementNative !== document;
+
+ /* On a div Element The if checks only whether:
+ * - the targetElement has the class "os-host"
+ * - the targetElement has a a child with the class "os-padding"
+ *
+ * If that's the case, its assumed the DOM has already the following structure:
+ * (The ".os-host" element is the targetElement)
+ *
+ *
+ *
+ * =====================================================================================
+ *
+ * On a Textarea Element The if checks only whether:
+ * - the targetElement has the class "os-textarea"
+ * - the targetElement is inside a element with the class "os-content"
+ *
+ * If that's the case, its assumed the DOM has already the following structure:
+ * (The ".os-textarea" (textarea) element is the targetElement)
+ *
+ *
+ */
+ _domExists = _isTextarea
+ ? _targetElement.hasClass(_classNameTextareaElement) && _targetElement.parent().hasClass(_classNameContentElement)
+ : _targetElement.hasClass(_classNameHostElement) && _targetElement.children(_strDot + _classNamePaddingElement)[LEXICON.l];
+
+ var initBodyScroll;
+ var bodyMouseTouchDownListener;
+
+ //check if the plugin hasn't to be initialized
+ if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) {
+ dispatchCallback('onInitializationWithdrawn');
+ if (_domExists) {
+ setupStructureDOM(true);
+ setupScrollbarsDOM(true);
+ setupScrollbarCornerDOM(true);
+ }
+
+ _destroyed = true;
+ _sleeping = true;
+
+ return _base;
+ }
+
+ if (_isBody) {
+ initBodyScroll = {};
+ initBodyScroll.l = MATH.max(_targetElement[_strScrollLeft](), _htmlElement[_strScrollLeft](), _windowElement[_strScrollLeft]());
+ initBodyScroll.t = MATH.max(_targetElement[_strScrollTop](), _htmlElement[_strScrollTop](), _windowElement[_strScrollTop]());
+
+ bodyMouseTouchDownListener = function () {
+ _viewportElement.removeAttr(LEXICON.ti);
+ setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, true, true);
+ }
+ }
+
+ //build OverlayScrollbars DOM
+ setupStructureDOM();
+ setupScrollbarsDOM();
+ setupScrollbarCornerDOM();
+
+ //create OverlayScrollbars events
+ setupStructureEvents();
+ setupScrollbarEvents(true);
+ setupScrollbarEvents(false);
+ setupScrollbarCornerEvents();
+
+ //create mutation observers
+ createMutationObservers();
+
+ //build resize observer for the host element
+ setupResizeObserver(_sizeObserverElement, hostOnResized);
+
+ if (_isBody) {
+ //apply the body scroll to handle it right in the update method
+ _viewportElement[_strScrollLeft](initBodyScroll.l)[_strScrollTop](initBodyScroll.t);
+
+ //set the focus on the viewport element so you dont have to click on the page to use keyboard keys (up / down / space) for scrolling
+ if (document.activeElement == targetElement && _viewportElementNative.focus) {
+ //set a tabindex to make the viewportElement focusable
+ _viewportElement.attr(LEXICON.ti, '-1');
+ _viewportElementNative.focus();
+
+ /* the tabindex has to be removed due to;
+ * If you set the tabindex attribute on an
, then its child content cannot be scrolled with the arrow keys unless you set tabindex on the content, too
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
+ */
+ setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, false, true);
+ }
+ }
+
+ //update for the first time & initialize cache
+ _base.update(_strAuto);
+
+ //the plugin is initialized now!
+ _initialized = true;
+ dispatchCallback('onInitialized');
+
+ //call all callbacks which would fire before the initialized was complete
+ each(_callbacksInitQeueue, function (index, value) { dispatchCallback(value.n, value.a); });
+ _callbacksInitQeueue = [];
+
+ //add extensions
+ if (type(extensions) == TYPES.s)
+ extensions = [extensions];
+ if (COMPATIBILITY.isA(extensions))
+ each(extensions, function (index, value) { _base.addExt(value); });
+ else if (FRAMEWORK.isPlainObject(extensions))
+ each(extensions, function (key, value) { _base.addExt(key, value); });
+
+ //add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions)
+ setTimeout(function () {
+ if (_supportTransition && !_destroyed)
+ addClass(_hostElement, _classNameHostTransition);
+ }, 333);
+
+ return _base;
+ }
+
+ if (_plugin.valid(construct(pluginTargetElement, options, extensions))) {
+ INSTANCES(pluginTargetElement, _base);
+ }
+
+ return _base;
+ }
+
+ /**
+ * Initializes a new OverlayScrollbarsInstance object or changes options if already initialized or returns the current instance.
+ * @param pluginTargetElements The elements to which the Plugin shall be initialized.
+ * @param options The custom options with which the plugin shall be initialized.
+ * @param extensions The extension(s) which shall be added right after initialization.
+ * @returns {*}
+ */
+ _plugin = window[PLUGINNAME] = function (pluginTargetElements, options, extensions) {
+ if (arguments[LEXICON.l] === 0)
+ return this;
+
+ var arr = [];
+ var optsIsPlainObj = FRAMEWORK.isPlainObject(options);
+ var inst;
+ var result;
+
+ //pluginTargetElements is null or undefined
+ if (!pluginTargetElements)
+ return optsIsPlainObj || !options ? result : arr;
+
+ /*
+ pluginTargetElements will be converted to:
+ 1. A jQueryElement Array
+ 2. A HTMLElement Array
+ 3. A Array with a single HTML Element
+ so pluginTargetElements is always a array.
+ */
+ pluginTargetElements = pluginTargetElements[LEXICON.l] != undefined ? pluginTargetElements : [pluginTargetElements[0] || pluginTargetElements];
+ initOverlayScrollbarsStatics();
+
+ if (pluginTargetElements[LEXICON.l] > 0) {
+ if (optsIsPlainObj) {
+ FRAMEWORK.each(pluginTargetElements, function (i, v) {
+ inst = v;
+ if (inst !== undefined)
+ arr.push(OverlayScrollbarsInstance(inst, options, extensions, _pluginsGlobals, _pluginsAutoUpdateLoop));
+ });
+ }
+ else {
+ FRAMEWORK.each(pluginTargetElements, function (i, v) {
+ inst = INSTANCES(v);
+ if ((options === '!' && _plugin.valid(inst)) || (COMPATIBILITY.type(options) == TYPES.f && options(v, inst)))
+ arr.push(inst);
+ else if (options === undefined)
+ arr.push(inst);
+ });
+ }
+ result = arr[LEXICON.l] === 1 ? arr[0] : arr;
+ }
+ return result;
+ };
+
+ /**
+ * Returns a object which contains global information about the plugin and each instance of it.
+ * The returned object is just a copy, that means that changes to the returned object won't have any effect to the original object.
+ */
+ _plugin.globals = function () {
+ initOverlayScrollbarsStatics();
+ var globals = FRAMEWORK.extend(true, {}, _pluginsGlobals);
+ delete globals['msie'];
+ return globals;
+ };
+
+ /**
+ * Gets or Sets the default options for each new plugin initialization.
+ * @param newDefaultOptions The object with which the default options shall be extended.
+ */
+ _plugin.defaultOptions = function (newDefaultOptions) {
+ initOverlayScrollbarsStatics();
+ var currDefaultOptions = _pluginsGlobals.defaultOptions;
+ if (newDefaultOptions === undefined)
+ return FRAMEWORK.extend(true, {}, currDefaultOptions);
+
+ //set the new default options
+ _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, {}, currDefaultOptions, _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true, currDefaultOptions)._default);
+ };
+
+ /**
+ * Checks whether the passed instance is a non-destroyed OverlayScrollbars instance.
+ * @param osInstance The potential OverlayScrollbars instance which shall be checked.
+ * @returns {boolean} True if the passed value is a non-destroyed OverlayScrollbars instance, false otherwise.
+ */
+ _plugin.valid = function (osInstance) {
+ return osInstance instanceof _plugin && !osInstance.getState().destroyed;
+ };
+
+ /**
+ * Registers, Unregisters or returns a extension.
+ * Register: Pass the name and the extension. (defaultOptions is optional)
+ * Unregister: Pass the name and anything except a function as extension parameter.
+ * Get extension: Pass the name of the extension which shall be got.
+ * Get all extensions: Pass no arguments.
+ * @param extensionName The name of the extension which shall be registered, unregistered or returned.
+ * @param extension A function which generates the instance of the extension or anything other to remove a already registered extension.
+ * @param defaultOptions The default options which shall be used for the registered extension.
+ */
+ _plugin.extension = function (extensionName, extension, defaultOptions) {
+ var extNameTypeString = COMPATIBILITY.type(extensionName) == TYPES.s;
+ var argLen = arguments[LEXICON.l];
+ var i = 0;
+ if (argLen < 1 || !extNameTypeString) {
+ //return a copy of all extension objects
+ return FRAMEWORK.extend(true, { length: _pluginsExtensions[LEXICON.l] }, _pluginsExtensions);
+ }
+ else if (extNameTypeString) {
+ if (COMPATIBILITY.type(extension) == TYPES.f) {
+ //register extension
+ _pluginsExtensions.push({
+ name: extensionName,
+ extensionFactory: extension,
+ defaultOptions: defaultOptions
+ });
+ }
+ else {
+ for (; i < _pluginsExtensions[LEXICON.l]; i++) {
+ if (_pluginsExtensions[i].name === extensionName) {
+ if (argLen > 1)
+ _pluginsExtensions.splice(i, 1); //remove extension
+ else
+ return FRAMEWORK.extend(true, {}, _pluginsExtensions[i]); //return extension with the given name
+ }
+ }
+ }
+ }
+ };
+
+ return _plugin;
+ })();
+
+ if (JQUERY && JQUERY.fn) {
+ /**
+ * The jQuery initialization interface.
+ * @param options The initial options for the construction of the plugin. To initialize the plugin, this option has to be a object! If it isn't a object, the instance(s) are returned and the plugin wont be initialized.
+ * @param extensions The extension(s) which shall be added right after initialization.
+ * @returns {*} After initialization it returns the jQuery element array, else it returns the instance(s) of the elements which are selected.
+ */
+ JQUERY.fn.overlayScrollbars = function (options, extensions) {
+ var _elements = this;
+ if (JQUERY.isPlainObject(options)) {
+ JQUERY.each(_elements, function () { PLUGIN(this, options, extensions); });
+ return _elements;
+ }
+ else
+ return PLUGIN(_elements, options);
+ };
+ }
+ return PLUGIN;
+ }
));
\ No newline at end of file
diff --git a/plugins/overlayScrollbars/js/jquery.overlayScrollbars.js b/plugins/overlayScrollbars/js/jquery.overlayScrollbars.js
index 3d876f741..4383b712d 100644
--- a/plugins/overlayScrollbars/js/jquery.overlayScrollbars.js
+++ b/plugins/overlayScrollbars/js/jquery.overlayScrollbars.js
@@ -1,5571 +1,5571 @@
-/*!
- * OverlayScrollbars
- * https://github.com/KingSora/OverlayScrollbars
- *
- * Version: 1.11.0
- *
- * Copyright KingSora | Rene Haas.
- * https://github.com/KingSora
- *
- * Released under the MIT license.
- * Date: 29.02.2020
- */
-
-(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',
- ti: 'tabindex',
- 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('
');
- 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
- //since 1.11.0 always false -> fixed via CSS (hopefully)
- 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();
- //https://github.com/KingSora/OverlayScrollbars/issues/187
- scrollbarDummyElement.scrollLeft(-999);
- var dummyContainerChildOffsetAfterScroll = 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 !== dummyContainerChildOffsetAfterScroll.left
- };
- })(),
- 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 which manages the scrollbars visibility of the target element.
- * @param pluginTargetElement The element from which the scrollbars shall be hidden.
- * @param options The custom options.
- * @param extensions The custom extensions.
- * @param globals
- * @param autoUpdateLoop
- * @returns {*}
- * @constructor
- */
- function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) {
- //shortcuts
- var type = COMPATIBILITY.type;
- var inArray = FRAMEWORK.inArray;
- var each = FRAMEWORK.each;
-
- //make correct instanceof
- var _base = new _plugin();
- var _frameworkProto = FRAMEWORK[LEXICON.p];
-
- //if passed element is no HTML element: skip and return
- if (!isHTMLElement(pluginTargetElement))
- return;
-
- //if passed element is already initialized: set passed options if there are any and return its instance
- if (INSTANCES(pluginTargetElement)) {
- var inst = INSTANCES(pluginTargetElement);
- inst.options(options);
- return inst;
- }
-
- //globals:
- var _nativeScrollbarIsOverlaid;
- var _overlayScrollbarDummySize;
- var _rtlScrollBehavior;
- var _autoUpdateRecommended;
- var _msieVersion;
- var _nativeScrollbarStyling;
- var _cssCalc;
- var _nativeScrollbarSize;
- var _supportTransition;
- var _supportTransform;
- var _supportPassiveEvents;
- var _supportResizeObserver;
- var _supportMutationObserver;
- var _restrictedMeasuring;
-
- //general readonly:
- var _initialized;
- var _destroyed;
- var _isTextarea;
- var _isBody;
- var _documentMixed;
- var _domExists;
-
- //general:
- var _isBorderBox;
- var _sizeAutoObserverAdded;
- var _paddingX;
- var _paddingY;
- var _borderX;
- var _borderY;
- var _marginX;
- var _marginY;
- var _isRTL;
- var _sleeping;
- var _contentBorderSize = {};
- var _scrollHorizontalInfo = {};
- var _scrollVerticalInfo = {};
- var _viewportSize = {};
- var _nativeScrollbarMinSize = {};
-
- //naming:
- var _strMinusHidden = '-hidden';
- var _strMarginMinus = 'margin-';
- var _strPaddingMinus = 'padding-';
- var _strBorderMinus = 'border-';
- var _strTop = 'top';
- var _strRight = 'right';
- var _strBottom = 'bottom';
- var _strLeft = 'left';
- var _strMinMinus = 'min-';
- var _strMaxMinus = 'max-';
- var _strWidth = 'width';
- var _strHeight = 'height';
- var _strFloat = 'float';
- var _strEmpty = '';
- var _strAuto = 'auto';
- var _strSync = 'sync';
- var _strScroll = 'scroll';
- var _strHundredPercent = '100%';
- var _strX = 'x';
- var _strY = 'y';
- var _strDot = '.';
- var _strSpace = ' ';
- var _strScrollbar = 'scrollbar';
- var _strMinusHorizontal = '-horizontal';
- var _strMinusVertical = '-vertical';
- var _strScrollLeft = _strScroll + 'Left';
- var _strScrollTop = _strScroll + 'Top';
- var _strMouseTouchDownEvent = 'mousedown touchstart';
- var _strMouseTouchUpEvent = 'mouseup touchend touchcancel';
- var _strMouseTouchMoveEvent = 'mousemove touchmove';
- var _strMouseTouchEnter = 'mouseenter';
- var _strMouseTouchLeave = 'mouseleave';
- var _strKeyDownEvent = 'keydown';
- var _strKeyUpEvent = 'keyup';
- var _strSelectStartEvent = 'selectstart';
- var _strTransitionEndEvent = 'transitionend webkitTransitionEnd oTransitionEnd';
- var _strResizeObserverProperty = '__overlayScrollbarsRO__';
-
- //class names:
- var _cassNamesPrefix = 'os-';
- var _classNameHTMLElement = _cassNamesPrefix + 'html';
- var _classNameHostElement = _cassNamesPrefix + 'host';
- var _classNameHostTextareaElement = _classNameHostElement + '-textarea';
- var _classNameHostScrollbarHorizontalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusHorizontal + _strMinusHidden;
- var _classNameHostScrollbarVerticalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusVertical + _strMinusHidden;
- var _classNameHostTransition = _classNameHostElement + '-transition';
- var _classNameHostRTL = _classNameHostElement + '-rtl';
- var _classNameHostResizeDisabled = _classNameHostElement + '-resize-disabled';
- var _classNameHostScrolling = _classNameHostElement + '-scrolling';
- var _classNameHostOverflow = _classNameHostElement + '-overflow';
- var _classNameHostOverflowX = _classNameHostOverflow + '-x';
- var _classNameHostOverflowY = _classNameHostOverflow + '-y';
- var _classNameTextareaElement = _cassNamesPrefix + 'textarea';
- var _classNameTextareaCoverElement = _classNameTextareaElement + '-cover';
- var _classNamePaddingElement = _cassNamesPrefix + 'padding';
- var _classNameViewportElement = _cassNamesPrefix + 'viewport';
- var _classNameViewportNativeScrollbarsInvisible = _classNameViewportElement + '-native-scrollbars-invisible';
- var _classNameViewportNativeScrollbarsOverlaid = _classNameViewportElement + '-native-scrollbars-overlaid';
- var _classNameContentElement = _cassNamesPrefix + 'content';
- var _classNameContentArrangeElement = _cassNamesPrefix + 'content-arrange';
- var _classNameContentGlueElement = _cassNamesPrefix + 'content-glue';
- var _classNameSizeAutoObserverElement = _cassNamesPrefix + 'size-auto-observer';
- var _classNameResizeObserverElement = _cassNamesPrefix + 'resize-observer';
- var _classNameResizeObserverItemElement = _cassNamesPrefix + 'resize-observer-item';
- var _classNameResizeObserverItemFinalElement = _classNameResizeObserverItemElement + '-final';
- var _classNameTextInherit = _cassNamesPrefix + 'text-inherit';
- var _classNameScrollbar = _cassNamesPrefix + _strScrollbar;
- var _classNameScrollbarTrack = _classNameScrollbar + '-track';
- var _classNameScrollbarTrackOff = _classNameScrollbarTrack + '-off';
- var _classNameScrollbarHandle = _classNameScrollbar + '-handle';
- var _classNameScrollbarHandleOff = _classNameScrollbarHandle + '-off';
- var _classNameScrollbarUnusable = _classNameScrollbar + '-unusable';
- var _classNameScrollbarAutoHidden = _classNameScrollbar + '-' + _strAuto + _strMinusHidden;
- var _classNameScrollbarCorner = _classNameScrollbar + '-corner';
- var _classNameScrollbarCornerResize = _classNameScrollbarCorner + '-resize';
- var _classNameScrollbarCornerResizeB = _classNameScrollbarCornerResize + '-both';
- var _classNameScrollbarCornerResizeH = _classNameScrollbarCornerResize + _strMinusHorizontal;
- var _classNameScrollbarCornerResizeV = _classNameScrollbarCornerResize + _strMinusVertical;
- var _classNameScrollbarHorizontal = _classNameScrollbar + _strMinusHorizontal;
- var _classNameScrollbarVertical = _classNameScrollbar + _strMinusVertical;
- var _classNameDragging = _cassNamesPrefix + 'dragging';
- var _classNameThemeNone = _cassNamesPrefix + 'theme-none';
- var _classNamesDynamicDestroy = [
- _classNameViewportNativeScrollbarsInvisible,
- _classNameViewportNativeScrollbarsOverlaid,
- _classNameScrollbarTrackOff,
- _classNameScrollbarHandleOff,
- _classNameScrollbarUnusable,
- _classNameScrollbarAutoHidden,
- _classNameScrollbarCornerResize,
- _classNameScrollbarCornerResizeB,
- _classNameScrollbarCornerResizeH,
- _classNameScrollbarCornerResizeV,
- _classNameDragging].join(_strSpace);
-
- //callbacks:
- var _callbacksInitQeueue = [];
-
- //attrs viewport shall inherit from target
- var _viewportAttrsFromTarget = [LEXICON.ti];
-
- //options:
- var _defaultOptions;
- var _currentOptions;
- var _currentPreparedOptions;
-
- //extensions:
- var _extensions = {};
- var _extensionsPrivateMethods = 'added removed on contract';
-
- //update
- var _lastUpdateTime;
- var _swallowedUpdateHints = {};
- var _swallowedUpdateTimeout;
- var _swallowUpdateLag = 42;
- var _imgs = [];
-
- //DOM elements:
- var _windowElement;
- var _documentElement;
- var _htmlElement;
- var _bodyElement;
- var _targetElement; //the target element of this OverlayScrollbars object
- var _hostElement; //the host element of this OverlayScrollbars object -> may be the same as targetElement
- var _sizeAutoObserverElement; //observes size auto changes
- var _sizeObserverElement; //observes size and padding changes
- var _paddingElement; //manages the padding
- var _viewportElement; //is the viewport of our scrollbar model
- var _contentElement; //the element which holds the content
- var _contentArrangeElement; //is needed for correct sizing of the content element (only if native scrollbars are overlays)
- var _contentGlueElement; //has always the size of the content element
- var _textareaCoverElement; //only applied if target is a textarea element. Used for correct size calculation and for prevention of uncontrolled scrolling
- var _scrollbarCornerElement;
- var _scrollbarHorizontalElement;
- var _scrollbarHorizontalTrackElement;
- var _scrollbarHorizontalHandleElement;
- var _scrollbarVerticalElement;
- var _scrollbarVerticalTrackElement;
- var _scrollbarVerticalHandleElement;
- var _windowElementNative;
- var _documentElementNative;
- var _targetElementNative;
- var _hostElementNative;
- var _sizeAutoObserverElementNative;
- var _sizeObserverElementNative;
- var _paddingElementNative;
- var _viewportElementNative;
- var _contentElementNative;
-
- //Cache:
- var _hostSizeCache;
- var _contentScrollSizeCache;
- var _arrangeContentSizeCache;
- var _hasOverflowCache;
- var _hideOverflowCache;
- var _widthAutoCache;
- var _heightAutoCache;
- var _cssMaxValueCache;
- var _cssBoxSizingCache;
- var _cssPaddingCache;
- var _cssBorderCache;
- var _cssMarginCache;
- var _cssDirectionCache;
- var _cssDirectionDetectedCache;
- var _paddingAbsoluteCache;
- var _clipAlwaysCache;
- var _contentGlueSizeCache;
- var _overflowBehaviorCache;
- var _overflowAmountCache;
- var _ignoreOverlayScrollbarHidingCache;
- var _autoUpdateCache;
- var _sizeAutoCapableCache;
- var _contentElementScrollSizeChangeDetectedCache;
- var _hostElementSizeChangeDetectedCache;
- var _scrollbarsVisibilityCache;
- var _scrollbarsAutoHideCache;
- var _scrollbarsClickScrollingCache;
- var _scrollbarsDragScrollingCache;
- var _resizeCache;
- var _normalizeRTLCache;
- var _classNameCache;
- var _oldClassName;
- var _textareaAutoWrappingCache;
- var _textareaInfoCache;
- var _textareaSizeCache;
- var _textareaDynHeightCache;
- var _textareaDynWidthCache;
- var _bodyMinSizeCache;
- var _displayIsHiddenCache;
- var _updateAutoCache = {};
-
- //MutationObserver:
- var _mutationObserverHost;
- var _mutationObserverContent;
- var _mutationObserverHostCallback;
- var _mutationObserverContentCallback;
- var _mutationObserversConnected;
- var _mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows'];
- var _mutationObserverAttrsHost = [LEXICON.i, LEXICON.c, LEXICON.s, 'open'].concat(_viewportAttrsFromTarget);
-
- //events:
- var _destroyEvents = [];
-
- //textarea:
- var _textareaHasFocus;
-
- //scrollbars:
- var _scrollbarsAutoHideTimeoutId;
- var _scrollbarsAutoHideMoveTimeoutId;
- var _scrollbarsAutoHideDelay;
- var _scrollbarsAutoHideNever;
- var _scrollbarsAutoHideScroll;
- var _scrollbarsAutoHideMove;
- var _scrollbarsAutoHideLeave;
- var _scrollbarsHandleHovered;
- var _scrollbarsHandlesDefineScrollPos;
-
- //resize
- var _resizeNone;
- var _resizeBoth;
- var _resizeHorizontal;
- var _resizeVertical;
-
-
- //==== Event Listener ====//
-
- /**
- * Adds or removes a event listener from the given element.
- * @param element The element to which the event listener shall be applied or removed.
- * @param eventNames The name(s) of the events.
- * @param listener The method which shall be called.
- * @param remove True if the handler shall be removed, false or undefined if the handler shall be added.
- */
- function setupResponsiveEventListener(element, eventNames, listener, remove, passive) {
- var collected = type(eventNames) == TYPES.a && type(listener) == TYPES.a;
- var method = remove ? 'removeEventListener' : 'addEventListener';
- var onOff = remove ? 'off' : 'on';
- var events = collected ? false : eventNames.split(_strSpace)
- var i = 0;
-
- if (collected) {
- for (; i < eventNames[LEXICON.l]; i++)
- setupResponsiveEventListener(element, eventNames[i], listener[i], remove);
- }
- else {
- for (; i < events[LEXICON.l]; i++) {
- if (_supportPassiveEvents)
- element[0][method](events[i], listener, { passive: passive || false });
- else
- element[onOff](events[i], listener);
- }
- }
- }
-
-
- function addDestroyEventListener(element, eventNames, listener, passive) {
- setupResponsiveEventListener(element, eventNames, listener, false, passive);
- _destroyEvents.push(COMPATIBILITY.bind(setupResponsiveEventListener, 0, element, eventNames, listener, true, passive));
- }
-
- //==== Resize Observer ====//
-
- /**
- * Adds or removes a resize observer from the given element.
- * @param targetElement The element to which the resize observer shall be added or removed.
- * @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change or false / undefined if the resizeObserver shall be removed.
- */
- function setupResizeObserver(targetElement, onElementResizedCallback) {
- if (targetElement) {
- var resizeObserver = COMPATIBILITY.rO();
- var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart';
- var strChildNodes = 'childNodes';
- var constScroll = 3333333;
- var callback = function () {
- targetElement[_strScrollTop](constScroll)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll : constScroll);
- onElementResizedCallback();
- };
- //add resize observer:
- if (onElementResizedCallback) {
- if (_supportResizeObserver) {
- var element = targetElement.addClass('observed').append(generateDiv(_classNameResizeObserverElement)).contents()[0];
- var observer = element[_strResizeObserverProperty] = new resizeObserver(callback);
- observer.observe(element);
- }
- else {
- if (_msieVersion > 9 || !_autoUpdateRecommended) {
- targetElement.prepend(
- generateDiv(_classNameResizeObserverElement,
- generateDiv({ c: _classNameResizeObserverItemElement, dir: 'ltr' },
- generateDiv(_classNameResizeObserverItemElement,
- generateDiv(_classNameResizeObserverItemFinalElement)
- ) +
- generateDiv(_classNameResizeObserverItemElement,
- generateDiv({ c: _classNameResizeObserverItemFinalElement, style: 'width: 200%; height: 200%' })
- )
- )
- )
- );
-
- var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0];
- var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]);
- var expandElement = FRAMEWORK(observerElement[strChildNodes][0]);
- var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]);
- var widthCache = observerElement[LEXICON.oW];
- var heightCache = observerElement[LEXICON.oH];
- var isDirty;
- var rAFId;
- var currWidth;
- var currHeight;
- var factor = 2;
- var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!!
- var reset = function () {
- /*
- var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
- var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
- var expandChildCSS = {};
- expandChildCSS[_strWidth] = sizeResetWidth;
- expandChildCSS[_strHeight] = sizeResetHeight;
- expandElementChild.css(expandChildCSS);
-
-
- expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
- shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
- */
- expandElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);
- shrinkElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);
- };
- var onResized = function () {
- rAFId = 0;
- if (!isDirty)
- return;
-
- widthCache = currWidth;
- heightCache = currHeight;
- callback();
- };
- var onScroll = function (event) {
- currWidth = observerElement[LEXICON.oW];
- currHeight = observerElement[LEXICON.oH];
- isDirty = currWidth != widthCache || currHeight != heightCache;
-
- if (event && isDirty && !rAFId) {
- COMPATIBILITY.cAF()(rAFId);
- rAFId = COMPATIBILITY.rAF()(onResized);
- }
- else if (!event)
- onResized();
-
- reset();
- if (event) {
- COMPATIBILITY.prvD(event);
- COMPATIBILITY.stpP(event);
- }
- return false;
- };
- var expandChildCSS = {};
- var observerElementCSS = {};
-
- setTopRightBottomLeft(observerElementCSS, _strEmpty, [
- -((nativeScrollbarSize.y + 1) * factor),
- nativeScrollbarSize.x * -factor,
- nativeScrollbarSize.y * -factor,
- -((nativeScrollbarSize.x + 1) * factor)
- ]);
-
- FRAMEWORK(observerElement).css(observerElementCSS);
- expandElement.on(_strScroll, onScroll);
- shrinkElement.on(_strScroll, onScroll);
- targetElement.on(strAnimationStartEvent, function () {
- onScroll(false);
- });
- //lets assume that the divs will never be that large and a constant value is enough
- expandChildCSS[_strWidth] = constScroll;
- expandChildCSS[_strHeight] = constScroll;
- expandElementChild.css(expandChildCSS);
-
- reset();
- }
- else {
- var attachEvent = _documentElementNative.attachEvent;
- var isIE = _msieVersion !== undefined;
- if (attachEvent) {
- targetElement.prepend(generateDiv(_classNameResizeObserverElement));
- findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback);
- }
- else {
- var obj = _documentElementNative.createElement(TYPES.o);
- obj.setAttribute(LEXICON.ti, '-1');
- obj.setAttribute(LEXICON.c, _classNameResizeObserverElement);
- obj.onload = function () {
- var wnd = this.contentDocument.defaultView;
- wnd.addEventListener('resize', callback);
- wnd.document.documentElement.style.display = 'none';
- };
- obj.type = 'text/html';
- if (isIE)
- targetElement.prepend(obj);
- obj.data = 'about:blank';
- if (!isIE)
- targetElement.prepend(obj);
- targetElement.on(strAnimationStartEvent, callback);
- }
- }
- }
-
- if (targetElement[0] === _sizeObserverElementNative) {
- var directionChanged = function () {
- var dir = _hostElement.css('direction');
- var css = {};
- var scrollLeftValue = 0;
- var result = false;
- if (dir !== _cssDirectionDetectedCache) {
- if (dir === 'ltr') {
- css[_strLeft] = 0;
- css[_strRight] = _strAuto;
- scrollLeftValue = constScroll;
- }
- else {
- css[_strLeft] = _strAuto;
- css[_strRight] = 0;
- scrollLeftValue = _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll;
- }
- //execution order is important for IE!!!
- _sizeObserverElement.children().eq(0).css(css);
- _sizeObserverElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constScroll);
- _cssDirectionDetectedCache = dir;
- result = true;
- }
- return result;
- };
- directionChanged();
- addDestroyEventListener(targetElement, _strScroll, function (event) {
- if (directionChanged())
- update();
- COMPATIBILITY.prvD(event);
- COMPATIBILITY.stpP(event);
- return false;
- });
- }
- }
- //remove resize observer:
- else {
- if (_supportResizeObserver) {
- var element = targetElement.contents()[0];
- var resizeObserverObj = element[_strResizeObserverProperty];
- if (resizeObserverObj) {
- resizeObserverObj.disconnect();
- delete element[_strResizeObserverProperty];
- }
- }
- else {
- remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0));
- }
- }
- }
- }
-
- /**
- * Freezes or unfreezes the given resize observer.
- * @param targetElement The element to which the target resize observer is applied.
- * @param freeze True if the resize observer shall be frozen, false otherwise.
-
- function freezeResizeObserver(targetElement, freeze) {
- if (targetElement !== undefined) {
- if(freeze) {
- if (_supportResizeObserver) {
- var element = targetElement.contents()[0];
- element[_strResizeObserverProperty].unobserve(element);
- }
- else {
- targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0);
- var w = targetElement.css(_strWidth);
- var h = targetElement.css(_strHeight);
- var css = {};
- css[_strWidth] = w;
- css[_strHeight] = h;
- targetElement.css(css);
- }
- }
- else {
- if (_supportResizeObserver) {
- var element = targetElement.contents()[0];
- element[_strResizeObserverProperty].observe(element);
- }
- else {
- var css = { };
- css[_strHeight] = _strEmpty;
- css[_strWidth] = _strEmpty;
- targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css);
- }
- }
- }
- }
- */
-
-
- //==== Mutation Observers ====//
-
- /**
- * Creates MutationObservers for the host and content Element if they are supported.
- */
- function createMutationObservers() {
- if (_supportMutationObserver) {
- var mutationObserverContentLag = 11;
- var mutationObserver = COMPATIBILITY.mO();
- var contentLastUpdate = COMPATIBILITY.now();
- var mutationTarget;
- var mutationAttrName;
- var contentTimeout;
- var now;
- var sizeAuto;
- var action;
-
- _mutationObserverHostCallback = function (mutations) {
- var doUpdate = false;
- var mutation;
- var mutatedAttrs = [];
-
- if (_initialized && !_sleeping) {
- each(mutations, function () {
- mutation = this;
- mutationTarget = mutation.target;
- mutationAttrName = mutation.attributeName;
-
- if(!doUpdate) {
- if (mutationAttrName === LEXICON.c)
- doUpdate = hostClassNamesChanged(mutation.oldValue, mutationTarget.className);
- else if (mutationAttrName === LEXICON.s)
- doUpdate = mutation.oldValue !== mutationTarget[LEXICON.s].cssText;
- else
- doUpdate = true;
- }
-
- mutatedAttrs.push(mutationAttrName);
- });
-
- updateViewportAttrsFromTarget(mutatedAttrs);
-
- if (doUpdate)
- _base.update(_strAuto);
- }
- return doUpdate;
- };
- _mutationObserverContentCallback = function (mutations) {
- var doUpdate = false;
- var mutation;
-
- if (_initialized && !_sleeping) {
- each(mutations, function () {
- mutation = this;
- doUpdate = isUnknownMutation(mutation);
- return !doUpdate;
- });
-
- if (doUpdate) {
- now = COMPATIBILITY.now();
- sizeAuto = (_heightAutoCache || _widthAutoCache);
- action = function () {
- if (!_destroyed) {
- contentLastUpdate = now;
-
- //if cols, rows or wrap attr was changed
- if (_isTextarea)
- textareaUpdate();
-
- if (sizeAuto)
- update();
- else
- _base.update(_strAuto);
- }
- };
- clearTimeout(contentTimeout);
- if (mutationObserverContentLag <= 0 || now - contentLastUpdate > mutationObserverContentLag || !sizeAuto)
- action();
- else
- contentTimeout = setTimeout(action, mutationObserverContentLag);
- }
- }
- return doUpdate;
- }
-
- _mutationObserverHost = new mutationObserver(_mutationObserverHostCallback);
- _mutationObserverContent = new mutationObserver(_mutationObserverContentCallback);
- }
- }
-
- /**
- * Connects the MutationObservers if they are supported.
- */
- function connectMutationObservers() {
- if (_supportMutationObserver && !_mutationObserversConnected) {
- _mutationObserverHost.observe(_hostElementNative, {
- attributes: true,
- attributeOldValue: true,
- attributeFilter: _mutationObserverAttrsHost
- });
-
- _mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, {
- attributes: true,
- attributeOldValue: true,
- subtree: !_isTextarea,
- childList: !_isTextarea,
- characterData: !_isTextarea,
- attributeFilter: _isTextarea ? _mutationObserverAttrsTextarea : _mutationObserverAttrsHost
- });
-
- _mutationObserversConnected = true;
- }
- }
-
- /**
- * Disconnects the MutationObservers if they are supported.
- */
- function disconnectMutationObservers() {
- if (_supportMutationObserver && _mutationObserversConnected) {
- _mutationObserverHost.disconnect();
- _mutationObserverContent.disconnect();
-
- _mutationObserversConnected = false;
- }
- }
-
-
- //==== Events of elements ====//
-
- /**
- * This method gets called every time the host element gets resized. IMPORTANT: Padding changes are detected too!!
- * It refreshes the hostResizedEventArgs and the hostSizeResizeCache.
- * If there are any size changes, the update method gets called.
- */
- function hostOnResized() {
- if (!_sleeping) {
- var changed;
- var hostSize = {
- w: _sizeObserverElementNative[LEXICON.sW],
- h: _sizeObserverElementNative[LEXICON.sH]
- };
-
- changed = checkCache(hostSize, _hostElementSizeChangeDetectedCache);
- _hostElementSizeChangeDetectedCache = hostSize;
- if (changed)
- update({ _hostSizeChanged: true });
- }
- }
-
- /**
- * The mouse enter event of the host element. This event is only needed for the autoHide feature.
- */
- function hostOnMouseEnter() {
- if (_scrollbarsAutoHideLeave)
- refreshScrollbarsAutoHide(true);
- }
-
- /**
- * The mouse leave event of the host element. This event is only needed for the autoHide feature.
- */
- function hostOnMouseLeave() {
- if (_scrollbarsAutoHideLeave && !_bodyElement.hasClass(_classNameDragging))
- refreshScrollbarsAutoHide(false);
- }
-
- /**
- * The mouse move event of the host element. This event is only needed for the autoHide "move" feature.
- */
- function hostOnMouseMove() {
- if (_scrollbarsAutoHideMove) {
- refreshScrollbarsAutoHide(true);
- clearTimeout(_scrollbarsAutoHideMoveTimeoutId);
- _scrollbarsAutoHideMoveTimeoutId = setTimeout(function () {
- if (_scrollbarsAutoHideMove && !_destroyed)
- refreshScrollbarsAutoHide(false);
- }, 100);
- }
- }
-
- /**
- * Prevents text from deselection if attached to the document element on the mousedown event of a DOM element.
- * @param event The select start event.
- */
- function documentOnSelectStart(event) {
- COMPATIBILITY.prvD(event);
- return false;
- }
-
- /**
- * A callback which will be called after a img element has downloaded its src asynchronous.
- */
- function imgOnLoad() {
- update({ _contentSizeChanged: true });
- }
-
- /**
- * Adds or removes mouse & touch events of the host element. (for handling auto-hiding of the scrollbars)
- * @param destroy Indicates whether the events shall be added or removed.
- */
- function setupHostMouseTouchEvents(destroy) {
- setupResponsiveEventListener(_hostElement,
- _strMouseTouchMoveEvent,
- hostOnMouseMove,
- (_scrollbarsAutoHideMove ? destroy : true), true);
- setupResponsiveEventListener(_hostElement,
- [_strMouseTouchEnter, _strMouseTouchLeave],
- [hostOnMouseEnter, hostOnMouseLeave],
- (_scrollbarsAutoHideMove ? true : destroy), true);
-
- //if the plugin is initialized and the mouse is over the host element, make the scrollbars visible
- if (!_initialized && !destroy)
- _hostElement.one('mouseover', hostOnMouseEnter);
- }
-
-
- //==== Update Detection ====//
-
- /**
- * Measures the min width and min height of the body element and refreshes the related cache.
- * @returns {boolean} True if the min width or min height has changed, false otherwise.
- */
- function bodyMinSizeChanged() {
- var bodyMinSize = {};
- if (_isBody && _contentArrangeElement) {
- bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth));
- bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight));
- bodyMinSize.c = checkCache(bodyMinSize, _bodyMinSizeCache);
- bodyMinSize.f = true; //flag for "measured at least once"
- }
- _bodyMinSizeCache = bodyMinSize;
- return !!bodyMinSize.c;
- }
-
- /**
- * Returns true if the class names really changed (new class without plugin host prefix)
- * @param oldCassNames The old ClassName string.
- * @param newClassNames The new ClassName string.
- * @returns {boolean} True if the class names has really changed, false otherwise.
- */
- function hostClassNamesChanged(oldCassNames, newClassNames) {
- var currClasses = (newClassNames !== undefined && newClassNames !== null) ? newClassNames.split(_strSpace) : _strEmpty;
- var oldClasses = (oldCassNames !== undefined && oldCassNames !== null) ? oldCassNames.split(_strSpace) : _strEmpty;
- if (currClasses === _strEmpty && oldClasses === _strEmpty)
- return false;
- var diff = getArrayDifferences(oldClasses, currClasses);
- var changed = false;
- var oldClassNames = _oldClassName !== undefined && _oldClassName !== null ? _oldClassName.split(_strSpace) : [_strEmpty];
- var currClassNames = _classNameCache !== undefined && _classNameCache !== null ? _classNameCache.split(_strSpace) : [_strEmpty];
-
- //remove none theme from diff list to prevent update
- var idx = inArray(_classNameThemeNone, diff);
- var curr;
- var i;
- var v;
- var o;
- var c;
-
- if (idx > -1)
- diff.splice(idx, 1);
-
- for (i = 0; i < diff.length; i++) {
- curr = diff[i];
- if (curr.indexOf(_classNameHostElement) !== 0) {
- o = true;
- c = true;
- for (v = 0; v < oldClassNames.length; v++) {
- if (curr === oldClassNames[v]) {
- o = false;
- break;
- }
- }
- for (v = 0; v < currClassNames.length; v++) {
- if (curr === currClassNames[v]) {
- c = false;
- break;
- }
- }
- if (o && c) {
- changed = true;
- break;
- }
- }
-
- }
- return changed;
- }
-
- /**
- * Returns true if the given mutation is not from a from the plugin generated element. If the target element is a textarea the mutation is always unknown.
- * @param mutation The mutation which shall be checked.
- * @returns {boolean} True if the mutation is from a unknown element, false otherwise.
- */
- function isUnknownMutation(mutation) {
- var attributeName = mutation.attributeName;
- var mutationTarget = mutation.target;
- var mutationType = mutation.type;
- var strClosest = 'closest';
-
- if (mutationTarget === _contentElementNative)
- return attributeName === null;
- if (mutationType === 'attributes' && (attributeName === LEXICON.c || attributeName === LEXICON.s) && !_isTextarea) {
- //ignore className changes by the plugin
- if (attributeName === LEXICON.c && FRAMEWORK(mutationTarget).hasClass(_classNameHostElement))
- return hostClassNamesChanged(mutation.oldValue, mutationTarget.getAttribute(LEXICON.c));
-
- //only do it of browser support it natively
- if (typeof mutationTarget[strClosest] != TYPES.f)
- return true;
- if (mutationTarget[strClosest](_strDot + _classNameResizeObserverElement) !== null ||
- mutationTarget[strClosest](_strDot + _classNameScrollbar) !== null ||
- mutationTarget[strClosest](_strDot + _classNameScrollbarCorner) !== null)
- return false;
- }
- return true;
- }
-
- /**
- * Returns true if the content size was changed since the last time this method was called.
- * @returns {boolean} True if the content size was changed, false otherwise.
- */
- function updateAutoContentSizeChanged() {
- if (_sleeping)
- return false;
-
- var contentMeasureElement = getContentMeasureElement();
- var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0;
- var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea;
- var css = {};
- var float;
- var bodyMinSizeC;
- var changed;
- var contentElementScrollSize;
-
- if (setCSS) {
- float = _contentElement.css(_strFloat);
- css[_strFloat] = _isRTL ? _strRight : _strLeft;
- css[_strWidth] = _strAuto;
- _contentElement.css(css);
- }
- contentElementScrollSize = {
- w: contentMeasureElement[LEXICON.sW] + textareaValueLength,
- h: contentMeasureElement[LEXICON.sH] + textareaValueLength
- };
- if (setCSS) {
- css[_strFloat] = float;
- css[_strWidth] = _strHundredPercent;
- _contentElement.css(css);
- }
-
- bodyMinSizeC = bodyMinSizeChanged();
- changed = checkCache(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache);
-
- _contentElementScrollSizeChangeDetectedCache = contentElementScrollSize;
-
- return changed || bodyMinSizeC;
- }
-
- /**
- * Returns true when a attribute which the MutationObserver would observe has changed.
- * @returns {boolean} True if one of the attributes which a MutationObserver would observe has changed, false or undefined otherwise.
- */
- function meaningfulAttrsChanged() {
- if (_sleeping || _mutationObserversConnected)
- return;
-
- var elem;
- var curr;
- var cache;
- var changedAttrs = [];
- var checks = [
- {
- _elem: _hostElement,
- _attrs: _mutationObserverAttrsHost.concat(':visible')
- },
- {
- _elem: _isTextarea ? _targetElement : undefined,
- _attrs: _mutationObserverAttrsTextarea
- }
- ];
-
- each(checks, function (index, check) {
- elem = check._elem;
- if (elem) {
- each(check._attrs, function (index, attr) {
- curr = attr.charAt(0) === ':' ? elem.is(attr) : elem.attr(attr);
- cache = _updateAutoCache[attr];
-
- if(checkCache(curr, cache)) {
- changedAttrs.push(attr);
- }
-
- _updateAutoCache[attr] = curr;
- });
- }
- });
-
- updateViewportAttrsFromTarget(changedAttrs);
-
- return changedAttrs[LEXICON.l] > 0;
- }
-
- /**
- * Checks is a CSS Property of a child element is affecting the scroll size of the content.
- * @param propertyName The CSS property name.
- * @returns {boolean} True if the property is affecting the content scroll size, false otherwise.
- */
- function isSizeAffectingCSSProperty(propertyName) {
- if (!_initialized)
- return true;
- var flexGrow = 'flex-grow';
- var flexShrink = 'flex-shrink';
- var flexBasis = 'flex-basis';
- var affectingPropsX = [
- _strWidth,
- _strMinMinus + _strWidth,
- _strMaxMinus + _strWidth,
- _strMarginMinus + _strLeft,
- _strMarginMinus + _strRight,
- _strLeft,
- _strRight,
- 'font-weight',
- 'word-spacing',
- flexGrow,
- flexShrink,
- flexBasis
- ];
- var affectingPropsXContentBox = [
- _strPaddingMinus + _strLeft,
- _strPaddingMinus + _strRight,
- _strBorderMinus + _strLeft + _strWidth,
- _strBorderMinus + _strRight + _strWidth
- ];
- var affectingPropsY = [
- _strHeight,
- _strMinMinus + _strHeight,
- _strMaxMinus + _strHeight,
- _strMarginMinus + _strTop,
- _strMarginMinus + _strBottom,
- _strTop,
- _strBottom,
- 'line-height',
- flexGrow,
- flexShrink,
- flexBasis
- ];
- var affectingPropsYContentBox = [
- _strPaddingMinus + _strTop,
- _strPaddingMinus + _strBottom,
- _strBorderMinus + _strTop + _strWidth,
- _strBorderMinus + _strBottom + _strWidth
- ];
- var _strS = 's';
- var _strVS = 'v-s';
- var checkX = _overflowBehaviorCache.x === _strS || _overflowBehaviorCache.x === _strVS;
- var checkY = _overflowBehaviorCache.y === _strS || _overflowBehaviorCache.y === _strVS;
- var sizeIsAffected = false;
- var checkPropertyName = function (arr, name) {
- for (var i = 0; i < arr[LEXICON.l]; i++) {
- if (arr[i] === name)
- return true;
- }
- return false;
- };
-
- if (checkY) {
- sizeIsAffected = checkPropertyName(affectingPropsY, propertyName);
- if (!sizeIsAffected && !_isBorderBox)
- sizeIsAffected = checkPropertyName(affectingPropsYContentBox, propertyName);
- }
- if (checkX && !sizeIsAffected) {
- sizeIsAffected = checkPropertyName(affectingPropsX, propertyName);
- if (!sizeIsAffected && !_isBorderBox)
- sizeIsAffected = checkPropertyName(affectingPropsXContentBox, propertyName);
- }
- return sizeIsAffected;
- }
-
-
- //==== Update ====//
-
- /**
- * Sets the attribute values of the viewport element to the values from the target element.
- * The value of a attribute is only set if the attribute is whitelisted.
- * @attrs attrs The array of attributes which shall be set or undefined if all whitelisted shall be set.
- */
- function updateViewportAttrsFromTarget(attrs) {
- attrs = attrs || _viewportAttrsFromTarget;
- each(attrs, function (index, attr) {
- if (COMPATIBILITY.inA(attr, _viewportAttrsFromTarget) > -1) {
- var targetAttr = _targetElement.attr(attr);
- if(type(targetAttr) == TYPES.s) {
- _viewportElement.attr(attr, targetAttr);
- }
- else {
- _viewportElement.removeAttr(attr);
- }
- }
- });
- }
-
- /**
- * Updates the variables and size of the textarea element, and manages the scroll on new line or new character.
- */
- function textareaUpdate() {
- if (!_sleeping) {
- var wrapAttrOff = !_textareaAutoWrappingCache;
- var minWidth = _viewportSize.w;
- var minHeight = _viewportSize.h;
- var css = {};
- var doMeasure = _widthAutoCache || wrapAttrOff;
- var origWidth;
- var width;
- var origHeight;
- var height;
-
- //reset min size
- css[_strMinMinus + _strWidth] = _strEmpty;
- css[_strMinMinus + _strHeight] = _strEmpty;
-
- //set width auto
- css[_strWidth] = _strAuto;
- _targetElement.css(css);
-
- //measure width
- origWidth = _targetElementNative[LEXICON.oW];
- width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1;
- /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/
-
- //set measured width
- css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent;
- css[_strMinMinus + _strWidth] = _strHundredPercent;
-
- //set height auto
- css[_strHeight] = _strAuto;
- _targetElement.css(css);
-
- //measure height
- origHeight = _targetElementNative[LEXICON.oH];
- height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1);
-
- //append correct size values
- css[_strWidth] = width;
- css[_strHeight] = height;
- _textareaCoverElement.css(css);
-
- //apply min width / min height to prevent textarea collapsing
- css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/;
- css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/;
- _targetElement.css(css);
-
- return {
- _originalWidth: origWidth,
- _originalHeight: origHeight,
- _dynamicWidth: width,
- _dynamicHeight: height
- };
- }
- }
-
- /**
- * Updates the plugin and DOM to the current options.
- * This method should only be called if a update is 100% required.
- * @param updateHints A objects which contains hints for this update:
- * {
- * _hostSizeChanged : boolean,
- * _contentSizeChanged : boolean,
- * _force : boolean, == preventSwallowing
- * _changedOptions : { }, == preventSwallowing && preventSleep
- * }
- */
- function update(updateHints) {
- clearTimeout(_swallowedUpdateTimeout);
- updateHints = updateHints || {};
- _swallowedUpdateHints._hostSizeChanged |= updateHints._hostSizeChanged;
- _swallowedUpdateHints._contentSizeChanged |= updateHints._contentSizeChanged;
- _swallowedUpdateHints._force |= updateHints._force;
-
- var now = COMPATIBILITY.now();
- var hostSizeChanged = !!_swallowedUpdateHints._hostSizeChanged;
- var contentSizeChanged = !!_swallowedUpdateHints._contentSizeChanged;
- var force = !!_swallowedUpdateHints._force;
- var changedOptions = updateHints._changedOptions;
- var swallow = _swallowUpdateLag > 0 && _initialized && !_destroyed && !force && !changedOptions && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache);
- var displayIsHidden;
-
- if (swallow)
- _swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag);
-
- //abort update due to:
- //destroyed
- //swallowing
- //sleeping
- //host is hidden or has false display
- if (_destroyed || swallow || (_sleeping && !changedOptions) || (_initialized && !force && (displayIsHidden = _hostElement.is(':hidden'))) || _hostElement.css('display') === 'inline')
- return;
-
- _lastUpdateTime = now;
- _swallowedUpdateHints = {};
-
- //if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely.
- if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
- //native scrollbars are hidden, so change the values to zero
- _nativeScrollbarSize.x = 0;
- _nativeScrollbarSize.y = 0;
- }
- else {
- //refresh native scrollbar size (in case of zoom)
- _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
- }
-
- // Scrollbar padding is needed for firefox, because firefox hides scrollbar automatically if the size of the div is too small.
- // The calculation: [scrollbar size +3 *3]
- // (+3 because of possible decoration e.g. borders, margins etc., but only if native scrollbar is NOT a overlaid scrollbar)
- // (*3 because (1)increase / (2)decrease -button and (3)resize handle)
- _nativeScrollbarMinSize = {
- x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3,
- y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 3
- };
-
- //changedOptions = changedOptions || { };
- //freezeResizeObserver(_sizeObserverElement, true);
- //freezeResizeObserver(_sizeAutoObserverElement, true);
-
- var checkCacheAutoForce = function () {
- return checkCache.apply(this, [].slice.call(arguments).concat([force]));
- };
-
- //save current scroll offset
- var currScroll = {
- x: _viewportElement[_strScrollLeft](),
- y: _viewportElement[_strScrollTop]()
- };
-
- var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars;
- var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea;
-
- //scrollbars visibility:
- var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility;
- var scrollbarsVisibilityChanged = checkCacheAutoForce(scrollbarsVisibility, _scrollbarsVisibilityCache);
-
- //scrollbars autoHide:
- var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide;
- var scrollbarsAutoHideChanged = checkCacheAutoForce(scrollbarsAutoHide, _scrollbarsAutoHideCache);
-
- //scrollbars click scrolling
- var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling;
- var scrollbarsClickScrollingChanged = checkCacheAutoForce(scrollbarsClickScrolling, _scrollbarsClickScrollingCache);
-
- //scrollbars drag scrolling
- var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling;
- var scrollbarsDragScrollingChanged = checkCacheAutoForce(scrollbarsDragScrolling, _scrollbarsDragScrollingCache);
-
- //className
- var className = _currentPreparedOptions.className;
- var classNameChanged = checkCacheAutoForce(className, _classNameCache);
-
- //resize
- var resize = _currentPreparedOptions.resize;
- var resizeChanged = checkCacheAutoForce(resize, _resizeCache) && !_isBody; //body can't be resized since the window itself acts as resize possibility.
-
- //paddingAbsolute
- var paddingAbsolute = _currentPreparedOptions.paddingAbsolute;
- var paddingAbsoluteChanged = checkCacheAutoForce(paddingAbsolute, _paddingAbsoluteCache);
-
- //clipAlways
- var clipAlways = _currentPreparedOptions.clipAlways;
- var clipAlwaysChanged = checkCacheAutoForce(clipAlways, _clipAlwaysCache);
-
- //sizeAutoCapable
- var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport.
- var sizeAutoCapableChanged = checkCacheAutoForce(sizeAutoCapable, _sizeAutoCapableCache);
-
- //showNativeScrollbars
- var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars;
- var ignoreOverlayScrollbarHidingChanged = checkCacheAutoForce(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache);
-
- //autoUpdate
- var autoUpdate = _currentPreparedOptions.autoUpdate;
- var autoUpdateChanged = checkCacheAutoForce(autoUpdate, _autoUpdateCache);
-
- //overflowBehavior
- var overflowBehavior = _currentPreparedOptions.overflowBehavior;
- var overflowBehaviorChanged = checkCacheAutoForce(overflowBehavior, _overflowBehaviorCache, force);
-
- //dynWidth:
- var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth;
- var textareaDynWidthChanged = checkCacheAutoForce(_textareaDynWidthCache, textareaDynWidth);
-
- //dynHeight:
- var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight;
- var textareaDynHeightChanged = checkCacheAutoForce(_textareaDynHeightCache, textareaDynHeight);
-
- //scrollbars visibility
- _scrollbarsAutoHideNever = scrollbarsAutoHide === 'n';
- _scrollbarsAutoHideScroll = scrollbarsAutoHide === 's';
- _scrollbarsAutoHideMove = scrollbarsAutoHide === 'm';
- _scrollbarsAutoHideLeave = scrollbarsAutoHide === 'l';
-
- //scrollbars autoHideDelay
- _scrollbarsAutoHideDelay = currentPreparedOptionsScrollbars.autoHideDelay;
-
- //old className
- _oldClassName = _classNameCache;
-
- //resize
- _resizeNone = resize === 'n';
- _resizeBoth = resize === 'b';
- _resizeHorizontal = resize === 'h';
- _resizeVertical = resize === 'v';
-
- //normalizeRTL
- _normalizeRTLCache = _currentPreparedOptions.normalizeRTL;
-
- //ignore overlay scrollbar hiding
- ignoreOverlayScrollbarHiding = ignoreOverlayScrollbarHiding && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y);
-
- //refresh options cache
- _scrollbarsVisibilityCache = scrollbarsVisibility;
- _scrollbarsAutoHideCache = scrollbarsAutoHide;
- _scrollbarsClickScrollingCache = scrollbarsClickScrolling;
- _scrollbarsDragScrollingCache = scrollbarsDragScrolling;
- _classNameCache = className;
- _resizeCache = resize;
- _paddingAbsoluteCache = paddingAbsolute;
- _clipAlwaysCache = clipAlways;
- _sizeAutoCapableCache = sizeAutoCapable;
- _ignoreOverlayScrollbarHidingCache = ignoreOverlayScrollbarHiding;
- _autoUpdateCache = autoUpdate;
- _overflowBehaviorCache = extendDeep({}, overflowBehavior);
- _textareaDynWidthCache = textareaDynWidth;
- _textareaDynHeightCache = textareaDynHeight;
- _hasOverflowCache = _hasOverflowCache || { x: false, y: false };
-
- //set correct class name to the host element
- if (classNameChanged) {
- removeClass(_hostElement, _oldClassName + _strSpace + _classNameThemeNone);
- addClass(_hostElement, className !== undefined && className !== null && className.length > 0 ? className : _classNameThemeNone);
- }
-
- //set correct auto Update
- if (autoUpdateChanged) {
- if (autoUpdate === true) {
- disconnectMutationObservers();
- autoUpdateLoop.add(_base);
- }
- else if (autoUpdate === null) {
- if (_autoUpdateRecommended) {
- disconnectMutationObservers();
- autoUpdateLoop.add(_base);
- }
- else {
- autoUpdateLoop.remove(_base);
- connectMutationObservers();
- }
- }
- else {
- autoUpdateLoop.remove(_base);
- connectMutationObservers();
- }
- }
-
- //activate or deactivate size auto capability
- if (sizeAutoCapableChanged) {
- if (sizeAutoCapable) {
- if (!_contentGlueElement) {
- _contentGlueElement = FRAMEWORK(generateDiv(_classNameContentGlueElement));
- _paddingElement.before(_contentGlueElement);
- }
- else {
- _contentGlueElement.show();
- }
- if (_sizeAutoObserverAdded) {
- _sizeAutoObserverElement.show();
- }
- else {
- _sizeAutoObserverElement = FRAMEWORK(generateDiv(_classNameSizeAutoObserverElement));
- _sizeAutoObserverElementNative = _sizeAutoObserverElement[0];
-
- _contentGlueElement.before(_sizeAutoObserverElement);
- var oldSize = { w: -1, h: -1 };
- setupResizeObserver(_sizeAutoObserverElement, function () {
- var newSize = {
- w: _sizeAutoObserverElementNative[LEXICON.oW],
- h: _sizeAutoObserverElementNative[LEXICON.oH]
- };
- if (checkCache(newSize, oldSize)) {
- if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) {
- update();
- }
- else if (_initialized && (!_heightAutoCache && newSize.h === 0) || (!_widthAutoCache && newSize.w === 0)) {
- update();
- }
- }
- oldSize = newSize;
- });
- _sizeAutoObserverAdded = true;
- //fix heightAuto detector bug if height is fixed but contentHeight is 0.
- //the probability this bug will ever happen is very very low, thats why its ok if we use calc which isn't supported in IE8.
- if (_cssCalc !== null)
- _sizeAutoObserverElement.css(_strHeight, _cssCalc + '(100% + 1px)');
- }
- }
- else {
- if (_sizeAutoObserverAdded)
- _sizeAutoObserverElement.hide();
- if (_contentGlueElement)
- _contentGlueElement.hide();
- }
- }
-
- //if force, update all resizeObservers too
- if (force) {
- _sizeObserverElement.find('*').trigger(_strScroll);
- if (_sizeAutoObserverAdded)
- _sizeAutoObserverElement.find('*').trigger(_strScroll);
- }
-
- //display hidden:
- displayIsHidden = displayIsHidden === undefined ? _hostElement.is(':hidden') : displayIsHidden;
- var displayIsHiddenChanged = checkCacheAutoForce(displayIsHidden, _displayIsHiddenCache);
-
- //textarea AutoWrapping:
- var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false;
- var textareaAutoWrappingChanged = checkCacheAutoForce(textareaAutoWrapping, _textareaAutoWrappingCache);
-
- //detect direction:
- var cssDirection = _hostElement.css('direction');
- var cssDirectionChanged = checkCacheAutoForce(cssDirection, _cssDirectionCache);
-
- //detect box-sizing:
- var boxSizing = _hostElement.css('box-sizing');
- var boxSizingChanged = checkCacheAutoForce(boxSizing, _cssBoxSizingCache);
-
- //detect padding:
- var padding = {
- c: force,
- t: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strTop)),
- r: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strRight)),
- b: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strBottom)),
- l: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strLeft))
- };
-
- //width + height auto detecting var:
- var sizeAutoObserverElementBCRect;
- //exception occurs in IE8 sometimes (unknown exception)
- try {
- sizeAutoObserverElementBCRect = _sizeAutoObserverAdded ? _sizeAutoObserverElementNative[LEXICON.bCR]() : null;
- } catch (ex) {
- return;
- }
-
- _isRTL = cssDirection === 'rtl';
- _isBorderBox = (boxSizing === 'border-box');
- var isRTLLeft = _isRTL ? _strLeft : _strRight;
- var isRTLRight = _isRTL ? _strRight : _strLeft;
-
- //detect width auto:
- var widthAutoResizeDetection = false;
- var widthAutoObserverDetection = (_sizeAutoObserverAdded && (_hostElement.css(_strFloat) !== 'none' /*|| _isTextarea */)) ? (MATH.round(sizeAutoObserverElementBCRect.right - sizeAutoObserverElementBCRect.left) === 0) && (!paddingAbsolute ? (_hostElementNative[LEXICON.cW] - _paddingX) > 0 : true) : false;
- if (sizeAutoCapable && !widthAutoObserverDetection) {
- var tmpCurrHostWidth = _hostElementNative[LEXICON.oW];
- var tmpCurrContentGlueWidth = _contentGlueElement.css(_strWidth);
- _contentGlueElement.css(_strWidth, _strAuto);
-
- var tmpNewHostWidth = _hostElementNative[LEXICON.oW];
- _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
- widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
- if (!widthAutoResizeDetection) {
- _contentGlueElement.css(_strWidth, tmpCurrHostWidth + 1);
- tmpNewHostWidth = _hostElementNative[LEXICON.oW];
- _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
- widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
- }
- }
- var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden;
- var widthAutoChanged = checkCacheAutoForce(widthAuto, _widthAutoCache);
- var wasWidthAuto = !widthAuto && _widthAutoCache;
-
- //detect height auto:
- var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false;
- var heightAutoChanged = checkCacheAutoForce(heightAuto, _heightAutoCache);
- var wasHeightAuto = !heightAuto && _heightAutoCache;
-
- //detect border:
- //we need the border only if border box and auto size
- var strMinusWidth = '-' + _strWidth;
- var updateBorderX = (widthAuto && _isBorderBox) || !_isBorderBox;
- var updateBorderY = (heightAuto && _isBorderBox) || !_isBorderBox;
- var border = {
- c: force,
- t: updateBorderY ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strTop + strMinusWidth), true) : 0,
- r: updateBorderX ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strRight + strMinusWidth), true) : 0,
- b: updateBorderY ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strBottom + strMinusWidth), true) : 0,
- l: updateBorderX ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strLeft + strMinusWidth), true) : 0
- };
-
- //detect margin:
- var margin = {
- c: force,
- t: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strTop)),
- r: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strRight)),
- b: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strBottom)),
- l: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strLeft))
- };
-
- //detect css max width & height:
- var cssMaxValue = {
- h: String(_hostElement.css(_strMaxMinus + _strHeight)),
- w: String(_hostElement.css(_strMaxMinus + _strWidth))
- };
-
- //vars to apply correct css
- var contentElementCSS = {};
- var contentGlueElementCSS = {};
-
- //funcs
- var getHostSize = function () {
- //has to be clientSize because offsetSize respect borders
- return {
- w: _hostElementNative[LEXICON.cW],
- h: _hostElementNative[LEXICON.cH]
- };
- };
- var getViewportSize = function () {
- //viewport size is padding container because it never has padding, margin and a border
- //determine zoom rounding error -> sometimes scrollWidth/Height is smaller than clientWidth/Height
- //if this happens add the difference to the viewportSize to compensate the rounding error
- return {
- w: _paddingElementNative[LEXICON.oW] + MATH.max(0, _contentElementNative[LEXICON.cW] - _contentElementNative[LEXICON.sW]),
- h: _paddingElementNative[LEXICON.oH] + MATH.max(0, _contentElementNative[LEXICON.cH] - _contentElementNative[LEXICON.sH])
- };
- };
-
- //set info for padding
- var paddingAbsoluteX = _paddingX = padding.l + padding.r;
- var paddingAbsoluteY = _paddingY = padding.t + padding.b;
- paddingAbsoluteX *= paddingAbsolute ? 1 : 0;
- paddingAbsoluteY *= paddingAbsolute ? 1 : 0;
- padding.c = checkCacheAutoForce(padding, _cssPaddingCache);
-
- //set info for border
- _borderX = border.l + border.r;
- _borderY = border.t + border.b;
- border.c = checkCacheAutoForce(border, _cssBorderCache);
-
- //set info for margin
- _marginX = margin.l + margin.r;
- _marginY = margin.t + margin.b;
- margin.c = checkCacheAutoForce(margin, _cssMarginCache);
-
- //set info for css max value
- cssMaxValue.ih = parseToZeroOrNumber(cssMaxValue.h); //ih = integer height
- cssMaxValue.iw = parseToZeroOrNumber(cssMaxValue.w); //iw = integer width
- cssMaxValue.ch = cssMaxValue.h.indexOf('px') > -1; //ch = correct height
- cssMaxValue.cw = cssMaxValue.w.indexOf('px') > -1; //cw = correct width
- cssMaxValue.c = checkCacheAutoForce(cssMaxValue, _cssMaxValueCache);
-
- //refresh cache
- _displayIsHiddenCache = displayIsHidden;
- _textareaAutoWrappingCache = textareaAutoWrapping;
- _cssDirectionCache = cssDirection;
- _cssBoxSizingCache = boxSizing;
- _widthAutoCache = widthAuto;
- _heightAutoCache = heightAuto;
- _cssPaddingCache = padding;
- _cssBorderCache = border;
- _cssMarginCache = margin;
- _cssMaxValueCache = cssMaxValue;
-
- //IEFix direction changed
- if (cssDirectionChanged && _sizeAutoObserverAdded)
- _sizeAutoObserverElement.css(_strFloat, isRTLRight);
-
- //apply padding:
- if (padding.c || cssDirectionChanged || paddingAbsoluteChanged || widthAutoChanged || heightAutoChanged || boxSizingChanged || sizeAutoCapableChanged) {
- var paddingElementCSS = {};
- var textareaCSS = {};
- setTopRightBottomLeft(contentGlueElementCSS, _strMarginMinus, [-padding.t, -padding.r, -padding.b, -padding.l]);
- if (paddingAbsolute) {
- setTopRightBottomLeft(paddingElementCSS, _strEmpty, [padding.t, padding.r, padding.b, padding.l]);
- if (_isTextarea)
- setTopRightBottomLeft(textareaCSS, _strPaddingMinus);
- else
- setTopRightBottomLeft(contentElementCSS, _strPaddingMinus);
- }
- else {
- setTopRightBottomLeft(paddingElementCSS, _strEmpty);
- if (_isTextarea)
- setTopRightBottomLeft(textareaCSS, _strPaddingMinus, [padding.t, padding.r, padding.b, padding.l]);
- else
- setTopRightBottomLeft(contentElementCSS, _strPaddingMinus, [padding.t, padding.r, padding.b, padding.l]);
- }
- _paddingElement.css(paddingElementCSS);
- _targetElement.css(textareaCSS);
- }
-
- //viewport size is padding container because it never has padding, margin and a border.
- _viewportSize = getViewportSize();
-
- //update Textarea
- var textareaSize = _isTextarea ? textareaUpdate() : false;
- var textareaSizeChanged = _isTextarea && checkCacheAutoForce(textareaSize, _textareaSizeCache);
- var textareaDynOrigSize = _isTextarea && textareaSize ? {
- w: textareaDynWidth ? textareaSize._dynamicWidth : textareaSize._originalWidth,
- h: textareaDynHeight ? textareaSize._dynamicHeight : textareaSize._originalHeight
- } : {};
- _textareaSizeCache = textareaSize;
-
- //fix height auto / width auto in cooperation with current padding & boxSizing behavior:
- if (heightAuto && (heightAutoChanged || paddingAbsoluteChanged || boxSizingChanged || cssMaxValue.c || padding.c || border.c)) {
- /*
- if (cssMaxValue.ch)
- contentElementCSS[_strMaxMinus + _strHeight] =
- (cssMaxValue.ch ? (cssMaxValue.ih - paddingAbsoluteY + (_isBorderBox ? -_borderY : _paddingY))
- : _strEmpty);
- */
- contentElementCSS[_strHeight] = _strAuto;
- }
- else if (heightAutoChanged || paddingAbsoluteChanged) {
- contentElementCSS[_strMaxMinus + _strHeight] = _strEmpty;
- contentElementCSS[_strHeight] = _strHundredPercent;
- }
- if (widthAuto && (widthAutoChanged || paddingAbsoluteChanged || boxSizingChanged || cssMaxValue.c || padding.c || border.c || cssDirectionChanged)) {
- /*
- if (cssMaxValue.cw)
- contentElementCSS[_strMaxMinus + _strWidth] =
- (cssMaxValue.cw ? (cssMaxValue.iw - paddingAbsoluteX + (_isBorderBox ? -_borderX : _paddingX)) +
- (_nativeScrollbarIsOverlaid.y ? _overlayScrollbarDummySize.y : 0)
- : _strEmpty);
- */
- contentElementCSS[_strWidth] = _strAuto;
- contentGlueElementCSS[_strMaxMinus + _strWidth] = _strHundredPercent; //IE Fix
- }
- else if (widthAutoChanged || paddingAbsoluteChanged) {
- contentElementCSS[_strMaxMinus + _strWidth] = _strEmpty;
- contentElementCSS[_strWidth] = _strHundredPercent;
- contentElementCSS[_strFloat] = _strEmpty;
- contentGlueElementCSS[_strMaxMinus + _strWidth] = _strEmpty; //IE Fix
- }
- if (widthAuto) {
- if (!cssMaxValue.cw)
- contentElementCSS[_strMaxMinus + _strWidth] = _strEmpty;
- //textareaDynOrigSize.w || _strAuto :: doesnt works because applied margin will shift width
- contentGlueElementCSS[_strWidth] = _strAuto;
-
- contentElementCSS[_strWidth] = _strAuto;
- contentElementCSS[_strFloat] = isRTLRight;
- }
- else {
- contentGlueElementCSS[_strWidth] = _strEmpty;
- }
- if (heightAuto) {
- if (!cssMaxValue.ch)
- contentElementCSS[_strMaxMinus + _strHeight] = _strEmpty;
- //textareaDynOrigSize.h || _contentElementNative[LEXICON.cH] :: use for anti scroll jumping
- contentGlueElementCSS[_strHeight] = textareaDynOrigSize.h || _contentElementNative[LEXICON.cH];
- }
- else {
- contentGlueElementCSS[_strHeight] = _strEmpty;
- }
- if (sizeAutoCapable)
- _contentGlueElement.css(contentGlueElementCSS);
- _contentElement.css(contentElementCSS);
-
- //CHECKPOINT HERE ~
- contentElementCSS = {};
- contentGlueElementCSS = {};
-
- //if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true
- if (hostSizeChanged || contentSizeChanged || textareaSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || cssMaxValue.c || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged) {
- var strOverflow = 'overflow';
- var strOverflowX = strOverflow + '-x';
- var strOverflowY = strOverflow + '-y';
- var strHidden = 'hidden';
- var strVisible = 'visible';
-
- //Reset the viewport (very important for natively overlaid scrollbars and zoom change
- //don't change the overflow prop as it is very expensive and affects performance !A LOT!
- if(!_nativeScrollbarStyling) {
- var viewportElementResetCSS = {};
- var resetXTmp = _hasOverflowCache.y && _hideOverflowCache.ys && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.y ? _viewportElement.css(isRTLLeft) : -_nativeScrollbarSize.y) : 0;
- var resetBottomTmp = _hasOverflowCache.x && _hideOverflowCache.xs && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.x ? _viewportElement.css(_strBottom) : -_nativeScrollbarSize.x) : 0;
- setTopRightBottomLeft(viewportElementResetCSS, _strEmpty);
- _viewportElement.css(viewportElementResetCSS);
- }
-
- //measure several sizes:
- var contentMeasureElement = getContentMeasureElement();
- //in Firefox content element has to have overflow hidden, else element margins aren't calculated properly, this element prevents this bug, but only if scrollbars aren't overlaid
- var contentSize = {
- //use clientSize because natively overlaidScrollbars add borders
- w: textareaDynOrigSize.w || contentMeasureElement[LEXICON.cW],
- h: textareaDynOrigSize.h || contentMeasureElement[LEXICON.cH]
- };
- var scrollSize = {
- w: contentMeasureElement[LEXICON.sW],
- h: contentMeasureElement[LEXICON.sH]
- };
-
- //apply the correct viewport style and measure viewport size
- if(!_nativeScrollbarStyling) {
- viewportElementResetCSS[_strBottom] = wasHeightAuto ? _strEmpty : resetBottomTmp;
- viewportElementResetCSS[isRTLLeft] = wasWidthAuto ? _strEmpty : resetXTmp;
- _viewportElement.css(viewportElementResetCSS);
- }
- _viewportSize = getViewportSize();
-
- //measure and correct several sizes
- var hostSize = getHostSize();
- var contentGlueSize = {
- //client/scrollSize + AbsolutePadding -> because padding is only applied to the paddingElement if its absolute, so you have to add it manually
- //hostSize is clientSize -> so padding should be added manually, right? FALSE! Because content glue is inside hostElement, so we don't have to worry about padding
- w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostSize.w),
- h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostSize.h)
- };
- contentGlueSize.c = checkCacheAutoForce(contentGlueSize, _contentGlueSizeCache);
- _contentGlueSizeCache = contentGlueSize;
-
- //apply correct contentGlue size
- if (sizeAutoCapable) {
- //size contentGlue correctly to make sure the element has correct size if the sizing switches to auto
- if (contentGlueSize.c || (heightAuto || widthAuto)) {
- contentGlueElementCSS[_strWidth] = contentGlueSize.w;
- contentGlueElementCSS[_strHeight] = contentGlueSize.h;
-
- //textarea-sizes are already calculated correctly at this point
- if (!_isTextarea) {
- contentSize = {
- //use clientSize because natively overlaidScrollbars add borders
- w: contentMeasureElement[LEXICON.cW],
- h: contentMeasureElement[LEXICON.cH]
- };
- }
- }
- var textareaCoverCSS = {};
- var setContentGlueElementCSSfunction = function (horizontal) {
- var scrollbarVars = getScrollbarVars(horizontal);
- var wh = scrollbarVars._w_h;
- var strWH = scrollbarVars._width_height;
- var autoSize = horizontal ? widthAuto : heightAuto;
- var borderSize = horizontal ? _borderX : _borderY;
- var paddingSize = horizontal ? _paddingX : _paddingY;
- var marginSize = horizontal ? _marginX : _marginY;
- var maxSize = contentGlueElementCSS[strWH] + (_isBorderBox ? borderSize : -paddingSize);
-
- //make contentGlue size -1 if element is not auto sized, to make sure that a resize event happens when the element shrinks
- if (!autoSize || (!autoSize && border.c))
- contentGlueElementCSS[strWH] = hostSize[wh] - (_isBorderBox ? 0 : paddingSize + borderSize) - 1 - marginSize;
-
- //if size is auto and host is same size as max size, make content glue size +1 to make sure size changes will be detected
- if (autoSize && cssMaxValue['c' + wh] && cssMaxValue['i' + wh] === maxSize)
- contentGlueElementCSS[strWH] = maxSize + (_isBorderBox ? 0 : paddingSize) + 1;
-
- //if size is auto and host is smaller than size as min size, make content glue size -1 to make sure size changes will be detected (this is only needed if padding is 0)
- if (autoSize && (contentSize[wh] < _viewportSize[wh]) && (horizontal && _isTextarea ? !textareaAutoWrapping : true)) {
- if (_isTextarea)
- textareaCoverCSS[strWH] = parseToZeroOrNumber(_textareaCoverElement.css(strWH)) - 1;
- contentGlueElementCSS[strWH] -= 1;
- }
-
- //make sure content glue size is at least 1
- if (contentSize[wh] > 0)
- contentGlueElementCSS[strWH] = MATH.max(1, contentGlueElementCSS[strWH]);
- };
- setContentGlueElementCSSfunction(true);
- setContentGlueElementCSSfunction(false);
-
- if (_isTextarea)
- _textareaCoverElement.css(textareaCoverCSS);
- _contentGlueElement.css(contentGlueElementCSS);
- }
- if (widthAuto)
- contentElementCSS[_strWidth] = _strHundredPercent;
- if (widthAuto && !_isBorderBox && !_mutationObserversConnected)
- contentElementCSS[_strFloat] = 'none';
-
- //apply and reset content style
- _contentElement.css(contentElementCSS);
- contentElementCSS = {};
-
- //measure again, but this time all correct sizes:
- var contentScrollSize = {
- w: contentMeasureElement[LEXICON.sW],
- h: contentMeasureElement[LEXICON.sH],
- };
- contentScrollSize.c = contentSizeChanged = checkCacheAutoForce(contentScrollSize, _contentScrollSizeCache);
- _contentScrollSizeCache = contentScrollSize;
-
- //refresh viewport size after correct measuring
- _viewportSize = getViewportSize();
-
- hostSize = getHostSize();
- hostSizeChanged = checkCacheAutoForce(hostSize, _hostSizeCache);
- _hostSizeCache = hostSize;
-
- var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0);
- var previousOverflowAmount = _overflowAmountCache;
- var overflowBehaviorIsVS = {};
- var overflowBehaviorIsVH = {};
- var overflowBehaviorIsS = {};
- var overflowAmount = {};
- var hasOverflow = {};
- var hideOverflow = {};
- var canScroll = {};
- var viewportRect = _paddingElementNative[LEXICON.bCR]();
- var setOverflowVariables = function (horizontal) {
- var scrollbarVars = getScrollbarVars(horizontal);
- var scrollbarVarsInverted = getScrollbarVars(!horizontal);
- var xyI = scrollbarVarsInverted._x_y;
- var xy = scrollbarVars._x_y;
- var wh = scrollbarVars._w_h;
- var widthHeight = scrollbarVars._width_height;
- var scrollMax = _strScroll + scrollbarVars._Left_Top + 'Max';
- var fractionalOverflowAmount = viewportRect[widthHeight] ? MATH.abs(viewportRect[widthHeight] - _viewportSize[wh]) : 0;
- var checkFractionalOverflowAmount = previousOverflowAmount && previousOverflowAmount[xy] > 0 && _viewportElementNative[scrollMax] === 0;
- overflowBehaviorIsVS[xy] = overflowBehavior[xy] === 'v-s';
- overflowBehaviorIsVH[xy] = overflowBehavior[xy] === 'v-h';
- overflowBehaviorIsS[xy] = overflowBehavior[xy] === 's';
- overflowAmount[xy] = MATH.max(0, MATH.round((contentScrollSize[wh] - _viewportSize[wh]) * 100) / 100);
- overflowAmount[xy] *= (hideOverflowForceTextarea || (checkFractionalOverflowAmount && fractionalOverflowAmount > 0 && fractionalOverflowAmount < 1)) ? 0 : 1;
- hasOverflow[xy] = overflowAmount[xy] > 0;
-
- //hideOverflow:
- //x || y : true === overflow is hidden by "overflow: scroll" OR "overflow: hidden"
- //xs || ys : true === overflow is hidden by "overflow: scroll"
- hideOverflow[xy] = overflowBehaviorIsVS[xy] || overflowBehaviorIsVH[xy] ? (hasOverflow[xyI] && !overflowBehaviorIsVS[xyI] && !overflowBehaviorIsVH[xyI]) : hasOverflow[xy];
- hideOverflow[xy + 's'] = hideOverflow[xy] ? (overflowBehaviorIsS[xy] || overflowBehaviorIsVS[xy]) : false;
-
- canScroll[xy] = hasOverflow[xy] && hideOverflow[xy + 's'];
- };
- setOverflowVariables(true);
- setOverflowVariables(false);
-
- overflowAmount.c = checkCacheAutoForce(overflowAmount, _overflowAmountCache);
- _overflowAmountCache = overflowAmount;
- hasOverflow.c = checkCacheAutoForce(hasOverflow, _hasOverflowCache);
- _hasOverflowCache = hasOverflow;
- hideOverflow.c = checkCacheAutoForce(hideOverflow, _hideOverflowCache);
- _hideOverflowCache = hideOverflow;
-
- //if native scrollbar is overlay at x OR y axis, prepare DOM
- if (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) {
- var borderDesign = 'px solid transparent';
- var contentArrangeElementCSS = {};
- var arrangeContent = {};
- var arrangeChanged = force;
- var setContentElementCSS;
-
- if (hasOverflow.x || hasOverflow.y) {
- arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty;
- arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty;
- arrangeChanged = checkCacheAutoForce(arrangeContent, _arrangeContentSizeCache);
- _arrangeContentSizeCache = arrangeContent;
- }
-
- if (hasOverflow.c || hideOverflow.c || contentScrollSize.c || cssDirectionChanged || widthAutoChanged || heightAutoChanged || widthAuto || heightAuto || ignoreOverlayScrollbarHidingChanged) {
- contentElementCSS[_strMarginMinus + isRTLRight] = contentElementCSS[_strBorderMinus + isRTLRight] = _strEmpty;
- setContentElementCSS = function (horizontal) {
- var scrollbarVars = getScrollbarVars(horizontal);
- var scrollbarVarsInverted = getScrollbarVars(!horizontal);
- var xy = scrollbarVars._x_y;
- var strDirection = horizontal ? _strBottom : isRTLLeft;
- var invertedAutoSize = horizontal ? heightAuto : widthAuto;
-
- if (_nativeScrollbarIsOverlaid[xy] && hasOverflow[xy] && hideOverflow[xy + 's']) {
- contentElementCSS[_strMarginMinus + strDirection] = invertedAutoSize ? (ignoreOverlayScrollbarHiding ? _strEmpty : _overlayScrollbarDummySize[xy]) : _strEmpty;
- contentElementCSS[_strBorderMinus + strDirection] = ((horizontal ? !invertedAutoSize : true) && !ignoreOverlayScrollbarHiding) ? (_overlayScrollbarDummySize[xy] + borderDesign) : _strEmpty;
- }
- else {
- arrangeContent[scrollbarVarsInverted._w_h] =
- contentElementCSS[_strMarginMinus + strDirection] =
- contentElementCSS[_strBorderMinus + strDirection] = _strEmpty;
- arrangeChanged = true;
- }
- };
-
- if (_nativeScrollbarStyling) {
- if (ignoreOverlayScrollbarHiding)
- removeClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
- else
- addClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
- }
- else {
- setContentElementCSS(true);
- setContentElementCSS(false);
- }
- }
- if (ignoreOverlayScrollbarHiding) {
- arrangeContent.w = arrangeContent.h = _strEmpty;
- arrangeChanged = true;
- }
- if (arrangeChanged && !_nativeScrollbarStyling) {
- contentArrangeElementCSS[_strWidth] = hideOverflow.y ? arrangeContent.w : _strEmpty;
- contentArrangeElementCSS[_strHeight] = hideOverflow.x ? arrangeContent.h : _strEmpty;
-
- if (!_contentArrangeElement) {
- _contentArrangeElement = FRAMEWORK(generateDiv(_classNameContentArrangeElement));
- _viewportElement.prepend(_contentArrangeElement);
- }
- _contentArrangeElement.css(contentArrangeElementCSS);
- }
- _contentElement.css(contentElementCSS);
- }
-
- var viewportElementCSS = {};
- var paddingElementCSS = {};
- var setViewportCSS;
- if (hostSizeChanged || hasOverflow.c || hideOverflow.c || contentScrollSize.c || overflowBehaviorChanged || boxSizingChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged || clipAlwaysChanged || heightAutoChanged) {
- viewportElementCSS[isRTLRight] = _strEmpty;
- setViewportCSS = function (horizontal) {
- var scrollbarVars = getScrollbarVars(horizontal);
- var scrollbarVarsInverted = getScrollbarVars(!horizontal);
- var xy = scrollbarVars._x_y;
- var XY = scrollbarVars._X_Y;
- var strDirection = horizontal ? _strBottom : isRTLLeft;
-
- var reset = function () {
- viewportElementCSS[strDirection] = _strEmpty;
- _contentBorderSize[scrollbarVarsInverted._w_h] = 0;
- };
- if (hasOverflow[xy] && hideOverflow[xy + 's']) {
- viewportElementCSS[strOverflow + XY] = _strScroll;
- if (ignoreOverlayScrollbarHiding || _nativeScrollbarStyling) {
- reset();
- }
- else {
- viewportElementCSS[strDirection] = -(_nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[xy] : _nativeScrollbarSize[xy]);
- _contentBorderSize[scrollbarVarsInverted._w_h] = _nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[scrollbarVarsInverted._x_y] : 0;
- }
- } else {
- viewportElementCSS[strOverflow + XY] = _strEmpty;
- reset();
- }
- };
- setViewportCSS(true);
- setViewportCSS(false);
-
- // if the scroll container is too small and if there is any overflow with no overlay scrollbar (and scrollbar styling isn't possible),
- // make viewport element greater in size (Firefox hide Scrollbars fix)
- // because firefox starts hiding scrollbars on too small elements
- // with this behavior the overflow calculation may be incorrect or the scrollbars would appear suddenly
- // https://bugzilla.mozilla.org/show_bug.cgi?id=292284
- if (!_nativeScrollbarStyling
- && (_viewportSize.h < _nativeScrollbarMinSize.x || _viewportSize.w < _nativeScrollbarMinSize.y)
- && ((hasOverflow.x && hideOverflow.x && !_nativeScrollbarIsOverlaid.x) || (hasOverflow.y && hideOverflow.y && !_nativeScrollbarIsOverlaid.y))) {
- viewportElementCSS[_strPaddingMinus + _strTop] = _nativeScrollbarMinSize.x;
- viewportElementCSS[_strMarginMinus + _strTop] = -_nativeScrollbarMinSize.x;
-
- viewportElementCSS[_strPaddingMinus + isRTLRight] = _nativeScrollbarMinSize.y;
- viewportElementCSS[_strMarginMinus + isRTLRight] = -_nativeScrollbarMinSize.y;
- }
- else {
- viewportElementCSS[_strPaddingMinus + _strTop] =
- viewportElementCSS[_strMarginMinus + _strTop] =
- viewportElementCSS[_strPaddingMinus + isRTLRight] =
- viewportElementCSS[_strMarginMinus + isRTLRight] = _strEmpty;
- }
- viewportElementCSS[_strPaddingMinus + isRTLLeft] =
- viewportElementCSS[_strMarginMinus + isRTLLeft] = _strEmpty;
-
- //if there is any overflow (x OR y axis) and this overflow shall be hidden, make overflow hidden, else overflow visible
- if ((hasOverflow.x && hideOverflow.x) || (hasOverflow.y && hideOverflow.y) || hideOverflowForceTextarea) {
- //only hide if is Textarea
- if (_isTextarea && hideOverflowForceTextarea) {
- paddingElementCSS[strOverflowX] =
- paddingElementCSS[strOverflowY] = strHidden;
- }
- }
- else {
- if (!clipAlways || (overflowBehaviorIsVH.x || overflowBehaviorIsVS.x || overflowBehaviorIsVH.y || overflowBehaviorIsVS.y)) {
- //only un-hide if Textarea
- if (_isTextarea) {
- paddingElementCSS[strOverflowX] =
- paddingElementCSS[strOverflowY] = _strEmpty;
- }
- viewportElementCSS[strOverflowX] =
- viewportElementCSS[strOverflowY] = strVisible;
- }
- }
-
- _paddingElement.css(paddingElementCSS);
- _viewportElement.css(viewportElementCSS);
- viewportElementCSS = {};
-
- //force soft redraw in webkit because without the scrollbars will may appear because DOM wont be redrawn under special conditions
- if ((hasOverflow.c || boxSizingChanged || widthAutoChanged || heightAutoChanged) && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
- var elementStyle = _contentElementNative[LEXICON.s];
- var dump;
- elementStyle.webkitTransform = 'scale(1)';
- elementStyle.display = 'run-in';
- dump = _contentElementNative[LEXICON.oH];
- elementStyle.display = _strEmpty; //|| dump; //use dump to prevent it from deletion if minify
- elementStyle.webkitTransform = _strEmpty;
- }
- /*
- //force hard redraw in webkit if native overlaid scrollbars shall appear
- if (ignoreOverlayScrollbarHidingChanged && ignoreOverlayScrollbarHiding) {
- _hostElement.hide();
- var dump = _hostElementNative[LEXICON.oH];
- _hostElement.show();
- }
- */
- }
-
- //change to direction RTL and width auto Bugfix in Webkit
- //without this fix, the DOM still thinks the scrollbar is LTR and thus the content is shifted to the left
- contentElementCSS = {};
- if (cssDirectionChanged || widthAutoChanged || heightAutoChanged) {
- if (_isRTL && widthAuto) {
- var floatTmp = _contentElement.css(_strFloat);
- var posLeftWithoutFloat = MATH.round(_contentElement.css(_strFloat, _strEmpty).css(_strLeft, _strEmpty).position().left);
- _contentElement.css(_strFloat, floatTmp);
- var posLeftWithFloat = MATH.round(_contentElement.position().left);
-
- if (posLeftWithoutFloat !== posLeftWithFloat)
- contentElementCSS[_strLeft] = posLeftWithoutFloat;
- }
- else {
- contentElementCSS[_strLeft] = _strEmpty;
- }
- }
- _contentElement.css(contentElementCSS);
-
- //handle scroll position
- if (_isTextarea && contentSizeChanged) {
- var textareaInfo = getTextareaInfo();
- if (textareaInfo) {
- var textareaRowsChanged = _textareaInfoCache === undefined ? true : textareaInfo._rows !== _textareaInfoCache._rows;
- var cursorRow = textareaInfo._cursorRow;
- var cursorCol = textareaInfo._cursorColumn;
- var widestRow = textareaInfo._widestRow;
- var lastRow = textareaInfo._rows;
- var lastCol = textareaInfo._columns;
- var cursorPos = textareaInfo._cursorPosition;
- var cursorMax = textareaInfo._cursorMax;
- var cursorIsLastPosition = (cursorPos >= cursorMax && _textareaHasFocus);
- var textareaScrollAmount = {
- x: (!textareaAutoWrapping && (cursorCol === lastCol && cursorRow === widestRow)) ? _overflowAmountCache.x : -1,
- y: (textareaAutoWrapping ? cursorIsLastPosition || textareaRowsChanged && (previousOverflowAmount ? (currScroll.y === previousOverflowAmount.y) : false) : (cursorIsLastPosition || textareaRowsChanged) && cursorRow === lastRow) ? _overflowAmountCache.y : -1
- };
- currScroll.x = textareaScrollAmount.x > -1 ? (_isRTL && _normalizeRTLCache && _rtlScrollBehavior.i ? 0 : textareaScrollAmount.x) : currScroll.x; //if inverted, scroll to 0 -> normalized this means to max scroll offset.
- currScroll.y = textareaScrollAmount.y > -1 ? textareaScrollAmount.y : currScroll.y;
- }
- _textareaInfoCache = textareaInfo;
- }
- if (_isRTL && _rtlScrollBehavior.i && _nativeScrollbarIsOverlaid.y && hasOverflow.x && _normalizeRTLCache)
- currScroll.x += _contentBorderSize.w || 0;
- if (widthAuto)
- _hostElement[_strScrollLeft](0);
- if (heightAuto)
- _hostElement[_strScrollTop](0);
- _viewportElement[_strScrollLeft](currScroll.x)[_strScrollTop](currScroll.y);
-
- //scrollbars management:
- var scrollbarsVisibilityVisible = scrollbarsVisibility === 'v';
- var scrollbarsVisibilityHidden = scrollbarsVisibility === 'h';
- var scrollbarsVisibilityAuto = scrollbarsVisibility === 'a';
-
- var showScrollbarH = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, true, true, canScroll.x);
- var showScrollbarV = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, false, true, canScroll.y);
- var hideScrollbarH = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, true, false, canScroll.x);
- var hideScrollbarV = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, false, false, canScroll.y);
-
- //manage class name which indicates scrollable overflow
- if (hideOverflow.x || hideOverflow.y)
- addClass(_hostElement, _classNameHostOverflow);
- else
- removeClass(_hostElement, _classNameHostOverflow);
- if (hideOverflow.x)
- addClass(_hostElement, _classNameHostOverflowX);
- else
- removeClass(_hostElement, _classNameHostOverflowX);
- if (hideOverflow.y)
- addClass(_hostElement, _classNameHostOverflowY);
- else
- removeClass(_hostElement, _classNameHostOverflowY);
-
- //add or remove rtl class name for styling purposes
- if (cssDirectionChanged) {
- if (_isRTL)
- addClass(_hostElement, _classNameHostRTL);
- else
- removeClass(_hostElement, _classNameHostRTL);
- }
-
- //manage the resize feature (CSS3 resize "polyfill" for this plugin)
- if (_isBody)
- addClass(_hostElement, _classNameHostResizeDisabled);
- if (resizeChanged) {
- removeClass(_scrollbarCornerElement, [
- _classNameScrollbarCornerResize,
- _classNameScrollbarCornerResizeB,
- _classNameScrollbarCornerResizeH,
- _classNameScrollbarCornerResizeV].join(_strSpace));
- if (_resizeNone) {
- addClass(_hostElement, _classNameHostResizeDisabled);
- }
- else {
- removeClass(_hostElement, _classNameHostResizeDisabled);
- addClass(_scrollbarCornerElement, _classNameScrollbarCornerResize);
- if (_resizeBoth)
- addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeB);
- else if (_resizeHorizontal)
- addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeH);
- else if (_resizeVertical)
- addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV);
- }
- }
-
- //manage the scrollbars general visibility + the scrollbar interactivity (unusable class name)
- if (scrollbarsVisibilityChanged || overflowBehaviorChanged || hideOverflow.c || hasOverflow.c || ignoreOverlayScrollbarHidingChanged) {
- if (ignoreOverlayScrollbarHiding) {
- if (ignoreOverlayScrollbarHidingChanged) {
- removeClass(_hostElement, _classNameHostScrolling);
- if (ignoreOverlayScrollbarHiding) {
- hideScrollbarH();
- hideScrollbarV();
- }
- }
- }
- else if (scrollbarsVisibilityAuto) {
- if (canScroll.x)
- showScrollbarH();
- else
- hideScrollbarH();
-
- if (canScroll.y)
- showScrollbarV();
- else
- hideScrollbarV();
- }
- else if (scrollbarsVisibilityVisible) {
- showScrollbarH();
- showScrollbarV();
- }
- else if (scrollbarsVisibilityHidden) {
- hideScrollbarH();
- hideScrollbarV();
- }
- }
-
- //manage the scrollbars auto hide feature (auto hide them after specific actions)
- if (scrollbarsAutoHideChanged || ignoreOverlayScrollbarHidingChanged) {
- if (_scrollbarsAutoHideLeave || _scrollbarsAutoHideMove) {
- setupHostMouseTouchEvents(true);
- setupHostMouseTouchEvents();
- }
- else {
- setupHostMouseTouchEvents(true);
- }
-
- if (_scrollbarsAutoHideNever)
- refreshScrollbarsAutoHide(true);
- else
- refreshScrollbarsAutoHide(false, true);
- }
-
- //manage scrollbars handle length & offset - don't remove!
- if (hostSizeChanged || overflowAmount.c || heightAutoChanged || widthAutoChanged || resizeChanged || boxSizingChanged || paddingAbsoluteChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged) {
- refreshScrollbarHandleLength(true);
- refreshScrollbarHandleOffset(true);
- refreshScrollbarHandleLength(false);
- refreshScrollbarHandleOffset(false);
- }
-
- //manage interactivity
- if (scrollbarsClickScrollingChanged)
- refreshScrollbarsInteractive(true, scrollbarsClickScrolling);
- if (scrollbarsDragScrollingChanged)
- refreshScrollbarsInteractive(false, scrollbarsDragScrolling);
-
- //callbacks:
- if (cssDirectionChanged) {
- dispatchCallback('onDirectionChanged', {
- isRTL: _isRTL,
- dir: cssDirection
- });
- }
- if (hostSizeChanged) {
- dispatchCallback('onHostSizeChanged', {
- width: _hostSizeCache.w,
- height: _hostSizeCache.h
- });
- }
- if (contentSizeChanged) {
- dispatchCallback('onContentSizeChanged', {
- width: _contentScrollSizeCache.w,
- height: _contentScrollSizeCache.h
- });
- }
- if (hasOverflow.c || hideOverflow.c) {
- dispatchCallback('onOverflowChanged', {
- x: hasOverflow.x,
- y: hasOverflow.y,
- xScrollable: hideOverflow.xs,
- yScrollable: hideOverflow.ys,
- clipped: hideOverflow.x || hideOverflow.y
- });
- }
- if (overflowAmount.c) {
- dispatchCallback('onOverflowAmountChanged', {
- x: overflowAmount.x,
- y: overflowAmount.y
- });
- }
- }
-
- //fix body min size
- if (_isBody && _bodyMinSizeCache && (_hasOverflowCache.c || _bodyMinSizeCache.c)) {
- //its possible that no min size was measured until now, because the content arrange element was just added now, in this case, measure now the min size.
- if (!_bodyMinSizeCache.f)
- bodyMinSizeChanged();
- if (_nativeScrollbarIsOverlaid.y && _hasOverflowCache.x)
- _contentElement.css(_strMinMinus + _strWidth, _bodyMinSizeCache.w + _overlayScrollbarDummySize.y);
- if (_nativeScrollbarIsOverlaid.x && _hasOverflowCache.y)
- _contentElement.css(_strMinMinus + _strHeight, _bodyMinSizeCache.h + _overlayScrollbarDummySize.x);
- _bodyMinSizeCache.c = false;
- }
-
- //freezeResizeObserver(_sizeObserverElement, false);
- //freezeResizeObserver(_sizeAutoObserverElement, false);
-
- dispatchCallback('onUpdated', { forced: force });
- }
-
-
- //==== Options ====//
-
- /**
- * Sets new options but doesn't call the update method.
- * @param newOptions The object which contains the new options.
- * @returns {*} A object which contains the changed options.
- */
- function setOptions(newOptions) {
- var validatedOpts = _pluginsOptions._validate(newOptions, _pluginsOptions._template, true, _currentOptions)
-
- _currentOptions = extendDeep({}, _currentOptions, validatedOpts._default);
- _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, validatedOpts._prepared);
-
- return validatedOpts._prepared;
- }
-
-
- //==== Structure ====//
-
- /**
- * Builds or destroys the wrapper and helper DOM elements.
- * @param destroy Indicates whether the DOM shall be build or destroyed.
- */
- function setupStructureDOM(destroy) {
- var strParent = 'parent';
- var classNameResizeObserverHost = 'os-resize-observer-host';
- var classNameTextareaElementFull = _classNameTextareaElement + _strSpace + _classNameTextInherit;
- var textareaClass = _isTextarea ? _strSpace + _classNameTextInherit : _strEmpty;
- var adoptAttrs = _currentPreparedOptions.textarea.inheritedAttrs;
- var adoptAttrsMap = {};
- var applyAdoptedAttrs = function () {
- var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement;
- each(adoptAttrsMap, function (key, value) {
- if (type(value) == TYPES.s) {
- if (key == LEXICON.c)
- applyAdoptedAttrsElm.addClass(value);
- else
- applyAdoptedAttrsElm.attr(key, value);
- }
- });
- };
- var hostElementClassNames = [
- _classNameHostElement,
- _classNameHostTextareaElement,
- _classNameHostResizeDisabled,
- _classNameHostRTL,
- _classNameHostScrollbarHorizontalHidden,
- _classNameHostScrollbarVerticalHidden,
- _classNameHostTransition,
- _classNameHostScrolling,
- _classNameHostOverflow,
- _classNameHostOverflowX,
- _classNameHostOverflowY,
- _classNameThemeNone,
- _classNameTextareaElement,
- _classNameTextInherit,
- _classNameCache].join(_strSpace);
- var hostElementCSS = {};
-
- //get host element as first element, because that's the most upper element and required for the other elements
- _hostElement = _hostElement || (_isTextarea ? (_domExists ? _targetElement[strParent]()[strParent]()[strParent]()[strParent]() : FRAMEWORK(generateDiv(_classNameHostTextareaElement))) : _targetElement);
- _contentElement = _contentElement || selectOrGenerateDivByClass(_classNameContentElement + textareaClass);
- _viewportElement = _viewportElement || selectOrGenerateDivByClass(_classNameViewportElement + textareaClass);
- _paddingElement = _paddingElement || selectOrGenerateDivByClass(_classNamePaddingElement + textareaClass);
- _sizeObserverElement = _sizeObserverElement || selectOrGenerateDivByClass(classNameResizeObserverHost);
- _textareaCoverElement = _textareaCoverElement || (_isTextarea ? selectOrGenerateDivByClass(_classNameTextareaCoverElement) : undefined);
-
- //on destroy, remove all generated class names from the host element before collecting the adopted attributes
- //to prevent adopting generated class names
- if (destroy)
- removeClass(_hostElement, hostElementClassNames);
-
- //collect all adopted attributes
- adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(_strSpace) : adoptAttrs;
- if (type(adoptAttrs) == TYPES.a && _isTextarea) {
- each(adoptAttrs, function (i, v) {
- if (type(v) == TYPES.s) {
- adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v);
- }
- });
- }
-
- if (!destroy) {
- if (_isTextarea) {
- if (!_currentPreparedOptions.sizeAutoCapable) {
- hostElementCSS[_strWidth] = _targetElement.css(_strWidth);
- hostElementCSS[_strHeight] = _targetElement.css(_strHeight);
- }
-
- if (!_domExists)
- _targetElement.addClass(_classNameTextInherit).wrap(_hostElement);
-
- //jQuery clones elements in wrap functions, so we have to select them again
- _hostElement = _targetElement[strParent]().css(hostElementCSS);
- }
-
- if (!_domExists) {
- //add the correct class to the target element
- addClass(_targetElement, _isTextarea ? classNameTextareaElementFull : _classNameHostElement);
-
- //wrap the content into the generated elements to create the required DOM
- _hostElement.wrapInner(_contentElement)
- .wrapInner(_viewportElement)
- .wrapInner(_paddingElement)
- .prepend(_sizeObserverElement);
-
- //jQuery clones elements in wrap functions, so we have to select them again
- _contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);
- _viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);
- _paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);
-
- if (_isTextarea) {
- _contentElement.prepend(_textareaCoverElement);
- applyAdoptedAttrs();
- }
- }
-
- if (_nativeScrollbarStyling)
- addClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
- if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)
- addClass(_viewportElement, _classNameViewportNativeScrollbarsOverlaid);
- if (_isBody)
- addClass(_htmlElement, _classNameHTMLElement);
-
- _sizeObserverElementNative = _sizeObserverElement[0];
- _hostElementNative = _hostElement[0];
- _paddingElementNative = _paddingElement[0];
- _viewportElementNative = _viewportElement[0];
- _contentElementNative = _contentElement[0];
-
- updateViewportAttrsFromTarget();
- }
- else {
- if (_domExists && _initialized) {
- //clear size observer
- _sizeObserverElement.children().remove();
-
- //remove the style property and classes from already generated elements
- each([_paddingElement, _viewportElement, _contentElement, _textareaCoverElement], function (i, elm) {
- if (elm) {
- removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
- }
- });
-
- //add classes to the host element which was removed previously to match the expected DOM
- addClass(_hostElement, _isTextarea ? _classNameHostTextareaElement : _classNameHostElement);
- }
- else {
- //remove size observer
- remove(_sizeObserverElement);
-
- //unwrap the content to restore DOM
- _contentElement.contents()
- .unwrap()
- .unwrap()
- .unwrap();
-
- if (_isTextarea) {
- _targetElement.unwrap();
- remove(_hostElement);
- remove(_textareaCoverElement);
- applyAdoptedAttrs();
- }
- }
-
- if (_isTextarea)
- _targetElement.removeAttr(LEXICON.s);
-
- if (_isBody)
- removeClass(_htmlElement, _classNameHTMLElement);
- }
- }
-
- /**
- * Adds or removes all wrapper elements interactivity events.
- * @param destroy Indicates whether the Events shall be added or removed.
- */
- function setupStructureEvents() {
- var textareaKeyDownRestrictedKeyCodes = [
- 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, //F1 to F12
- 33, 34, //page up, page down
- 37, 38, 39, 40, //left, up, right, down arrows
- 16, 17, 18, 19, 20, 144 //Shift, Ctrl, Alt, Pause, CapsLock, NumLock
- ];
- var textareaKeyDownKeyCodesList = [];
- var textareaUpdateIntervalID;
- var scrollStopTimeoutId;
- var scrollStopDelay = 175;
- var strFocus = 'focus';
-
- function updateTextarea(doClearInterval) {
- textareaUpdate();
- _base.update(_strAuto);
- if (doClearInterval && _autoUpdateRecommended)
- clearInterval(textareaUpdateIntervalID);
- }
- function textareaOnScroll(event) {
- _targetElement[_strScrollLeft](_rtlScrollBehavior.i && _normalizeRTLCache ? 9999999 : 0);
- _targetElement[_strScrollTop](0);
- COMPATIBILITY.prvD(event);
- COMPATIBILITY.stpP(event);
- return false;
- }
- function textareaOnDrop(event) {
- setTimeout(function () {
- if (!_destroyed)
- updateTextarea();
- }, 50);
- }
- function textareaOnFocus() {
- _textareaHasFocus = true;
- addClass(_hostElement, strFocus);
- }
- function textareaOnFocusout() {
- _textareaHasFocus = false;
- textareaKeyDownKeyCodesList = [];
- removeClass(_hostElement, strFocus);
- updateTextarea(true);
- }
- function textareaOnKeyDown(event) {
- var keyCode = event.keyCode;
-
- if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {
- if (!textareaKeyDownKeyCodesList[LEXICON.l]) {
- updateTextarea();
- textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60);
- }
- if (inArray(keyCode, textareaKeyDownKeyCodesList) < 0)
- textareaKeyDownKeyCodesList.push(keyCode);
- }
- }
- function textareaOnKeyUp(event) {
- var keyCode = event.keyCode;
- var index = inArray(keyCode, textareaKeyDownKeyCodesList);
-
- if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {
- if (index > -1)
- textareaKeyDownKeyCodesList.splice(index, 1);
- if (!textareaKeyDownKeyCodesList[LEXICON.l])
- updateTextarea(true);
- }
- }
- function contentOnTransitionEnd(event) {
- if (_autoUpdateCache === true)
- return;
- event = event.originalEvent || event;
- if (isSizeAffectingCSSProperty(event.propertyName))
- _base.update(_strAuto);
- }
- function viewportOnScroll(event) {
- if (!_sleeping) {
- if (scrollStopTimeoutId !== undefined)
- clearTimeout(scrollStopTimeoutId);
- else {
- if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
- refreshScrollbarsAutoHide(true);
-
- if (!nativeOverlayScrollbarsAreActive())
- addClass(_hostElement, _classNameHostScrolling);
-
- dispatchCallback('onScrollStart', event);
- }
-
- //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset
- //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point
- //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove
- if (!_scrollbarsHandlesDefineScrollPos) {
- refreshScrollbarHandleOffset(true);
- refreshScrollbarHandleOffset(false);
- }
- dispatchCallback('onScroll', event);
-
- scrollStopTimeoutId = setTimeout(function () {
- if (!_destroyed) {
- //OnScrollStop:
- clearTimeout(scrollStopTimeoutId);
- scrollStopTimeoutId = undefined;
-
- if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
- refreshScrollbarsAutoHide(false);
-
- if (!nativeOverlayScrollbarsAreActive())
- removeClass(_hostElement, _classNameHostScrolling);
-
- dispatchCallback('onScrollStop', event);
- }
- }, scrollStopDelay);
- }
- }
-
-
- if (_isTextarea) {
- if (_msieVersion > 9 || !_autoUpdateRecommended) {
- addDestroyEventListener(_targetElement, 'input', updateTextarea);
- }
- else {
- addDestroyEventListener(_targetElement,
- [_strKeyDownEvent, _strKeyUpEvent],
- [textareaOnKeyDown, textareaOnKeyUp]);
- }
-
- addDestroyEventListener(_targetElement,
- [_strScroll, 'drop', strFocus, strFocus + 'out'],
- [textareaOnScroll, textareaOnDrop, textareaOnFocus, textareaOnFocusout]);
- }
- else {
- addDestroyEventListener(_contentElement, _strTransitionEndEvent, contentOnTransitionEnd);
- }
- addDestroyEventListener(_viewportElement, _strScroll, viewportOnScroll, true);
- }
-
-
- //==== Scrollbars ====//
-
- /**
- * Builds or destroys all scrollbar DOM elements (scrollbar, track, handle)
- * @param destroy Indicates whether the DOM shall be build or destroyed.
- */
- function setupScrollbarsDOM(destroy) {
- var selectOrGenerateScrollbarDOM = function (isHorizontal) {
- var scrollbarClassName = isHorizontal ? _classNameScrollbarHorizontal : _classNameScrollbarVertical;
- var scrollbar = selectOrGenerateDivByClass(_classNameScrollbar + _strSpace + scrollbarClassName, true);
- var track = selectOrGenerateDivByClass(_classNameScrollbarTrack, scrollbar);
- var handle = selectOrGenerateDivByClass(_classNameScrollbarHandle, scrollbar);
-
- if (!_domExists && !destroy) {
- scrollbar.append(track);
- track.append(handle);
- }
-
- return {
- _scrollbar: scrollbar,
- _track: track,
- _handle: handle
- };
- };
- function resetScrollbarDOM(isHorizontal) {
- var scrollbarVars = getScrollbarVars(isHorizontal);
- var scrollbar = scrollbarVars._scrollbar;
- var track = scrollbarVars._track;
- var handle = scrollbarVars._handle;
-
- if (_domExists && _initialized) {
- each([scrollbar, track, handle], function (i, elm) {
- removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
- });
- }
- else {
- remove(scrollbar || selectOrGenerateScrollbarDOM(isHorizontal)._scrollbar);
- }
- }
- var horizontalElements;
- var verticalElements;
-
- if (!destroy) {
- horizontalElements = selectOrGenerateScrollbarDOM(true);
- verticalElements = selectOrGenerateScrollbarDOM();
-
- _scrollbarHorizontalElement = horizontalElements._scrollbar;
- _scrollbarHorizontalTrackElement = horizontalElements._track;
- _scrollbarHorizontalHandleElement = horizontalElements._handle;
- _scrollbarVerticalElement = verticalElements._scrollbar;
- _scrollbarVerticalTrackElement = verticalElements._track;
- _scrollbarVerticalHandleElement = verticalElements._handle;
-
- if (!_domExists) {
- _paddingElement.after(_scrollbarVerticalElement);
- _paddingElement.after(_scrollbarHorizontalElement);
- }
- }
- else {
- resetScrollbarDOM(true);
- resetScrollbarDOM();
- }
- }
-
- /**
- * Initializes all scrollbar interactivity events. (track and handle dragging, clicking, scrolling)
- * @param isHorizontal True if the target scrollbar is the horizontal scrollbar, false if the target scrollbar is the vertical scrollbar.
- */
- function setupScrollbarEvents(isHorizontal) {
- var scrollbarVars = getScrollbarVars(isHorizontal);
- var scrollbarVarsInfo = scrollbarVars._info;
- var insideIFrame = _windowElementNative.top !== _windowElementNative;
- var xy = scrollbarVars._x_y;
- var XY = scrollbarVars._X_Y;
- var scroll = _strScroll + scrollbarVars._Left_Top;
- var strActive = 'active';
- var strSnapHandle = 'snapHandle';
- var scrollDurationFactor = 1;
- var increaseDecreaseScrollAmountKeyCodes = [16, 17]; //shift, ctrl
- var trackTimeout;
- var mouseDownScroll;
- var mouseDownOffset;
- var mouseDownInvertedScale;
-
- function getPointerPosition(event) {
- return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames.
- }
- function getPreparedScrollbarsOption(name) {
- return _currentPreparedOptions.scrollbars[name];
- }
- function increaseTrackScrollAmount() {
- scrollDurationFactor = 0.5;
- }
- function decreaseTrackScrollAmount() {
- scrollDurationFactor = 1;
- }
- function documentKeyDown(event) {
- if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
- increaseTrackScrollAmount();
- }
- function documentKeyUp(event) {
- if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
- decreaseTrackScrollAmount();
- }
- function onMouseTouchDownContinue(event) {
- var originalEvent = event.originalEvent || event;
- var isTouchEvent = originalEvent.touches !== undefined;
- return _sleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
- }
- function documentDragMove(event) {
- if (onMouseTouchDownContinue(event)) {
- var trackLength = scrollbarVarsInfo._trackLength;
- var handleLength = scrollbarVarsInfo._handleLength;
- var scrollRange = scrollbarVarsInfo._maxScroll;
- var scrollRaw = (getPointerPosition(event) - mouseDownOffset) * mouseDownInvertedScale;
- var scrollDeltaPercent = scrollRaw / (trackLength - handleLength);
- var scrollDelta = (scrollRange * scrollDeltaPercent);
- scrollDelta = isFinite(scrollDelta) ? scrollDelta : 0;
- if (_isRTL && isHorizontal && !_rtlScrollBehavior.i)
- scrollDelta *= -1;
-
- _viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta));
-
- if (_scrollbarsHandlesDefineScrollPos)
- refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta);
-
- if (!_supportPassiveEvents)
- COMPATIBILITY.prvD(event);
- }
- else
- documentMouseTouchUp(event);
- }
- function documentMouseTouchUp(event) {
- event = event || event.originalEvent;
-
- setupResponsiveEventListener(_documentElement,
- [_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],
- [documentDragMove, documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart],
- true);
-
- if (_scrollbarsHandlesDefineScrollPos)
- refreshScrollbarHandleOffset(isHorizontal, true);
-
- _scrollbarsHandlesDefineScrollPos = false;
- removeClass(_bodyElement, _classNameDragging);
- removeClass(scrollbarVars._handle, strActive);
- removeClass(scrollbarVars._track, strActive);
- removeClass(scrollbarVars._scrollbar, strActive);
-
- mouseDownScroll = undefined;
- mouseDownOffset = undefined;
- mouseDownInvertedScale = 1;
-
- decreaseTrackScrollAmount();
-
- if (trackTimeout !== undefined) {
- _base.scrollStop();
- clearTimeout(trackTimeout);
- trackTimeout = undefined;
- }
-
- if (event) {
- var rect = _hostElementNative[LEXICON.bCR]();
- var mouseInsideHost = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
-
- //if mouse is outside host element
- if (!mouseInsideHost)
- hostOnMouseLeave();
-
- if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
- refreshScrollbarsAutoHide(false);
- }
- }
- function onHandleMouseTouchDown(event) {
- if (onMouseTouchDownContinue(event))
- onHandleMouseTouchDownAction(event);
- }
- function onHandleMouseTouchDownAction(event) {
- mouseDownScroll = _viewportElement[scroll]();
- mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll;
- if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL)
- mouseDownScroll = mouseDownScroll < 0 ? 0 : mouseDownScroll;
-
- mouseDownInvertedScale = getHostElementInvertedScale()[xy];
- mouseDownOffset = getPointerPosition(event);
-
- _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);
- addClass(_bodyElement, _classNameDragging);
- addClass(scrollbarVars._handle, strActive);
- addClass(scrollbarVars._scrollbar, strActive);
-
- setupResponsiveEventListener(_documentElement,
- [_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strSelectStartEvent],
- [documentDragMove, documentMouseTouchUp, documentOnSelectStart]);
-
- if (_msieVersion || !_documentMixed)
- COMPATIBILITY.prvD(event);
- COMPATIBILITY.stpP(event);
- }
- function onTrackMouseTouchDown(event) {
- if (onMouseTouchDownContinue(event)) {
- var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h]);
- var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top];
- var ctrlKey = event.ctrlKey;
- var instantScroll = event.shiftKey;
- var instantScrollTransition = instantScroll && ctrlKey;
- var isFirstIteration = true;
- var easing = 'linear';
- var decreaseScroll;
- var finishedCondition;
- var scrollActionFinsished = function (transition) {
- if (_scrollbarsHandlesDefineScrollPos)
- refreshScrollbarHandleOffset(isHorizontal, transition);
- };
- var scrollActionInstantFinished = function () {
- scrollActionFinsished();
- onHandleMouseTouchDownAction(event);
- };
- var scrollAction = function () {
- if (!_destroyed) {
- var mouseOffset = (mouseDownOffset - trackOffset) * mouseDownInvertedScale;
- var handleOffset = scrollbarVarsInfo._handleOffset;
- var trackLength = scrollbarVarsInfo._trackLength;
- var handleLength = scrollbarVarsInfo._handleLength;
- var scrollRange = scrollbarVarsInfo._maxScroll;
- var currScroll = scrollbarVarsInfo._currentScroll;
- var scrollDuration = 270 * scrollDurationFactor;
- var timeoutDelay = isFirstIteration ? MATH.max(400, scrollDuration) : scrollDuration;
- var instantScrollPosition = scrollRange * ((mouseOffset - (handleLength / 2)) / (trackLength - handleLength)); // 100% * positionPercent
- var rtlIsNormal = _isRTL && isHorizontal && ((!_rtlScrollBehavior.i && !_rtlScrollBehavior.n) || _normalizeRTLCache);
- var decreaseScrollCondition = rtlIsNormal ? handleOffset < mouseOffset : handleOffset > mouseOffset;
- var scrollObj = {};
- var animationObj = {
- easing: easing,
- step: function (now) {
- if (_scrollbarsHandlesDefineScrollPos) {
- _viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/4340
- refreshScrollbarHandleOffset(isHorizontal, now);
- }
- }
- };
- instantScrollPosition = isFinite(instantScrollPosition) ? instantScrollPosition : 0;
- instantScrollPosition = _isRTL && isHorizontal && !_rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
-
- //_base.scrollStop();
-
- if (instantScroll) {
- _viewportElement[scroll](instantScrollPosition); //scroll instantly to new position
- if (instantScrollTransition) {
- //get the scroll position after instant scroll (in case CSS Snap Points are used) to get the correct snapped scroll position
- //and the animation stops at the correct point
- instantScrollPosition = _viewportElement[scroll]();
- //scroll back to the position before instant scrolling so animation can be performed
- _viewportElement[scroll](currScroll);
-
- instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
- instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.n ? -instantScrollPosition : instantScrollPosition;
-
- scrollObj[xy] = instantScrollPosition;
- _base.scroll(scrollObj, extendDeep(animationObj, {
- duration: 130,
- complete: scrollActionInstantFinished
- }));
- }
- else
- scrollActionInstantFinished();
- }
- else {
- decreaseScroll = isFirstIteration ? decreaseScrollCondition : decreaseScroll;
- finishedCondition = rtlIsNormal
- ? (decreaseScroll ? handleOffset + handleLength >= mouseOffset : handleOffset <= mouseOffset)
- : (decreaseScroll ? handleOffset <= mouseOffset : handleOffset + handleLength >= mouseOffset);
-
- if (finishedCondition) {
- clearTimeout(trackTimeout);
- _base.scrollStop();
- trackTimeout = undefined;
- scrollActionFinsished(true);
- }
- else {
- trackTimeout = setTimeout(scrollAction, timeoutDelay);
-
- scrollObj[xy] = (decreaseScroll ? '-=' : '+=') + scrollDistance;
- _base.scroll(scrollObj, extendDeep(animationObj, {
- duration: scrollDuration
- }));
- }
- isFirstIteration = false;
- }
- }
- };
- if (ctrlKey)
- increaseTrackScrollAmount();
-
- mouseDownInvertedScale = getHostElementInvertedScale()[xy];
- mouseDownOffset = COMPATIBILITY.page(event)[xy];
-
- _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);
- addClass(_bodyElement, _classNameDragging);
- addClass(scrollbarVars._track, strActive);
- addClass(scrollbarVars._scrollbar, strActive);
-
- setupResponsiveEventListener(_documentElement,
- [_strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],
- [documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart]);
-
- scrollAction();
- COMPATIBILITY.prvD(event);
- COMPATIBILITY.stpP(event);
- }
- }
- function onTrackMouseTouchEnter(event) {
- //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move".
- _scrollbarsHandleHovered = true;
- if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
- refreshScrollbarsAutoHide(true);
- }
- function onTrackMouseTouchLeave(event) {
- _scrollbarsHandleHovered = false;
- if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
- refreshScrollbarsAutoHide(false);
- }
- function onScrollbarMouseTouchDown(event) {
- COMPATIBILITY.stpP(event);
- }
-
- addDestroyEventListener(scrollbarVars._handle,
- _strMouseTouchDownEvent,
- onHandleMouseTouchDown);
- addDestroyEventListener(scrollbarVars._track,
- [_strMouseTouchDownEvent, _strMouseTouchEnter, _strMouseTouchLeave],
- [onTrackMouseTouchDown, onTrackMouseTouchEnter, onTrackMouseTouchLeave]);
- addDestroyEventListener(scrollbarVars._scrollbar,
- _strMouseTouchDownEvent,
- onScrollbarMouseTouchDown);
-
- if (_supportTransition) {
- addDestroyEventListener(scrollbarVars._scrollbar, _strTransitionEndEvent, function (event) {
- if (event.target !== scrollbarVars._scrollbar[0])
- return;
- refreshScrollbarHandleLength(isHorizontal);
- refreshScrollbarHandleOffset(isHorizontal);
- });
- }
- }
-
- /**
- * Shows or hides the given scrollbar and applied a class name which indicates if the scrollbar is scrollable or not.
- * @param isHorizontal True if the horizontal scrollbar is the target, false if the vertical scrollbar is the target.
- * @param shallBeVisible True if the scrollbar shall be shown, false if hidden.
- * @param canScroll True if the scrollbar is scrollable, false otherwise.
- */
- function refreshScrollbarAppearance(isHorizontal, shallBeVisible, canScroll) {
- var scrollbarClassName = isHorizontal ? _classNameHostScrollbarHorizontalHidden : _classNameHostScrollbarVerticalHidden;
- var scrollbarElement = isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement;
-
- if (shallBeVisible)
- removeClass(_hostElement, scrollbarClassName);
- else
- addClass(_hostElement, scrollbarClassName);
-
- if (canScroll)
- removeClass(scrollbarElement, _classNameScrollbarUnusable);
- else
- addClass(scrollbarElement, _classNameScrollbarUnusable);
- }
-
- /**
- * Autoshows / autohides both scrollbars with.
- * @param shallBeVisible True if the scrollbars shall be autoshown (only the case if they are hidden by a autohide), false if the shall be auto hidden.
- * @param delayfree True if the scrollbars shall be hidden without a delay, false or undefined otherwise.
- */
- function refreshScrollbarsAutoHide(shallBeVisible, delayfree) {
- clearTimeout(_scrollbarsAutoHideTimeoutId);
- if (shallBeVisible) {
- //if(_hasOverflowCache.x && _hideOverflowCache.xs)
- removeClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
- //if(_hasOverflowCache.y && _hideOverflowCache.ys)
- removeClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
- }
- else {
- var anyActive;
- var strActive = 'active';
- var hide = function () {
- if (!_scrollbarsHandleHovered && !_destroyed) {
- anyActive = _scrollbarHorizontalHandleElement.hasClass(strActive) || _scrollbarVerticalHandleElement.hasClass(strActive);
- if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
- addClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
- if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
- addClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
- }
- };
- if (_scrollbarsAutoHideDelay > 0 && delayfree !== true)
- _scrollbarsAutoHideTimeoutId = setTimeout(hide, _scrollbarsAutoHideDelay);
- else
- hide();
- }
- }
-
- /**
- * Refreshes the handle length of the given scrollbar.
- * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
- */
- function refreshScrollbarHandleLength(isHorizontal) {
- var handleCSS = {};
- var scrollbarVars = getScrollbarVars(isHorizontal);
- var scrollbarVarsInfo = scrollbarVars._info;
- var digit = 1000000;
- //get and apply intended handle length
- var handleRatio = MATH.min(1, (_hostSizeCache[scrollbarVars._w_h] - (_paddingAbsoluteCache ? (isHorizontal ? _paddingX : _paddingY) : 0)) / _contentScrollSizeCache[scrollbarVars._w_h]);
- handleCSS[scrollbarVars._width_height] = (MATH.floor(handleRatio * 100 * digit) / digit) + '%'; //the last * digit / digit is for flooring to the 4th digit
-
- if (!nativeOverlayScrollbarsAreActive())
- scrollbarVars._handle.css(handleCSS);
-
- //measure the handle length to respect min & max length
- scrollbarVarsInfo._handleLength = scrollbarVars._handle[0]['offset' + scrollbarVars._Width_Height];
- scrollbarVarsInfo._handleLengthRatio = handleRatio;
- }
-
- /**
- * Refreshes the handle offset of the given scrollbar.
- * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
- * @param scrollOrTransition The scroll position of the given scrollbar axis to which the handle shall be moved or a boolean which indicates whether a transition shall be applied. If undefined or boolean if the current scroll-offset is taken. (if isHorizontal ? scrollLeft : scrollTop)
- */
- function refreshScrollbarHandleOffset(isHorizontal, scrollOrTransition) {
- var transition = type(scrollOrTransition) == TYPES.b;
- var transitionDuration = 250;
- var isRTLisHorizontal = _isRTL && isHorizontal;
- var scrollbarVars = getScrollbarVars(isHorizontal);
- var scrollbarVarsInfo = scrollbarVars._info;
- var strTranslateBrace = 'translate(';
- var strTransform = VENDORS._cssProperty('transform');
- var strTransition = VENDORS._cssProperty('transition');
- var nativeScroll = isHorizontal ? _viewportElement[_strScrollLeft]() : _viewportElement[_strScrollTop]();
- var currentScroll = scrollOrTransition === undefined || transition ? nativeScroll : scrollOrTransition;
-
- //measure the handle length to respect min & max length
- var handleLength = scrollbarVarsInfo._handleLength;
- var trackLength = scrollbarVars._track[0]['offset' + scrollbarVars._Width_Height];
- var handleTrackDiff = trackLength - handleLength;
- var handleCSS = {};
- var transformOffset;
- var translateValue;
-
- //DONT use the variable '_contentScrollSizeCache[scrollbarVars._w_h]' instead of '_viewportElement[0]['scroll' + scrollbarVars._Width_Height]'
- // because its a bit behind during the small delay when content size updates
- //(delay = mutationObserverContentLag, if its 0 then this var could be used)
- var maxScroll = (_viewportElementNative[_strScroll + scrollbarVars._Width_Height] - _viewportElementNative['client' + scrollbarVars._Width_Height]) * (_rtlScrollBehavior.n && isRTLisHorizontal ? -1 : 1); //* -1 if rtl scroll max is negative
- var getScrollRatio = function (base) {
- return isNaN(base / maxScroll) ? 0 : MATH.max(0, MATH.min(1, base / maxScroll));
- };
- var getHandleOffset = function (scrollRatio) {
- var offset = handleTrackDiff * scrollRatio;
- offset = isNaN(offset) ? 0 : offset;
- offset = (isRTLisHorizontal && !_rtlScrollBehavior.i) ? (trackLength - handleLength - offset) : offset;
- offset = MATH.max(0, offset);
- return offset;
- };
- var scrollRatio = getScrollRatio(nativeScroll);
- var unsnappedScrollRatio = getScrollRatio(currentScroll);
- var handleOffset = getHandleOffset(unsnappedScrollRatio);
- var snappedHandleOffset = getHandleOffset(scrollRatio);
-
- scrollbarVarsInfo._maxScroll = maxScroll;
- scrollbarVarsInfo._currentScroll = nativeScroll;
- scrollbarVarsInfo._currentScrollRatio = scrollRatio;
-
- if (_supportTransform) {
- transformOffset = isRTLisHorizontal ? -(trackLength - handleLength - handleOffset) : handleOffset; //in px
- //transformOffset = (transformOffset / trackLength * 100) * (trackLength / handleLength); //in %
- translateValue = isHorizontal ? strTranslateBrace + transformOffset + 'px, 0)' : strTranslateBrace + '0, ' + transformOffset + 'px)';
-
- handleCSS[strTransform] = translateValue;
-
- //apply or clear up transition
- if (_supportTransition)
- handleCSS[strTransition] = transition && MATH.abs(handleOffset - scrollbarVarsInfo._handleOffset) > 1 ? getCSSTransitionString(scrollbarVars._handle) + ', ' + (strTransform + _strSpace + transitionDuration + 'ms') : _strEmpty;
- }
- else
- handleCSS[scrollbarVars._left_top] = handleOffset;
-
-
- //only apply css if offset has changed and overflow exists.
- if (!nativeOverlayScrollbarsAreActive()) {
- scrollbarVars._handle.css(handleCSS);
-
- //clear up transition
- if (_supportTransform && _supportTransition && transition) {
- scrollbarVars._handle.one(_strTransitionEndEvent, function () {
- if (!_destroyed)
- scrollbarVars._handle.css(strTransition, _strEmpty);
- });
- }
- }
-
- scrollbarVarsInfo._handleOffset = handleOffset;
- scrollbarVarsInfo._snappedHandleOffset = snappedHandleOffset;
- scrollbarVarsInfo._trackLength = trackLength;
- }
-
- /**
- * Refreshes the interactivity of the given scrollbar element.
- * @param isTrack True if the track element is the target, false if the handle element is the target.
- * @param value True for interactivity false for no interactivity.
- */
- function refreshScrollbarsInteractive(isTrack, value) {
- var action = value ? 'removeClass' : 'addClass';
- var element1 = isTrack ? _scrollbarHorizontalTrackElement : _scrollbarHorizontalHandleElement;
- var element2 = isTrack ? _scrollbarVerticalTrackElement : _scrollbarVerticalHandleElement;
- var className = isTrack ? _classNameScrollbarTrackOff : _classNameScrollbarHandleOff;
-
- element1[action](className);
- element2[action](className);
- }
-
- /**
- * Returns a object which is used for fast access for specific variables.
- * @param isHorizontal True if the horizontal scrollbar vars shall be accessed, false if the vertical scrollbar vars shall be accessed.
- * @returns {{wh: string, WH: string, lt: string, _wh: string, _lt: string, t: *, h: *, c: {}, s: *}}
- */
- function getScrollbarVars(isHorizontal) {
- return {
- _width_height: isHorizontal ? _strWidth : _strHeight,
- _Width_Height: isHorizontal ? 'Width' : 'Height',
- _left_top: isHorizontal ? _strLeft : _strTop,
- _Left_Top: isHorizontal ? 'Left' : 'Top',
- _x_y: isHorizontal ? _strX : _strY,
- _X_Y: isHorizontal ? 'X' : 'Y',
- _w_h: isHorizontal ? 'w' : 'h',
- _l_t: isHorizontal ? 'l' : 't',
- _track: isHorizontal ? _scrollbarHorizontalTrackElement : _scrollbarVerticalTrackElement,
- _handle: isHorizontal ? _scrollbarHorizontalHandleElement : _scrollbarVerticalHandleElement,
- _scrollbar: isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement,
- _info: isHorizontal ? _scrollHorizontalInfo : _scrollVerticalInfo
- };
- }
-
-
- //==== Scrollbar Corner ====//
-
- /**
- * Builds or destroys the scrollbar corner DOM element.
- * @param destroy Indicates whether the DOM shall be build or destroyed.
- */
- function setupScrollbarCornerDOM(destroy) {
- _scrollbarCornerElement = _scrollbarCornerElement || selectOrGenerateDivByClass(_classNameScrollbarCorner, true);
-
- if (!destroy) {
- if (!_domExists) {
- _hostElement.append(_scrollbarCornerElement);
- }
- }
- else {
- if (_domExists && _initialized) {
- removeClass(_scrollbarCornerElement.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
- }
- else {
- remove(_scrollbarCornerElement);
- }
- }
- }
-
- /**
- * Initializes all scrollbar corner interactivity events.
- */
- function setupScrollbarCornerEvents() {
- var insideIFrame = _windowElementNative.top !== _windowElementNative;
- var mouseDownPosition = {};
- var mouseDownSize = {};
- var mouseDownInvertedScale = {};
- var reconnectMutationObserver;
-
- function documentDragMove(event) {
- if (onMouseTouchDownContinue(event)) {
- var pageOffset = getCoordinates(event);
- var hostElementCSS = {};
- if (_resizeHorizontal || _resizeBoth)
- hostElementCSS[_strWidth] = (mouseDownSize.w + (pageOffset.x - mouseDownPosition.x) * mouseDownInvertedScale.x);
- if (_resizeVertical || _resizeBoth)
- hostElementCSS[_strHeight] = (mouseDownSize.h + (pageOffset.y - mouseDownPosition.y) * mouseDownInvertedScale.y);
- _hostElement.css(hostElementCSS);
- COMPATIBILITY.stpP(event);
- }
- else {
- documentMouseTouchUp(event);
- }
- }
- function documentMouseTouchUp(event) {
- var eventIsTrusted = event !== undefined;
-
- setupResponsiveEventListener(_documentElement,
- [_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],
- [documentOnSelectStart, documentDragMove, documentMouseTouchUp],
- true);
-
- removeClass(_bodyElement, _classNameDragging);
- if (_scrollbarCornerElement.releaseCapture)
- _scrollbarCornerElement.releaseCapture();
-
- if (eventIsTrusted) {
- if (reconnectMutationObserver)
- connectMutationObservers();
- _base.update(_strAuto);
- }
- reconnectMutationObserver = false;
- }
- function onMouseTouchDownContinue(event) {
- var originalEvent = event.originalEvent || event;
- var isTouchEvent = originalEvent.touches !== undefined;
- return _sleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
- }
- function getCoordinates(event) {
- return _msieVersion && insideIFrame ? { x: event.screenX, y: event.screenY } : COMPATIBILITY.page(event);
- }
-
- addDestroyEventListener(_scrollbarCornerElement, _strMouseTouchDownEvent, function (event) {
- if (onMouseTouchDownContinue(event) && !_resizeNone) {
- if (_mutationObserversConnected) {
- reconnectMutationObserver = true;
- disconnectMutationObservers();
- }
-
- mouseDownPosition = getCoordinates(event);
-
- mouseDownSize.w = _hostElementNative[LEXICON.oW] - (!_isBorderBox ? _paddingX : 0);
- mouseDownSize.h = _hostElementNative[LEXICON.oH] - (!_isBorderBox ? _paddingY : 0);
- mouseDownInvertedScale = getHostElementInvertedScale();
-
- setupResponsiveEventListener(_documentElement,
- [_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],
- [documentOnSelectStart, documentDragMove, documentMouseTouchUp]);
-
- addClass(_bodyElement, _classNameDragging);
- if (_scrollbarCornerElement.setCapture)
- _scrollbarCornerElement.setCapture();
-
- COMPATIBILITY.prvD(event);
- COMPATIBILITY.stpP(event);
- }
- });
- }
-
-
- //==== Utils ====//
-
- /**
- * Calls the callback with the given name. The Context of this callback is always _base (this).
- * @param name The name of the target which shall be called.
- * @param args The args with which the callback shall be called.
- */
- function dispatchCallback(name, args) {
- if (_initialized) {
- var callback = _currentPreparedOptions.callbacks[name];
- var extensionOnName = name;
- var ext;
-
- if (extensionOnName.substr(0, 2) === 'on')
- extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3);
-
- if (type(callback) == TYPES.f)
- callback.call(_base, args);
-
- each(_extensions, function () {
- ext = this;
- if (type(ext.on) == TYPES.f)
- ext.on(extensionOnName, args);
- });
- }
- else if (!_destroyed)
- _callbacksInitQeueue.push({ n: name, a: args });
- }
-
- /**
- * Sets the "top, right, bottom, left" properties, with a given prefix, of the given css object.
- * @param targetCSSObject The css object to which the values shall be applied.
- * @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
- * @param values A array of values which shall be applied to the "top, right, bottom, left" -properties. The array order is [top, right, bottom, left].
- * If this argument is undefined the value '' (empty string) will be applied to all properties.
- */
- function setTopRightBottomLeft(targetCSSObject, prefix, values) {
- if (values === undefined)
- values = [_strEmpty, _strEmpty, _strEmpty, _strEmpty];
-
- targetCSSObject[prefix + _strTop] = values[0];
- targetCSSObject[prefix + _strRight] = values[1];
- targetCSSObject[prefix + _strBottom] = values[2];
- targetCSSObject[prefix + _strLeft] = values[3];
- }
-
- /**
- * Returns the computed CSS transition string from the given element.
- * @param element The element from which the transition string shall be returned.
- * @returns {string} The CSS transition string from the given element.
- */
- function getCSSTransitionString(element) {
- var transitionStr = VENDORS._cssProperty('transition');
- var assembledValue = element.css(transitionStr);
- if (assembledValue)
- return assembledValue;
- var regExpString = '\\s*(' + '([^,(]+(\\(.+?\\))?)+' + ')[\\s,]*';
- var regExpMain = new RegExp(regExpString);
- var regExpValidate = new RegExp('^(' + regExpString + ')+$');
- var properties = 'property duration timing-function delay'.split(' ');
- var result = [];
- var strResult;
- var valueArray;
- var i = 0;
- var j;
- var splitCssStyleByComma = function (str) {
- strResult = [];
- if (!str.match(regExpValidate))
- return str;
- while (str.match(regExpMain)) {
- strResult.push(RegExp.$1);
- str = str.replace(regExpMain, _strEmpty);
- }
-
- return strResult;
- };
- for (; i < properties[LEXICON.l]; i++) {
- valueArray = splitCssStyleByComma(element.css(transitionStr + '-' + properties[i]));
- for (j = 0; j < valueArray[LEXICON.l]; j++)
- result[j] = (result[j] ? result[j] + _strSpace : _strEmpty) + valueArray[j];
- }
- return result.join(', ');
- }
-
- /**
- * Calculates the host-elements inverted scale. (invertedScale = 1 / scale)
- * @returns {{x: number, y: number}} The scale of the host-element.
- */
- function getHostElementInvertedScale() {
- var rect = _paddingElementNative[LEXICON.bCR]();
- return {
- x: _supportTransform ? 1 / (MATH.round(rect.width) / _paddingElementNative[LEXICON.oW]) || 1 : 1,
- y: _supportTransform ? 1 / (MATH.round(rect.height) / _paddingElementNative[LEXICON.oH]) || 1 : 1
- };
- }
-
- /**
- * Checks whether the given object is a HTMLElement.
- * @param o The object which shall be checked.
- * @returns {boolean} True the given object is a HTMLElement, false otherwise.
- */
- function isHTMLElement(o) {
- var strOwnerDocument = 'ownerDocument';
- var strHTMLElement = 'HTMLElement';
- var wnd = o && o[strOwnerDocument] ? (o[strOwnerDocument].parentWindow || window) : window;
- return (
- typeof wnd[strHTMLElement] == TYPES.o ? o instanceof wnd[strHTMLElement] : //DOM2
- o && typeof o == TYPES.o && o !== null && o.nodeType === 1 && typeof o.nodeName == TYPES.s
- );
- }
-
- /**
- * Compares 2 arrays and returns the differences between them as a array.
- * @param a1 The first array which shall be compared.
- * @param a2 The second array which shall be compared.
- * @returns {Array} The differences between the two arrays.
- */
- function getArrayDifferences(a1, a2) {
- var a = [];
- var diff = [];
- var i;
- var k;
- for (i = 0; i < a1.length; i++)
- a[a1[i]] = true;
- for (i = 0; i < a2.length; i++) {
- if (a[a2[i]])
- delete a[a2[i]];
- else
- a[a2[i]] = true;
- }
- for (k in a)
- diff.push(k);
- return diff;
- }
-
- /**
- * Returns Zero or the number to which the value can be parsed.
- * @param value The value which shall be parsed.
- * @param toFloat Indicates whether the number shall be parsed to a float.
- */
- function parseToZeroOrNumber(value, toFloat) {
- var num = toFloat ? parseFloat(value) : parseInt(value, 10);
- return isNaN(num) ? 0 : num;
- }
-
- /**
- * Gets several information of the textarea and returns them as a object or undefined if the browser doesn't support it.
- * @returns {{cursorRow: Number, cursorCol, rows: Number, cols: number, wRow: number, pos: number, max : number}} or undefined if not supported.
- */
- function getTextareaInfo() {
- //read needed values
- var textareaCursorPosition = _targetElementNative.selectionStart;
- if (textareaCursorPosition === undefined)
- return;
-
- var textareaValue = _targetElement.val();
- var textareaLength = textareaValue[LEXICON.l];
- var textareaRowSplit = textareaValue.split('\n');
- var textareaLastRow = textareaRowSplit[LEXICON.l];
- var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split('\n');
- var widestRow = 0;
- var textareaLastCol = 0;
- var cursorRow = textareaCurrentCursorRowSplit[LEXICON.l];
- var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[LEXICON.l] - 1][LEXICON.l];
- var rowCols;
- var i;
-
- //get widest Row and the last column of the textarea
- for (i = 0; i < textareaRowSplit[LEXICON.l]; i++) {
- rowCols = textareaRowSplit[i][LEXICON.l];
- if (rowCols > textareaLastCol) {
- widestRow = i + 1;
- textareaLastCol = rowCols;
- }
- }
-
- return {
- _cursorRow: cursorRow, //cursorRow
- _cursorColumn: cursorCol, //cursorCol
- _rows: textareaLastRow, //rows
- _columns: textareaLastCol, //cols
- _widestRow: widestRow, //wRow
- _cursorPosition: textareaCursorPosition, //pos
- _cursorMax: textareaLength //max
- };
- }
-
- /**
- * Determines whether native overlay scrollbars are active.
- * @returns {boolean} True if native overlay scrollbars are active, false otherwise.
- */
- function nativeOverlayScrollbarsAreActive() {
- return (_ignoreOverlayScrollbarHidingCache && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y));
- }
-
- /**
- * Gets the element which is used to measure the content size.
- * @returns {*} TextareaCover if target element is textarea else the ContentElement.
- */
- function getContentMeasureElement() {
- return _isTextarea ? _textareaCoverElement[0] : _contentElementNative;
- }
-
- /**
- * Generates a string which represents a HTML div with the given classes or attributes.
- * @param classesOrAttrs The class of the div as string or a object which represents the attributes of the div. (The class attribute can also be written as "className".)
- * @param content The content of the div as string.
- * @returns {string} The concated string which represents a HTML div and its content.
- */
- function generateDiv(classesOrAttrs, content) {
- return '
' +
- (content || _strEmpty) +
- '
';
- }
-
- /**
- * Selects or generates a div with the given class attribute.
- * @param className The class names (divided by spaces) of the div which shall be selected or generated.
- * @param selectParentOrOnlyChildren The parent element from which of the element shall be selected. (if undefined or boolean its hostElement)
- * If its a boolean it decides whether only the children of the host element shall be selected.
- * @returns {*} The generated or selected element.
- */
- function selectOrGenerateDivByClass(className, selectParentOrOnlyChildren) {
- var onlyChildren = type(selectParentOrOnlyChildren) == TYPES.b;
- var selectParent = onlyChildren ? _hostElement : (selectParentOrOnlyChildren || _hostElement);
-
- return (_domExists && !selectParent[LEXICON.l])
- ? null
- : _domExists
- ? selectParent[onlyChildren ? 'children' : 'find'](_strDot + className.replace(/\s/g, _strDot)).eq(0)
- : FRAMEWORK(generateDiv(className))
- }
-
- /**
- * Gets the value of the given property from the given object.
- * @param obj The object from which the property value shall be got.
- * @param path The property of which the value shall be got.
- * @returns {*} Returns the value of the searched property or undefined of the property wasn't found.
- */
- function getObjectPropVal(obj, path) {
- var splits = path.split(_strDot);
- var i = 0;
- var val;
- for (; i < splits.length; i++) {
- if (!obj[LEXICON.hOP](splits[i]))
- return;
- val = obj[splits[i]];
- if (i < splits.length && type(val) == TYPES.o)
- obj = val;
- }
- return val;
- }
-
- /**
- * Sets the value of the given property from the given object.
- * @param obj The object from which the property value shall be set.
- * @param path The property of which the value shall be set.
- * @param val The value of the property which shall be set.
- */
- function setObjectPropVal(obj, path, val) {
- var splits = path.split(_strDot);
- var splitsLength = splits.length;
- var i = 0;
- var extendObj = {};
- var extendObjRoot = extendObj;
- for (; i < splitsLength; i++)
- extendObj = extendObj[splits[i]] = i + 1 < splitsLength ? {} : val;
- FRAMEWORK.extend(obj, extendObjRoot, true);
- }
-
-
- //==== Utils Cache ====//
-
- /**
- * Compares two values or objects and returns true if they aren't equal.
- * @param current The first value or object which shall be compared.
- * @param cache The second value or object which shall be compared.
- * @param force If true the returned value is always true.
- * @returns {boolean} True if both values or objects aren't equal or force is true, false otherwise.
- */
- function checkCache(current, cache, force) {
- if (force)
- return force;
- if (type(current) == TYPES.o && type(cache) == TYPES.o) {
- for (var prop in current) {
- if (prop !== 'c') {
- if (current[LEXICON.hOP](prop) && cache[LEXICON.hOP](prop)) {
- if (checkCache(current[prop], cache[prop]))
- return true;
- }
- else {
- return true;
- }
- }
- }
- }
- else {
- return current !== cache;
- }
- return false;
- }
-
-
- //==== Shortcuts ====//
-
- /**
- * jQuery extend method shortcut with a appended "true" as first argument.
- */
- function extendDeep() {
- return FRAMEWORK.extend.apply(this, [true].concat([].slice.call(arguments)));
- }
-
- /**
- * jQuery addClass method shortcut.
- */
- function addClass(el, classes) {
- return _frameworkProto.addClass.call(el, classes);
- }
-
- /**
- * jQuery removeClass method shortcut.
- */
- function removeClass(el, classes) {
- return _frameworkProto.removeClass.call(el, classes);
- }
-
- /**
- * jQuery remove method shortcut.
- */
- function remove(el) {
- return _frameworkProto.remove.call(el);
- }
-
- /**
- * Finds the first child element with the given selector of the given element.
- * @param el The root element from which the selector shall be valid.
- * @param selector The selector of the searched element.
- * @returns {*} The first element which is a child of the given element and matches the givens selector.
- */
- function findFirst(el, selector) {
- return _frameworkProto.find.call(el, selector).eq(0);
- }
-
-
- //==== API ====//
-
- /**
- * Puts the instance to sleep. It wont respond to any changes in the DOM and won't update. Scrollbar Interactivity is also disabled as well as the resize handle.
- * This behavior can be reset by calling the update method.
- */
- _base.sleep = function () {
- _sleeping = true;
- };
-
- /**
- * Updates the plugin and DOM to the current options.
- * This method should only be called if a update is 100% required.
- * @param force True if every property shall be updated and the cache shall be ignored.
- * !INTERNAL USAGE! : force can be a string "auto", "sync" or "zoom" too
- * if "auto" then before a real update the content size and host element attributes gets checked, and if they changed only then the update method will be called.
- * if "sync" then the async update process (MutationObserver or UpdateLoop) gets synchronized and a corresponding update takes place if one was needed due to pending changes.
- * if "zoom" then a update takes place where it's assumed that content and host size changed
- * @returns {boolean|undefined}
- * If force is "sync" then a boolean is returned which indicates whether a update was needed due to pending changes.
- * If force is "auto" then a boolean is returned whether a update was needed due to attribute or size changes.
- * undefined otherwise.
- */
- _base.update = function (force) {
- if (_destroyed)
- return;
-
- var attrsChanged;
- var contentSizeC;
- var isString = type(force) == TYPES.s;
- var imgElementSelector = 'img';
- var imgElementLoadEvent = 'load';
- var doUpdateAuto;
- var mutHost;
- var mutContent;
-
- if (isString) {
- if (force === _strAuto) {
- attrsChanged = meaningfulAttrsChanged();
- contentSizeC = updateAutoContentSizeChanged();
- doUpdateAuto = attrsChanged || contentSizeC;
- if (doUpdateAuto) {
- update({
- _contentSizeChanged: contentSizeC,
- _changedOptions: _initialized ? undefined : _currentPreparedOptions
- });
- }
- }
- else if (force === _strSync) {
- if (_mutationObserversConnected) {
- mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords());
- mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords());
- }
- else {
- mutHost = _base.update(_strAuto);
- }
- }
- else if (force === 'zoom') {
- update({
- _hostSizeChanged: true,
- _contentSizeChanged: true
- });
- }
- }
- else {
- force = _sleeping || force;
- _sleeping = false;
- if (!_base.update(_strSync) || force)
- update({ _force: force });
- }
- if (!_isTextarea) {
- _contentElement.find(imgElementSelector).each(function (i, el) {
- var index = COMPATIBILITY.inA(el, _imgs);
- if (index === -1)
- FRAMEWORK(el).off(imgElementLoadEvent, imgOnLoad).on(imgElementLoadEvent, imgOnLoad);
- });
- }
- return doUpdateAuto || mutHost || mutContent;
- };
-
- /**
- Gets or sets the current options. The update method will be called automatically if new options were set.
- * @param newOptions If new options are given, then the new options will be set, if new options aren't given (undefined or a not a plain object) then the current options will be returned.
- * @param value If new options is a property path string, then this value will be used to set the option to which the property path string leads.
- * @returns {*}
- */
- _base.options = function (newOptions, value) {
- var option = {};
- var changedOps;
-
- //return current options if newOptions are undefined or empty
- if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) {
- if (type(newOptions) == TYPES.s) {
- if (arguments.length > 1) {
- setObjectPropVal(option, newOptions, value);
- changedOps = setOptions(option);
- }
- else
- return getObjectPropVal(_currentOptions, newOptions);
- }
- else
- return _currentOptions;
- }
- else {
- changedOps = setOptions(newOptions);
- }
-
- if (!FRAMEWORK.isEmptyObject(changedOps)) {
- update({ _changedOptions: changedOps });
- }
- };
-
- /**
- * Restore the DOM, disconnects all observers, remove all resize observers and put the instance to sleep.
- */
- _base.destroy = function () {
- if (_destroyed)
- return;
-
- //remove this instance from auto update loop
- autoUpdateLoop.remove(_base);
-
- //disconnect all mutation observers
- disconnectMutationObservers();
-
- //remove all resize observers
- setupResizeObserver(_sizeObserverElement);
- setupResizeObserver(_sizeAutoObserverElement);
-
- //remove all extensions
- for (var extName in _extensions)
- _base.removeExt(extName);
-
- //remove all 'destroy' events
- while (_destroyEvents[LEXICON.l] > 0)
- _destroyEvents.pop()();
-
- //remove all events from host element
- setupHostMouseTouchEvents(true);
-
- //remove all helper / detection elements
- if (_contentGlueElement)
- remove(_contentGlueElement);
- if (_contentArrangeElement)
- remove(_contentArrangeElement);
- if (_sizeAutoObserverAdded)
- remove(_sizeAutoObserverElement);
-
- //remove all generated DOM
- setupScrollbarsDOM(true);
- setupScrollbarCornerDOM(true);
- setupStructureDOM(true);
-
- //remove all generated image load events
- for (var i = 0; i < _imgs[LEXICON.l]; i++)
- FRAMEWORK(_imgs[i]).off('load', imgOnLoad);
- _imgs = undefined;
-
- _destroyed = true;
- _sleeping = true;
-
- //remove this instance from the instances list
- INSTANCES(pluginTargetElement, 0);
- dispatchCallback('onDestroyed');
-
- //remove all properties and methods
- //for (var property in _base)
- // delete _base[property];
- //_base = undefined;
- };
-
- /**
- * Scrolls to a given position or element.
- * @param coordinates
- * 1. Can be "coordinates" which looks like:
- * { x : ?, y : ? } OR Object with x and y properties
- * { left : ?, top : ? } OR Object with left and top properties
- * { l : ?, t : ? } OR Object with l and t properties
- * [ ?, ? ] OR Array where the first two element are the coordinates (first is x, second is y)
- * ? A single value which stays for both axis
- * A value can be a number, a string or a calculation.
- *
- * Operators:
- * [NONE] The current scroll will be overwritten by the value.
- * '+=' The value will be added to the current scroll offset
- * '-=' The value will be subtracted from the current scroll offset
- * '*=' The current scroll wil be multiplicated by the value.
- * '/=' The current scroll wil be divided by the value.
- *
- * Units:
- * [NONE] The value is the final scroll amount. final = (value * 1)
- * 'px' Same as none
- * '%' The value is dependent on the current scroll value. final = ((currentScrollValue / 100) * value)
- * 'vw' The value is multiplicated by the viewport width. final = (value * viewportWidth)
- * 'vh' The value is multiplicated by the viewport height. final = (value * viewportHeight)
- *
- * example final values:
- * 200, '200px', '50%', '1vw', '1vh', '+=200', '/=1vw', '*=2px', '-=5vh', '+=33%', '+= 50% - 2px', '-= 1vw - 50%'
- *
- * 2. Can be a HTML or jQuery element:
- * The final scroll offset is the offset (without margin) of the given HTML / jQuery element.
- *
- * 3. Can be a object with a HTML or jQuery element with additional settings:
- * {
- * el : [HTMLElement, jQuery element], MUST be specified, else this object isn't valid.
- * scroll : [string, array, object], Default value is 'always'.
- * block : [string, array, object], Default value is 'begin'.
- * margin : [number, boolean, array, object] Default value is false.
- * }
- *
- * Possible scroll settings are:
- * 'always' Scrolls always.
- * 'ifneeded' Scrolls only if the element isnt fully in view.
- * 'never' Scrolls never.
- *
- * Possible block settings are:
- * 'begin' Both axis shall be docked to the "begin" edge. - The element will be docked to the top and left edge of the viewport.
- * 'end' Both axis shall be docked to the "end" edge. - The element will be docked to the bottom and right edge of the viewport. (If direction is RTL to the bottom and left edge.)
- * 'center' Both axis shall be docked to "center". - The element will be centered in the viewport.
- * 'nearest' The element will be docked to the nearest edge(s).
- *
- * Possible margin settings are: -- The actual margin of the element wont be affect, this option affects only the final scroll offset.
- * [BOOLEAN] If true the css margin of the element will be used, if false no margin will be used.
- * [NUMBER] The margin will be used for all edges.
- *
- * @param duration The duration of the scroll animation, OR a jQuery animation configuration object.
- * @param easing The animation easing.
- * @param complete The animation complete callback.
- * @returns {{
- * position: {x: number, y: number},
- * ratio: {x: number, y: number},
- * max: {x: number, y: number},
- * handleOffset: {x: number, y: number},
- * handleLength: {x: number, y: number},
- * handleLengthRatio: {x: number, y: number}, t
- * rackLength: {x: number, y: number},
- * isRTL: boolean,
- * isRTLNormalized: boolean
- * }}
- */
- _base.scroll = function (coordinates, duration, easing, complete) {
- if (arguments.length === 0 || coordinates === undefined) {
- var infoX = _scrollHorizontalInfo;
- var infoY = _scrollVerticalInfo;
- var normalizeInvert = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.i;
- var normalizeNegate = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.n;
- var scrollX = infoX._currentScroll;
- var scrollXRatio = infoX._currentScrollRatio;
- var maxScrollX = infoX._maxScroll;
- scrollXRatio = normalizeInvert ? 1 - scrollXRatio : scrollXRatio;
- scrollX = normalizeInvert ? maxScrollX - scrollX : scrollX;
- scrollX *= normalizeNegate ? -1 : 1;
- maxScrollX *= normalizeNegate ? -1 : 1;
-
- return {
- position: {
- x: scrollX,
- y: infoY._currentScroll
- },
- ratio: {
- x: scrollXRatio,
- y: infoY._currentScrollRatio
- },
- max: {
- x: maxScrollX,
- y: infoY._maxScroll
- },
- handleOffset: {
- x: infoX._handleOffset,
- y: infoY._handleOffset
- },
- handleLength: {
- x: infoX._handleLength,
- y: infoY._handleLength
- },
- handleLengthRatio: {
- x: infoX._handleLengthRatio,
- y: infoY._handleLengthRatio
- },
- trackLength: {
- x: infoX._trackLength,
- y: infoY._trackLength
- },
- snappedHandleOffset: {
- x: infoX._snappedHandleOffset,
- y: infoY._snappedHandleOffset
- },
- isRTL: _isRTL,
- isRTLNormalized: _normalizeRTLCache
- };
- }
-
- _base.update(_strSync);
-
- var normalizeRTL = _normalizeRTLCache;
- var coordinatesXAxisProps = [_strX, _strLeft, 'l'];
- var coordinatesYAxisProps = [_strY, _strTop, 't'];
- var coordinatesOperators = ['+=', '-=', '*=', '/='];
- var durationIsObject = type(duration) == TYPES.o;
- var completeCallback = durationIsObject ? duration.complete : complete;
- var i;
- var finalScroll = {};
- var specialEasing = {};
- var doScrollLeft;
- var doScrollTop;
- var animationOptions;
- var strEnd = 'end';
- var strBegin = 'begin';
- var strCenter = 'center';
- var strNearest = 'nearest';
- var strAlways = 'always';
- var strNever = 'never';
- var strIfNeeded = 'ifneeded';
- var strLength = LEXICON.l;
- var settingsAxis;
- var settingsScroll;
- var settingsBlock;
- var settingsMargin;
- var finalElement;
- var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx'];
- var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest];
- var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded];
- var coordinatesIsElementObj = coordinates[LEXICON.hOP]('el');
- var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates;
- var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false;
- var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement);
- var updateScrollbarInfos = function () {
- if (doScrollLeft)
- refreshScrollbarHandleOffset(true);
- if (doScrollTop)
- refreshScrollbarHandleOffset(false);
- };
- var proxyCompleteCallback = type(completeCallback) != TYPES.f ? undefined : function () {
- updateScrollbarInfos();
- completeCallback();
- };
- function checkSettingsStringValue(currValue, allowedValues) {
- for (i = 0; i < allowedValues[strLength]; i++) {
- if (currValue === allowedValues[i])
- return true;
- }
- return false;
- }
- function getRawScroll(isX, coordinates) {
- var coordinateProps = isX ? coordinatesXAxisProps : coordinatesYAxisProps;
- coordinates = type(coordinates) == TYPES.s || type(coordinates) == TYPES.n ? [coordinates, coordinates] : coordinates;
-
- if (type(coordinates) == TYPES.a)
- return isX ? coordinates[0] : coordinates[1];
- else if (type(coordinates) == TYPES.o) {
- //decides RTL normalization "hack" with .n
- //normalizeRTL = type(coordinates.n) == TYPES.b ? coordinates.n : normalizeRTL;
- for (i = 0; i < coordinateProps[strLength]; i++)
- if (coordinateProps[i] in coordinates)
- return coordinates[coordinateProps[i]];
- }
- }
- function getFinalScroll(isX, rawScroll) {
- var isString = type(rawScroll) == TYPES.s;
- var operator;
- var amount;
- var scrollInfo = isX ? _scrollHorizontalInfo : _scrollVerticalInfo;
- var currScroll = scrollInfo._currentScroll;
- var maxScroll = scrollInfo._maxScroll;
- var mult = ' * ';
- var finalValue;
- var isRTLisX = _isRTL && isX;
- var normalizeShortcuts = isRTLisX && _rtlScrollBehavior.n && !normalizeRTL;
- var strReplace = 'replace';
- var evalFunc = eval;
- var possibleOperator;
- if (isString) {
- //check operator
- if (rawScroll[strLength] > 2) {
- possibleOperator = rawScroll.substr(0, 2);
- if (inArray(possibleOperator, coordinatesOperators) > -1)
- operator = possibleOperator;
- }
-
- //calculate units and shortcuts
- rawScroll = operator ? rawScroll.substr(2) : rawScroll;
- rawScroll = rawScroll
- [strReplace](/min/g, 0) //'min' = 0%
- [strReplace](//g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'>' = 100%
- [strReplace](/px/g, _strEmpty)
- [strReplace](/%/g, mult + (maxScroll * (isRTLisX && _rtlScrollBehavior.n ? -1 : 1) / 100.0))
- [strReplace](/vw/g, mult + _viewportSize.w)
- [strReplace](/vh/g, mult + _viewportSize.h);
- amount = parseToZeroOrNumber(isNaN(rawScroll) ? parseToZeroOrNumber(evalFunc(rawScroll), true).toFixed() : rawScroll);
- }
- else {
- amount = rawScroll;
- }
-
- if (amount !== undefined && !isNaN(amount) && type(amount) == TYPES.n) {
- var normalizeIsRTLisX = normalizeRTL && isRTLisX;
- var operatorCurrScroll = currScroll * (normalizeIsRTLisX && _rtlScrollBehavior.n ? -1 : 1);
- var invert = normalizeIsRTLisX && _rtlScrollBehavior.i;
- var negate = normalizeIsRTLisX && _rtlScrollBehavior.n;
- operatorCurrScroll = invert ? (maxScroll - operatorCurrScroll) : operatorCurrScroll;
- switch (operator) {
- case '+=':
- finalValue = operatorCurrScroll + amount;
- break;
- case '-=':
- finalValue = operatorCurrScroll - amount;
- break;
- case '*=':
- finalValue = operatorCurrScroll * amount;
- break;
- case '/=':
- finalValue = operatorCurrScroll / amount;
- break;
- default:
- finalValue = amount;
- break;
- }
- finalValue = invert ? maxScroll - finalValue : finalValue;
- finalValue *= negate ? -1 : 1;
- finalValue = isRTLisX && _rtlScrollBehavior.n ? MATH.min(0, MATH.max(maxScroll, finalValue)) : MATH.max(0, MATH.min(maxScroll, finalValue));
- }
- return finalValue === currScroll ? undefined : finalValue;
- }
- function getPerAxisValue(value, valueInternalType, defaultValue, allowedValues) {
- var resultDefault = [defaultValue, defaultValue];
- var valueType = type(value);
- var valueArrLength;
- var valueArrItem;
-
- //value can be [ string, or array of two strings ]
- if (valueType == valueInternalType) {
- value = [value, value];
- }
- else if (valueType == TYPES.a) {
- valueArrLength = value[strLength];
- if (valueArrLength > 2 || valueArrLength < 1)
- value = resultDefault;
- else {
- if (valueArrLength === 1)
- value[1] = defaultValue;
- for (i = 0; i < valueArrLength; i++) {
- valueArrItem = value[i];
- if (type(valueArrItem) != valueInternalType || !checkSettingsStringValue(valueArrItem, allowedValues)) {
- value = resultDefault;
- break;
- }
- }
- }
- }
- else if (valueType == TYPES.o)
- value = [value[_strX] || defaultValue, value[_strY] || defaultValue];
- else
- value = resultDefault;
- return { x: value[0], y: value[1] };
- }
- function generateMargin(marginTopRightBottomLeftArray) {
- var result = [];
- var currValue;
- var currValueType;
- var valueDirections = [_strTop, _strRight, _strBottom, _strLeft];
- for (i = 0; i < marginTopRightBottomLeftArray[strLength]; i++) {
- if (i === valueDirections[strLength])
- break;
- currValue = marginTopRightBottomLeftArray[i];
- currValueType = type(currValue);
- if (currValueType == TYPES.b)
- result.push(currValue ? parseToZeroOrNumber(finalElement.css(_strMarginMinus + valueDirections[i])) : 0);
- else
- result.push(currValueType == TYPES.n ? currValue : 0);
- }
- return result;
- }
-
- if (possibleElementIsJQuery || possibleElementIsHTMLElement) {
- //get settings
- var margin = coordinatesIsElementObj ? coordinates.margin : 0;
- var axis = coordinatesIsElementObj ? coordinates.axis : 0;
- var scroll = coordinatesIsElementObj ? coordinates.scroll : 0;
- var block = coordinatesIsElementObj ? coordinates.block : 0;
- var marginDefault = [0, 0, 0, 0];
- var marginType = type(margin);
- var marginLength;
- finalElement = possibleElementIsJQuery ? possibleElement : FRAMEWORK(possibleElement);
-
- if (finalElement[strLength] > 0) {
- //margin can be [ boolean, number, array of 2, array of 4, object ]
- if (marginType == TYPES.n || marginType == TYPES.b)
- margin = generateMargin([margin, margin, margin, margin]);
- else if (marginType == TYPES.a) {
- marginLength = margin[strLength];
- if (marginLength === 2)
- margin = generateMargin([margin[0], margin[1], margin[0], margin[1]]);
- else if (marginLength >= 4)
- margin = generateMargin(margin);
- else
- margin = marginDefault;
- }
- else if (marginType == TYPES.o)
- margin = generateMargin([margin[_strTop], margin[_strRight], margin[_strBottom], margin[_strLeft]]);
- else
- margin = marginDefault;
-
- //block = type(block) === TYPES.b ? block ? [ strNearest, strBegin ] : [ strNearest, strEnd ] : block;
- settingsAxis = checkSettingsStringValue(axis, elementObjSettingsAxisValues) ? axis : 'xy';
- settingsScroll = getPerAxisValue(scroll, TYPES.s, strAlways, elementObjSettingsScrollValues);
- settingsBlock = getPerAxisValue(block, TYPES.s, strBegin, elementObjSettingsBlockValues);
- settingsMargin = margin;
-
- var viewportScroll = {
- l: _scrollHorizontalInfo._currentScroll,
- t: _scrollVerticalInfo._currentScroll
- };
- // use padding element instead of viewport element because padding element has never padding, margin or position applied.
- var viewportOffset = _paddingElement.offset();
-
- //get coordinates
- var elementOffset = finalElement.offset();
- var doNotScroll = {
- x: settingsScroll.x == strNever || settingsAxis == _strY,
- y: settingsScroll.y == strNever || settingsAxis == _strX
- };
- elementOffset[_strTop] -= settingsMargin[0];
- elementOffset[_strLeft] -= settingsMargin[3];
- var elementScrollCoordinates = {
- x: MATH.round(elementOffset[_strLeft] - viewportOffset[_strLeft] + viewportScroll.l),
- y: MATH.round(elementOffset[_strTop] - viewportOffset[_strTop] + viewportScroll.t)
- };
- if (_isRTL) {
- if (!_rtlScrollBehavior.n && !_rtlScrollBehavior.i)
- elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + viewportScroll.l);
- if (_rtlScrollBehavior.n && normalizeRTL)
- elementScrollCoordinates.x *= -1;
- if (_rtlScrollBehavior.i && normalizeRTL)
- elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + (_scrollHorizontalInfo._maxScroll - viewportScroll.l));
- }
-
- //measuring is required
- if (settingsBlock.x != strBegin || settingsBlock.y != strBegin || settingsScroll.x == strIfNeeded || settingsScroll.y == strIfNeeded || _isRTL) {
- var measuringElm = finalElement[0];
- var rawElementSize = _supportTransform ? measuringElm[LEXICON.bCR]() : {
- width: measuringElm[LEXICON.oW],
- height: measuringElm[LEXICON.oH]
- };
- var elementSize = {
- w: rawElementSize[_strWidth] + settingsMargin[3] + settingsMargin[1],
- h: rawElementSize[_strHeight] + settingsMargin[0] + settingsMargin[2]
- };
- var finalizeBlock = function (isX) {
- var vars = getScrollbarVars(isX);
- var wh = vars._w_h;
- var lt = vars._left_top;
- var xy = vars._x_y;
- var blockIsEnd = settingsBlock[xy] == (isX ? _isRTL ? strBegin : strEnd : strEnd);
- var blockIsCenter = settingsBlock[xy] == strCenter;
- var blockIsNearest = settingsBlock[xy] == strNearest;
- var scrollNever = settingsScroll[xy] == strNever;
- var scrollIfNeeded = settingsScroll[xy] == strIfNeeded;
- var vpSize = _viewportSize[wh];
- var vpOffset = viewportOffset[lt];
- var elSize = elementSize[wh];
- var elOffset = elementOffset[lt];
- var divide = blockIsCenter ? 2 : 1;
- var elementCenterOffset = elOffset + (elSize / 2);
- var viewportCenterOffset = vpOffset + (vpSize / 2);
- var isInView =
- elSize <= vpSize
- && elOffset >= vpOffset
- && elOffset + elSize <= vpOffset + vpSize;
-
- if (scrollNever)
- doNotScroll[xy] = true;
- else if (!doNotScroll[xy]) {
- if (blockIsNearest || scrollIfNeeded) {
- doNotScroll[xy] = scrollIfNeeded ? isInView : false;
- blockIsEnd = elSize < vpSize ? elementCenterOffset > viewportCenterOffset : elementCenterOffset < viewportCenterOffset;
- }
- elementScrollCoordinates[xy] -= blockIsEnd || blockIsCenter ? ((vpSize / divide) - (elSize / divide)) * (isX && _isRTL && normalizeRTL ? -1 : 1) : 0;
- }
- };
- finalizeBlock(true);
- finalizeBlock(false);
- }
-
- if (doNotScroll.y)
- delete elementScrollCoordinates.y;
- if (doNotScroll.x)
- delete elementScrollCoordinates.x;
-
- coordinates = elementScrollCoordinates;
- }
- }
-
- finalScroll[_strScrollLeft] = getFinalScroll(true, getRawScroll(true, coordinates));
- finalScroll[_strScrollTop] = getFinalScroll(false, getRawScroll(false, coordinates));
- doScrollLeft = finalScroll[_strScrollLeft] !== undefined;
- doScrollTop = finalScroll[_strScrollTop] !== undefined;
-
- if ((doScrollLeft || doScrollTop) && (duration > 0 || durationIsObject)) {
- if (durationIsObject) {
- duration.complete = proxyCompleteCallback;
- _viewportElement.animate(finalScroll, duration);
- }
- else {
- animationOptions = {
- duration: duration,
- complete: proxyCompleteCallback
- };
- if (type(easing) == TYPES.a || FRAMEWORK.isPlainObject(easing)) {
- specialEasing[_strScrollLeft] = easing[0] || easing.x;
- specialEasing[_strScrollTop] = easing[1] || easing.y;
- animationOptions.specialEasing = specialEasing;
- }
- else {
- animationOptions.easing = easing;
- }
- _viewportElement.animate(finalScroll, animationOptions);
- }
- }
- else {
- if (doScrollLeft)
- _viewportElement[_strScrollLeft](finalScroll[_strScrollLeft]);
- if (doScrollTop)
- _viewportElement[_strScrollTop](finalScroll[_strScrollTop]);
- updateScrollbarInfos();
- }
- };
-
- /**
- * Stops all scroll animations.
- * @returns {*} The current OverlayScrollbars instance (for chaining).
- */
- _base.scrollStop = function (param1, param2, param3) {
- _viewportElement.stop(param1, param2, param3);
- return _base;
- };
-
- /**
- * Returns all relevant elements.
- * @param elementName The name of the element which shall be returned.
- * @returns {{target: *, host: *, padding: *, viewport: *, content: *, scrollbarHorizontal: {scrollbar: *, track: *, handle: *}, scrollbarVertical: {scrollbar: *, track: *, handle: *}, scrollbarCorner: *} | *}
- */
- _base.getElements = function (elementName) {
- var obj = {
- target: _targetElementNative,
- host: _hostElementNative,
- padding: _paddingElementNative,
- viewport: _viewportElementNative,
- content: _contentElementNative,
- scrollbarHorizontal: {
- scrollbar: _scrollbarHorizontalElement[0],
- track: _scrollbarHorizontalTrackElement[0],
- handle: _scrollbarHorizontalHandleElement[0]
- },
- scrollbarVertical: {
- scrollbar: _scrollbarVerticalElement[0],
- track: _scrollbarVerticalTrackElement[0],
- handle: _scrollbarVerticalHandleElement[0]
- },
- scrollbarCorner: _scrollbarCornerElement[0]
- };
- return type(elementName) == TYPES.s ? getObjectPropVal(obj, elementName) : obj;
- };
-
- /**
- * Returns a object which describes the current state of this instance.
- * @param stateProperty A specific property from the state object which shall be returned.
- * @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *}
- */
- _base.getState = function (stateProperty) {
- function prepare(obj) {
- if (!FRAMEWORK.isPlainObject(obj))
- return obj;
- var extended = extendDeep({}, obj);
- var changePropertyName = function (from, to) {
- if (extended[LEXICON.hOP](from)) {
- extended[to] = extended[from];
- delete extended[from];
- }
- };
- changePropertyName('w', _strWidth); //change w to width
- changePropertyName('h', _strHeight); //change h to height
- delete extended.c; //delete c (the 'changed' prop)
- return extended;
- };
- var obj = {
- destroyed: !!prepare(_destroyed),
- sleeping: !!prepare(_sleeping),
- autoUpdate: prepare(!_mutationObserversConnected),
- widthAuto: prepare(_widthAutoCache),
- heightAuto: prepare(_heightAutoCache),
- padding: prepare(_cssPaddingCache),
- overflowAmount: prepare(_overflowAmountCache),
- hideOverflow: prepare(_hideOverflowCache),
- hasOverflow: prepare(_hasOverflowCache),
- contentScrollSize: prepare(_contentScrollSizeCache),
- viewportSize: prepare(_viewportSize),
- hostSize: prepare(_hostSizeCache),
- documentMixed: prepare(_documentMixed)
- };
- return type(stateProperty) == TYPES.s ? getObjectPropVal(obj, stateProperty) : obj;
- };
-
- /**
- * Gets all or specific extension instance.
- * @param extName The name of the extension from which the instance shall be got.
- * @returns {{}} The instance of the extension with the given name or undefined if the instance couldn't be found.
- */
- _base.ext = function (extName) {
- var result;
- var privateMethods = _extensionsPrivateMethods.split(' ');
- var i = 0;
- if (type(extName) == TYPES.s) {
- if (_extensions[LEXICON.hOP](extName)) {
- result = extendDeep({}, _extensions[extName]);
- for (; i < privateMethods.length; i++)
- delete result[privateMethods[i]];
- }
- }
- else {
- result = {};
- for (i in _extensions)
- result[i] = extendDeep({}, _base.ext(i));
- }
- return result;
- };
-
- /**
- * Adds a extension to this instance.
- * @param extName The name of the extension which shall be added.
- * @param extensionOptions The extension options which shall be used.
- * @returns {{}} The instance of the added extension or undefined if the extension couldn't be added properly.
- */
- _base.addExt = function (extName, extensionOptions) {
- var registeredExtensionObj = _plugin.extension(extName);
- var instance;
- var instanceAdded;
- var instanceContract;
- var contractResult;
- var contractFulfilled = true;
- if (registeredExtensionObj) {
- if (!_extensions[LEXICON.hOP](extName)) {
- instance = registeredExtensionObj.extensionFactory.call(_base,
- extendDeep({}, registeredExtensionObj.defaultOptions),
- FRAMEWORK,
- COMPATIBILITY);
-
- if (instance) {
- instanceContract = instance.contract;
- if (type(instanceContract) == TYPES.f) {
- contractResult = instanceContract(window);
- contractFulfilled = type(contractResult) == TYPES.b ? contractResult : contractFulfilled;
- }
- if (contractFulfilled) {
- _extensions[extName] = instance;
- instanceAdded = instance.added;
- if (type(instanceAdded) == TYPES.f)
- instanceAdded(extensionOptions);
-
- return _base.ext(extName);
- }
- }
- }
- else
- return _base.ext(extName);
- }
- else
- console.warn("A extension with the name \"" + extName + "\" isn't registered.");
- };
-
- /**
- * Removes a extension from this instance.
- * @param extName The name of the extension which shall be removed.
- * @returns {boolean} True if the extension was removed, false otherwise e.g. if the extension wasn't added before.
- */
- _base.removeExt = function (extName) {
- var instance = _extensions[extName];
- var instanceRemoved;
- if (instance) {
- delete _extensions[extName];
-
- instanceRemoved = instance.removed;
- if (type(instanceRemoved) == TYPES.f)
- instanceRemoved();
-
- return true;
- }
- return false;
- };
-
- /**
- * Constructs the plugin.
- * @param targetElement The element to which the plugin shall be applied.
- * @param options The initial options of the plugin.
- * @param extensions The extension(s) which shall be added right after the initialization.
- * @returns {boolean} True if the plugin was successfully initialized, false otherwise.
- */
- function construct(targetElement, options, extensions) {
- _defaultOptions = globals.defaultOptions;
- _nativeScrollbarStyling = globals.nativeScrollbarStyling;
- _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
- _nativeScrollbarIsOverlaid = extendDeep({}, globals.nativeScrollbarIsOverlaid);
- _overlayScrollbarDummySize = extendDeep({}, globals.overlayScrollbarDummySize);
- _rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior);
-
- //parse & set options but don't update
- setOptions(extendDeep({}, _defaultOptions, options));
-
- _cssCalc = globals.cssCalc;
- _msieVersion = globals.msie;
- _autoUpdateRecommended = globals.autoUpdateRecommended;
- _supportTransition = globals.supportTransition;
- _supportTransform = globals.supportTransform;
- _supportPassiveEvents = globals.supportPassiveEvents;
- _supportResizeObserver = globals.supportResizeObserver;
- _supportMutationObserver = globals.supportMutationObserver;
- _restrictedMeasuring = globals.restrictedMeasuring;
- _documentElement = FRAMEWORK(targetElement.ownerDocument);
- _documentElementNative = _documentElement[0];
- _windowElement = FRAMEWORK(_documentElementNative.defaultView || _documentElementNative.parentWindow);
- _windowElementNative = _windowElement[0];
- _htmlElement = findFirst(_documentElement, 'html');
- _bodyElement = findFirst(_htmlElement, 'body');
- _targetElement = FRAMEWORK(targetElement);
- _targetElementNative = _targetElement[0];
- _isTextarea = _targetElement.is('textarea');
- _isBody = _targetElement.is('body');
- _documentMixed = _documentElementNative !== document;
-
- /* On a div Element The if checks only whether:
- * - the targetElement has the class "os-host"
- * - the targetElement has a a child with the class "os-padding"
- *
- * If that's the case, its assumed the DOM has already the following structure:
- * (The ".os-host" element is the targetElement)
- *
- *
- *
- * =====================================================================================
- *
- * On a Textarea Element The if checks only whether:
- * - the targetElement has the class "os-textarea"
- * - the targetElement is inside a element with the class "os-content"
- *
- * If that's the case, its assumed the DOM has already the following structure:
- * (The ".os-textarea" (textarea) element is the targetElement)
- *
- *
- */
- _domExists = _isTextarea
- ? _targetElement.hasClass(_classNameTextareaElement) && _targetElement.parent().hasClass(_classNameContentElement)
- : _targetElement.hasClass(_classNameHostElement) && _targetElement.children(_strDot + _classNamePaddingElement)[LEXICON.l];
-
- var initBodyScroll;
- var bodyMouseTouchDownListener;
-
- //check if the plugin hasn't to be initialized
- if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) {
- dispatchCallback('onInitializationWithdrawn');
- if (_domExists) {
- setupStructureDOM(true);
- setupScrollbarsDOM(true);
- setupScrollbarCornerDOM(true);
- }
-
- _destroyed = true;
- _sleeping = true;
-
- return _base;
- }
-
- if (_isBody) {
- initBodyScroll = {};
- initBodyScroll.l = MATH.max(_targetElement[_strScrollLeft](), _htmlElement[_strScrollLeft](), _windowElement[_strScrollLeft]());
- initBodyScroll.t = MATH.max(_targetElement[_strScrollTop](), _htmlElement[_strScrollTop](), _windowElement[_strScrollTop]());
-
- bodyMouseTouchDownListener = function () {
- _viewportElement.removeAttr(LEXICON.ti);
- setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, true, true);
- }
- }
-
- //build OverlayScrollbars DOM
- setupStructureDOM();
- setupScrollbarsDOM();
- setupScrollbarCornerDOM();
-
- //create OverlayScrollbars events
- setupStructureEvents();
- setupScrollbarEvents(true);
- setupScrollbarEvents(false);
- setupScrollbarCornerEvents();
-
- //create mutation observers
- createMutationObservers();
-
- //build resize observer for the host element
- setupResizeObserver(_sizeObserverElement, hostOnResized);
-
- if (_isBody) {
- //apply the body scroll to handle it right in the update method
- _viewportElement[_strScrollLeft](initBodyScroll.l)[_strScrollTop](initBodyScroll.t);
-
- //set the focus on the viewport element so you dont have to click on the page to use keyboard keys (up / down / space) for scrolling
- if (document.activeElement == targetElement && _viewportElementNative.focus) {
- //set a tabindex to make the viewportElement focusable
- _viewportElement.attr(LEXICON.ti, '-1');
- _viewportElementNative.focus();
-
- /* the tabindex has to be removed due to;
- * If you set the tabindex attribute on an
, then its child content cannot be scrolled with the arrow keys unless you set tabindex on the content, too
- * https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
- */
- setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, false, true);
- }
- }
-
- //update for the first time & initialize cache
- _base.update(_strAuto);
-
- //the plugin is initialized now!
- _initialized = true;
- dispatchCallback('onInitialized');
-
- //call all callbacks which would fire before the initialized was complete
- each(_callbacksInitQeueue, function (index, value) { dispatchCallback(value.n, value.a); });
- _callbacksInitQeueue = [];
-
- //add extensions
- if (type(extensions) == TYPES.s)
- extensions = [extensions];
- if (COMPATIBILITY.isA(extensions))
- each(extensions, function (index, value) { _base.addExt(value); });
- else if (FRAMEWORK.isPlainObject(extensions))
- each(extensions, function (key, value) { _base.addExt(key, value); });
-
- //add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions)
- setTimeout(function () {
- if (_supportTransition && !_destroyed)
- addClass(_hostElement, _classNameHostTransition);
- }, 333);
-
- return _base;
- }
-
- if (_plugin.valid(construct(pluginTargetElement, options, extensions))) {
- INSTANCES(pluginTargetElement, _base);
- }
-
- return _base;
- }
-
- /**
- * Initializes a new OverlayScrollbarsInstance object or changes options if already initialized or returns the current instance.
- * @param pluginTargetElements The elements to which the Plugin shall be initialized.
- * @param options The custom options with which the plugin shall be initialized.
- * @param extensions The extension(s) which shall be added right after initialization.
- * @returns {*}
- */
- _plugin = window[PLUGINNAME] = function (pluginTargetElements, options, extensions) {
- if (arguments[LEXICON.l] === 0)
- return this;
-
- var arr = [];
- var optsIsPlainObj = FRAMEWORK.isPlainObject(options);
- var inst;
- var result;
-
- //pluginTargetElements is null or undefined
- if (!pluginTargetElements)
- return optsIsPlainObj || !options ? result : arr;
-
- /*
- pluginTargetElements will be converted to:
- 1. A jQueryElement Array
- 2. A HTMLElement Array
- 3. A Array with a single HTML Element
- so pluginTargetElements is always a array.
- */
- pluginTargetElements = pluginTargetElements[LEXICON.l] != undefined ? pluginTargetElements : [pluginTargetElements[0] || pluginTargetElements];
- initOverlayScrollbarsStatics();
-
- if (pluginTargetElements[LEXICON.l] > 0) {
- if (optsIsPlainObj) {
- FRAMEWORK.each(pluginTargetElements, function (i, v) {
- inst = v;
- if (inst !== undefined)
- arr.push(OverlayScrollbarsInstance(inst, options, extensions, _pluginsGlobals, _pluginsAutoUpdateLoop));
- });
- }
- else {
- FRAMEWORK.each(pluginTargetElements, function (i, v) {
- inst = INSTANCES(v);
- if ((options === '!' && _plugin.valid(inst)) || (COMPATIBILITY.type(options) == TYPES.f && options(v, inst)))
- arr.push(inst);
- else if (options === undefined)
- arr.push(inst);
- });
- }
- result = arr[LEXICON.l] === 1 ? arr[0] : arr;
- }
- return result;
- };
-
- /**
- * Returns a object which contains global information about the plugin and each instance of it.
- * The returned object is just a copy, that means that changes to the returned object won't have any effect to the original object.
- */
- _plugin.globals = function () {
- initOverlayScrollbarsStatics();
- var globals = FRAMEWORK.extend(true, {}, _pluginsGlobals);
- delete globals['msie'];
- return globals;
- };
-
- /**
- * Gets or Sets the default options for each new plugin initialization.
- * @param newDefaultOptions The object with which the default options shall be extended.
- */
- _plugin.defaultOptions = function (newDefaultOptions) {
- initOverlayScrollbarsStatics();
- var currDefaultOptions = _pluginsGlobals.defaultOptions;
- if (newDefaultOptions === undefined)
- return FRAMEWORK.extend(true, {}, currDefaultOptions);
-
- //set the new default options
- _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, {}, currDefaultOptions, _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true, currDefaultOptions)._default);
- };
-
- /**
- * Checks whether the passed instance is a non-destroyed OverlayScrollbars instance.
- * @param osInstance The potential OverlayScrollbars instance which shall be checked.
- * @returns {boolean} True if the passed value is a non-destroyed OverlayScrollbars instance, false otherwise.
- */
- _plugin.valid = function (osInstance) {
- return osInstance instanceof _plugin && !osInstance.getState().destroyed;
- };
-
- /**
- * Registers, Unregisters or returns a extension.
- * Register: Pass the name and the extension. (defaultOptions is optional)
- * Unregister: Pass the name and anything except a function as extension parameter.
- * Get extension: Pass the name of the extension which shall be got.
- * Get all extensions: Pass no arguments.
- * @param extensionName The name of the extension which shall be registered, unregistered or returned.
- * @param extension A function which generates the instance of the extension or anything other to remove a already registered extension.
- * @param defaultOptions The default options which shall be used for the registered extension.
- */
- _plugin.extension = function (extensionName, extension, defaultOptions) {
- var extNameTypeString = COMPATIBILITY.type(extensionName) == TYPES.s;
- var argLen = arguments[LEXICON.l];
- var i = 0;
- if (argLen < 1 || !extNameTypeString) {
- //return a copy of all extension objects
- return FRAMEWORK.extend(true, { length: _pluginsExtensions[LEXICON.l] }, _pluginsExtensions);
- }
- else if (extNameTypeString) {
- if (COMPATIBILITY.type(extension) == TYPES.f) {
- //register extension
- _pluginsExtensions.push({
- name: extensionName,
- extensionFactory: extension,
- defaultOptions: defaultOptions
- });
- }
- else {
- for (; i < _pluginsExtensions[LEXICON.l]; i++) {
- if (_pluginsExtensions[i].name === extensionName) {
- if (argLen > 1)
- _pluginsExtensions.splice(i, 1); //remove extension
- else
- return FRAMEWORK.extend(true, {}, _pluginsExtensions[i]); //return extension with the given name
- }
- }
- }
- }
- };
-
- return _plugin;
- })();
-
- if (JQUERY && JQUERY.fn) {
- /**
- * The jQuery initialization interface.
- * @param options The initial options for the construction of the plugin. To initialize the plugin, this option has to be a object! If it isn't a object, the instance(s) are returned and the plugin wont be initialized.
- * @param extensions The extension(s) which shall be added right after initialization.
- * @returns {*} After initialization it returns the jQuery element array, else it returns the instance(s) of the elements which are selected.
- */
- JQUERY.fn.overlayScrollbars = function (options, extensions) {
- var _elements = this;
- if (JQUERY.isPlainObject(options)) {
- JQUERY.each(_elements, function () { PLUGIN(this, options, extensions); });
- return _elements;
- }
- else
- return PLUGIN(_elements, options);
- };
- }
- return PLUGIN;
- }
+/*!
+ * OverlayScrollbars
+ * https://github.com/KingSora/OverlayScrollbars
+ *
+ * Version: 1.11.0
+ *
+ * Copyright KingSora | Rene Haas.
+ * https://github.com/KingSora
+ *
+ * Released under the MIT license.
+ * Date: 29.02.2020
+ */
+
+(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',
+ ti: 'tabindex',
+ 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('
');
+ 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
+ //since 1.11.0 always false -> fixed via CSS (hopefully)
+ 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();
+ //https://github.com/KingSora/OverlayScrollbars/issues/187
+ scrollbarDummyElement.scrollLeft(-999);
+ var dummyContainerChildOffsetAfterScroll = 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 !== dummyContainerChildOffsetAfterScroll.left
+ };
+ })(),
+ 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 which manages the scrollbars visibility of the target element.
+ * @param pluginTargetElement The element from which the scrollbars shall be hidden.
+ * @param options The custom options.
+ * @param extensions The custom extensions.
+ * @param globals
+ * @param autoUpdateLoop
+ * @returns {*}
+ * @constructor
+ */
+ function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) {
+ //shortcuts
+ var type = COMPATIBILITY.type;
+ var inArray = FRAMEWORK.inArray;
+ var each = FRAMEWORK.each;
+
+ //make correct instanceof
+ var _base = new _plugin();
+ var _frameworkProto = FRAMEWORK[LEXICON.p];
+
+ //if passed element is no HTML element: skip and return
+ if (!isHTMLElement(pluginTargetElement))
+ return;
+
+ //if passed element is already initialized: set passed options if there are any and return its instance
+ if (INSTANCES(pluginTargetElement)) {
+ var inst = INSTANCES(pluginTargetElement);
+ inst.options(options);
+ return inst;
+ }
+
+ //globals:
+ var _nativeScrollbarIsOverlaid;
+ var _overlayScrollbarDummySize;
+ var _rtlScrollBehavior;
+ var _autoUpdateRecommended;
+ var _msieVersion;
+ var _nativeScrollbarStyling;
+ var _cssCalc;
+ var _nativeScrollbarSize;
+ var _supportTransition;
+ var _supportTransform;
+ var _supportPassiveEvents;
+ var _supportResizeObserver;
+ var _supportMutationObserver;
+ var _restrictedMeasuring;
+
+ //general readonly:
+ var _initialized;
+ var _destroyed;
+ var _isTextarea;
+ var _isBody;
+ var _documentMixed;
+ var _domExists;
+
+ //general:
+ var _isBorderBox;
+ var _sizeAutoObserverAdded;
+ var _paddingX;
+ var _paddingY;
+ var _borderX;
+ var _borderY;
+ var _marginX;
+ var _marginY;
+ var _isRTL;
+ var _sleeping;
+ var _contentBorderSize = {};
+ var _scrollHorizontalInfo = {};
+ var _scrollVerticalInfo = {};
+ var _viewportSize = {};
+ var _nativeScrollbarMinSize = {};
+
+ //naming:
+ var _strMinusHidden = '-hidden';
+ var _strMarginMinus = 'margin-';
+ var _strPaddingMinus = 'padding-';
+ var _strBorderMinus = 'border-';
+ var _strTop = 'top';
+ var _strRight = 'right';
+ var _strBottom = 'bottom';
+ var _strLeft = 'left';
+ var _strMinMinus = 'min-';
+ var _strMaxMinus = 'max-';
+ var _strWidth = 'width';
+ var _strHeight = 'height';
+ var _strFloat = 'float';
+ var _strEmpty = '';
+ var _strAuto = 'auto';
+ var _strSync = 'sync';
+ var _strScroll = 'scroll';
+ var _strHundredPercent = '100%';
+ var _strX = 'x';
+ var _strY = 'y';
+ var _strDot = '.';
+ var _strSpace = ' ';
+ var _strScrollbar = 'scrollbar';
+ var _strMinusHorizontal = '-horizontal';
+ var _strMinusVertical = '-vertical';
+ var _strScrollLeft = _strScroll + 'Left';
+ var _strScrollTop = _strScroll + 'Top';
+ var _strMouseTouchDownEvent = 'mousedown touchstart';
+ var _strMouseTouchUpEvent = 'mouseup touchend touchcancel';
+ var _strMouseTouchMoveEvent = 'mousemove touchmove';
+ var _strMouseTouchEnter = 'mouseenter';
+ var _strMouseTouchLeave = 'mouseleave';
+ var _strKeyDownEvent = 'keydown';
+ var _strKeyUpEvent = 'keyup';
+ var _strSelectStartEvent = 'selectstart';
+ var _strTransitionEndEvent = 'transitionend webkitTransitionEnd oTransitionEnd';
+ var _strResizeObserverProperty = '__overlayScrollbarsRO__';
+
+ //class names:
+ var _cassNamesPrefix = 'os-';
+ var _classNameHTMLElement = _cassNamesPrefix + 'html';
+ var _classNameHostElement = _cassNamesPrefix + 'host';
+ var _classNameHostTextareaElement = _classNameHostElement + '-textarea';
+ var _classNameHostScrollbarHorizontalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusHorizontal + _strMinusHidden;
+ var _classNameHostScrollbarVerticalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusVertical + _strMinusHidden;
+ var _classNameHostTransition = _classNameHostElement + '-transition';
+ var _classNameHostRTL = _classNameHostElement + '-rtl';
+ var _classNameHostResizeDisabled = _classNameHostElement + '-resize-disabled';
+ var _classNameHostScrolling = _classNameHostElement + '-scrolling';
+ var _classNameHostOverflow = _classNameHostElement + '-overflow';
+ var _classNameHostOverflowX = _classNameHostOverflow + '-x';
+ var _classNameHostOverflowY = _classNameHostOverflow + '-y';
+ var _classNameTextareaElement = _cassNamesPrefix + 'textarea';
+ var _classNameTextareaCoverElement = _classNameTextareaElement + '-cover';
+ var _classNamePaddingElement = _cassNamesPrefix + 'padding';
+ var _classNameViewportElement = _cassNamesPrefix + 'viewport';
+ var _classNameViewportNativeScrollbarsInvisible = _classNameViewportElement + '-native-scrollbars-invisible';
+ var _classNameViewportNativeScrollbarsOverlaid = _classNameViewportElement + '-native-scrollbars-overlaid';
+ var _classNameContentElement = _cassNamesPrefix + 'content';
+ var _classNameContentArrangeElement = _cassNamesPrefix + 'content-arrange';
+ var _classNameContentGlueElement = _cassNamesPrefix + 'content-glue';
+ var _classNameSizeAutoObserverElement = _cassNamesPrefix + 'size-auto-observer';
+ var _classNameResizeObserverElement = _cassNamesPrefix + 'resize-observer';
+ var _classNameResizeObserverItemElement = _cassNamesPrefix + 'resize-observer-item';
+ var _classNameResizeObserverItemFinalElement = _classNameResizeObserverItemElement + '-final';
+ var _classNameTextInherit = _cassNamesPrefix + 'text-inherit';
+ var _classNameScrollbar = _cassNamesPrefix + _strScrollbar;
+ var _classNameScrollbarTrack = _classNameScrollbar + '-track';
+ var _classNameScrollbarTrackOff = _classNameScrollbarTrack + '-off';
+ var _classNameScrollbarHandle = _classNameScrollbar + '-handle';
+ var _classNameScrollbarHandleOff = _classNameScrollbarHandle + '-off';
+ var _classNameScrollbarUnusable = _classNameScrollbar + '-unusable';
+ var _classNameScrollbarAutoHidden = _classNameScrollbar + '-' + _strAuto + _strMinusHidden;
+ var _classNameScrollbarCorner = _classNameScrollbar + '-corner';
+ var _classNameScrollbarCornerResize = _classNameScrollbarCorner + '-resize';
+ var _classNameScrollbarCornerResizeB = _classNameScrollbarCornerResize + '-both';
+ var _classNameScrollbarCornerResizeH = _classNameScrollbarCornerResize + _strMinusHorizontal;
+ var _classNameScrollbarCornerResizeV = _classNameScrollbarCornerResize + _strMinusVertical;
+ var _classNameScrollbarHorizontal = _classNameScrollbar + _strMinusHorizontal;
+ var _classNameScrollbarVertical = _classNameScrollbar + _strMinusVertical;
+ var _classNameDragging = _cassNamesPrefix + 'dragging';
+ var _classNameThemeNone = _cassNamesPrefix + 'theme-none';
+ var _classNamesDynamicDestroy = [
+ _classNameViewportNativeScrollbarsInvisible,
+ _classNameViewportNativeScrollbarsOverlaid,
+ _classNameScrollbarTrackOff,
+ _classNameScrollbarHandleOff,
+ _classNameScrollbarUnusable,
+ _classNameScrollbarAutoHidden,
+ _classNameScrollbarCornerResize,
+ _classNameScrollbarCornerResizeB,
+ _classNameScrollbarCornerResizeH,
+ _classNameScrollbarCornerResizeV,
+ _classNameDragging].join(_strSpace);
+
+ //callbacks:
+ var _callbacksInitQeueue = [];
+
+ //attrs viewport shall inherit from target
+ var _viewportAttrsFromTarget = [LEXICON.ti];
+
+ //options:
+ var _defaultOptions;
+ var _currentOptions;
+ var _currentPreparedOptions;
+
+ //extensions:
+ var _extensions = {};
+ var _extensionsPrivateMethods = 'added removed on contract';
+
+ //update
+ var _lastUpdateTime;
+ var _swallowedUpdateHints = {};
+ var _swallowedUpdateTimeout;
+ var _swallowUpdateLag = 42;
+ var _imgs = [];
+
+ //DOM elements:
+ var _windowElement;
+ var _documentElement;
+ var _htmlElement;
+ var _bodyElement;
+ var _targetElement; //the target element of this OverlayScrollbars object
+ var _hostElement; //the host element of this OverlayScrollbars object -> may be the same as targetElement
+ var _sizeAutoObserverElement; //observes size auto changes
+ var _sizeObserverElement; //observes size and padding changes
+ var _paddingElement; //manages the padding
+ var _viewportElement; //is the viewport of our scrollbar model
+ var _contentElement; //the element which holds the content
+ var _contentArrangeElement; //is needed for correct sizing of the content element (only if native scrollbars are overlays)
+ var _contentGlueElement; //has always the size of the content element
+ var _textareaCoverElement; //only applied if target is a textarea element. Used for correct size calculation and for prevention of uncontrolled scrolling
+ var _scrollbarCornerElement;
+ var _scrollbarHorizontalElement;
+ var _scrollbarHorizontalTrackElement;
+ var _scrollbarHorizontalHandleElement;
+ var _scrollbarVerticalElement;
+ var _scrollbarVerticalTrackElement;
+ var _scrollbarVerticalHandleElement;
+ var _windowElementNative;
+ var _documentElementNative;
+ var _targetElementNative;
+ var _hostElementNative;
+ var _sizeAutoObserverElementNative;
+ var _sizeObserverElementNative;
+ var _paddingElementNative;
+ var _viewportElementNative;
+ var _contentElementNative;
+
+ //Cache:
+ var _hostSizeCache;
+ var _contentScrollSizeCache;
+ var _arrangeContentSizeCache;
+ var _hasOverflowCache;
+ var _hideOverflowCache;
+ var _widthAutoCache;
+ var _heightAutoCache;
+ var _cssMaxValueCache;
+ var _cssBoxSizingCache;
+ var _cssPaddingCache;
+ var _cssBorderCache;
+ var _cssMarginCache;
+ var _cssDirectionCache;
+ var _cssDirectionDetectedCache;
+ var _paddingAbsoluteCache;
+ var _clipAlwaysCache;
+ var _contentGlueSizeCache;
+ var _overflowBehaviorCache;
+ var _overflowAmountCache;
+ var _ignoreOverlayScrollbarHidingCache;
+ var _autoUpdateCache;
+ var _sizeAutoCapableCache;
+ var _contentElementScrollSizeChangeDetectedCache;
+ var _hostElementSizeChangeDetectedCache;
+ var _scrollbarsVisibilityCache;
+ var _scrollbarsAutoHideCache;
+ var _scrollbarsClickScrollingCache;
+ var _scrollbarsDragScrollingCache;
+ var _resizeCache;
+ var _normalizeRTLCache;
+ var _classNameCache;
+ var _oldClassName;
+ var _textareaAutoWrappingCache;
+ var _textareaInfoCache;
+ var _textareaSizeCache;
+ var _textareaDynHeightCache;
+ var _textareaDynWidthCache;
+ var _bodyMinSizeCache;
+ var _displayIsHiddenCache;
+ var _updateAutoCache = {};
+
+ //MutationObserver:
+ var _mutationObserverHost;
+ var _mutationObserverContent;
+ var _mutationObserverHostCallback;
+ var _mutationObserverContentCallback;
+ var _mutationObserversConnected;
+ var _mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows'];
+ var _mutationObserverAttrsHost = [LEXICON.i, LEXICON.c, LEXICON.s, 'open'].concat(_viewportAttrsFromTarget);
+
+ //events:
+ var _destroyEvents = [];
+
+ //textarea:
+ var _textareaHasFocus;
+
+ //scrollbars:
+ var _scrollbarsAutoHideTimeoutId;
+ var _scrollbarsAutoHideMoveTimeoutId;
+ var _scrollbarsAutoHideDelay;
+ var _scrollbarsAutoHideNever;
+ var _scrollbarsAutoHideScroll;
+ var _scrollbarsAutoHideMove;
+ var _scrollbarsAutoHideLeave;
+ var _scrollbarsHandleHovered;
+ var _scrollbarsHandlesDefineScrollPos;
+
+ //resize
+ var _resizeNone;
+ var _resizeBoth;
+ var _resizeHorizontal;
+ var _resizeVertical;
+
+
+ //==== Event Listener ====//
+
+ /**
+ * Adds or removes a event listener from the given element.
+ * @param element The element to which the event listener shall be applied or removed.
+ * @param eventNames The name(s) of the events.
+ * @param listener The method which shall be called.
+ * @param remove True if the handler shall be removed, false or undefined if the handler shall be added.
+ */
+ function setupResponsiveEventListener(element, eventNames, listener, remove, passive) {
+ var collected = type(eventNames) == TYPES.a && type(listener) == TYPES.a;
+ var method = remove ? 'removeEventListener' : 'addEventListener';
+ var onOff = remove ? 'off' : 'on';
+ var events = collected ? false : eventNames.split(_strSpace)
+ var i = 0;
+
+ if (collected) {
+ for (; i < eventNames[LEXICON.l]; i++)
+ setupResponsiveEventListener(element, eventNames[i], listener[i], remove);
+ }
+ else {
+ for (; i < events[LEXICON.l]; i++) {
+ if (_supportPassiveEvents)
+ element[0][method](events[i], listener, { passive: passive || false });
+ else
+ element[onOff](events[i], listener);
+ }
+ }
+ }
+
+
+ function addDestroyEventListener(element, eventNames, listener, passive) {
+ setupResponsiveEventListener(element, eventNames, listener, false, passive);
+ _destroyEvents.push(COMPATIBILITY.bind(setupResponsiveEventListener, 0, element, eventNames, listener, true, passive));
+ }
+
+ //==== Resize Observer ====//
+
+ /**
+ * Adds or removes a resize observer from the given element.
+ * @param targetElement The element to which the resize observer shall be added or removed.
+ * @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change or false / undefined if the resizeObserver shall be removed.
+ */
+ function setupResizeObserver(targetElement, onElementResizedCallback) {
+ if (targetElement) {
+ var resizeObserver = COMPATIBILITY.rO();
+ var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart';
+ var strChildNodes = 'childNodes';
+ var constScroll = 3333333;
+ var callback = function () {
+ targetElement[_strScrollTop](constScroll)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll : constScroll);
+ onElementResizedCallback();
+ };
+ //add resize observer:
+ if (onElementResizedCallback) {
+ if (_supportResizeObserver) {
+ var element = targetElement.addClass('observed').append(generateDiv(_classNameResizeObserverElement)).contents()[0];
+ var observer = element[_strResizeObserverProperty] = new resizeObserver(callback);
+ observer.observe(element);
+ }
+ else {
+ if (_msieVersion > 9 || !_autoUpdateRecommended) {
+ targetElement.prepend(
+ generateDiv(_classNameResizeObserverElement,
+ generateDiv({ c: _classNameResizeObserverItemElement, dir: 'ltr' },
+ generateDiv(_classNameResizeObserverItemElement,
+ generateDiv(_classNameResizeObserverItemFinalElement)
+ ) +
+ generateDiv(_classNameResizeObserverItemElement,
+ generateDiv({ c: _classNameResizeObserverItemFinalElement, style: 'width: 200%; height: 200%' })
+ )
+ )
+ )
+ );
+
+ var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0];
+ var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]);
+ var expandElement = FRAMEWORK(observerElement[strChildNodes][0]);
+ var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]);
+ var widthCache = observerElement[LEXICON.oW];
+ var heightCache = observerElement[LEXICON.oH];
+ var isDirty;
+ var rAFId;
+ var currWidth;
+ var currHeight;
+ var factor = 2;
+ var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!!
+ var reset = function () {
+ /*
+ var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
+ var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
+ var expandChildCSS = {};
+ expandChildCSS[_strWidth] = sizeResetWidth;
+ expandChildCSS[_strHeight] = sizeResetHeight;
+ expandElementChild.css(expandChildCSS);
+
+
+ expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
+ shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
+ */
+ expandElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);
+ shrinkElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);
+ };
+ var onResized = function () {
+ rAFId = 0;
+ if (!isDirty)
+ return;
+
+ widthCache = currWidth;
+ heightCache = currHeight;
+ callback();
+ };
+ var onScroll = function (event) {
+ currWidth = observerElement[LEXICON.oW];
+ currHeight = observerElement[LEXICON.oH];
+ isDirty = currWidth != widthCache || currHeight != heightCache;
+
+ if (event && isDirty && !rAFId) {
+ COMPATIBILITY.cAF()(rAFId);
+ rAFId = COMPATIBILITY.rAF()(onResized);
+ }
+ else if (!event)
+ onResized();
+
+ reset();
+ if (event) {
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ }
+ return false;
+ };
+ var expandChildCSS = {};
+ var observerElementCSS = {};
+
+ setTopRightBottomLeft(observerElementCSS, _strEmpty, [
+ -((nativeScrollbarSize.y + 1) * factor),
+ nativeScrollbarSize.x * -factor,
+ nativeScrollbarSize.y * -factor,
+ -((nativeScrollbarSize.x + 1) * factor)
+ ]);
+
+ FRAMEWORK(observerElement).css(observerElementCSS);
+ expandElement.on(_strScroll, onScroll);
+ shrinkElement.on(_strScroll, onScroll);
+ targetElement.on(strAnimationStartEvent, function () {
+ onScroll(false);
+ });
+ //lets assume that the divs will never be that large and a constant value is enough
+ expandChildCSS[_strWidth] = constScroll;
+ expandChildCSS[_strHeight] = constScroll;
+ expandElementChild.css(expandChildCSS);
+
+ reset();
+ }
+ else {
+ var attachEvent = _documentElementNative.attachEvent;
+ var isIE = _msieVersion !== undefined;
+ if (attachEvent) {
+ targetElement.prepend(generateDiv(_classNameResizeObserverElement));
+ findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback);
+ }
+ else {
+ var obj = _documentElementNative.createElement(TYPES.o);
+ obj.setAttribute(LEXICON.ti, '-1');
+ obj.setAttribute(LEXICON.c, _classNameResizeObserverElement);
+ obj.onload = function () {
+ var wnd = this.contentDocument.defaultView;
+ wnd.addEventListener('resize', callback);
+ wnd.document.documentElement.style.display = 'none';
+ };
+ obj.type = 'text/html';
+ if (isIE)
+ targetElement.prepend(obj);
+ obj.data = 'about:blank';
+ if (!isIE)
+ targetElement.prepend(obj);
+ targetElement.on(strAnimationStartEvent, callback);
+ }
+ }
+ }
+
+ if (targetElement[0] === _sizeObserverElementNative) {
+ var directionChanged = function () {
+ var dir = _hostElement.css('direction');
+ var css = {};
+ var scrollLeftValue = 0;
+ var result = false;
+ if (dir !== _cssDirectionDetectedCache) {
+ if (dir === 'ltr') {
+ css[_strLeft] = 0;
+ css[_strRight] = _strAuto;
+ scrollLeftValue = constScroll;
+ }
+ else {
+ css[_strLeft] = _strAuto;
+ css[_strRight] = 0;
+ scrollLeftValue = _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll;
+ }
+ //execution order is important for IE!!!
+ _sizeObserverElement.children().eq(0).css(css);
+ _sizeObserverElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constScroll);
+ _cssDirectionDetectedCache = dir;
+ result = true;
+ }
+ return result;
+ };
+ directionChanged();
+ addDestroyEventListener(targetElement, _strScroll, function (event) {
+ if (directionChanged())
+ update();
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ return false;
+ });
+ }
+ }
+ //remove resize observer:
+ else {
+ if (_supportResizeObserver) {
+ var element = targetElement.contents()[0];
+ var resizeObserverObj = element[_strResizeObserverProperty];
+ if (resizeObserverObj) {
+ resizeObserverObj.disconnect();
+ delete element[_strResizeObserverProperty];
+ }
+ }
+ else {
+ remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0));
+ }
+ }
+ }
+ }
+
+ /**
+ * Freezes or unfreezes the given resize observer.
+ * @param targetElement The element to which the target resize observer is applied.
+ * @param freeze True if the resize observer shall be frozen, false otherwise.
+
+ function freezeResizeObserver(targetElement, freeze) {
+ if (targetElement !== undefined) {
+ if(freeze) {
+ if (_supportResizeObserver) {
+ var element = targetElement.contents()[0];
+ element[_strResizeObserverProperty].unobserve(element);
+ }
+ else {
+ targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0);
+ var w = targetElement.css(_strWidth);
+ var h = targetElement.css(_strHeight);
+ var css = {};
+ css[_strWidth] = w;
+ css[_strHeight] = h;
+ targetElement.css(css);
+ }
+ }
+ else {
+ if (_supportResizeObserver) {
+ var element = targetElement.contents()[0];
+ element[_strResizeObserverProperty].observe(element);
+ }
+ else {
+ var css = { };
+ css[_strHeight] = _strEmpty;
+ css[_strWidth] = _strEmpty;
+ targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css);
+ }
+ }
+ }
+ }
+ */
+
+
+ //==== Mutation Observers ====//
+
+ /**
+ * Creates MutationObservers for the host and content Element if they are supported.
+ */
+ function createMutationObservers() {
+ if (_supportMutationObserver) {
+ var mutationObserverContentLag = 11;
+ var mutationObserver = COMPATIBILITY.mO();
+ var contentLastUpdate = COMPATIBILITY.now();
+ var mutationTarget;
+ var mutationAttrName;
+ var contentTimeout;
+ var now;
+ var sizeAuto;
+ var action;
+
+ _mutationObserverHostCallback = function (mutations) {
+ var doUpdate = false;
+ var mutation;
+ var mutatedAttrs = [];
+
+ if (_initialized && !_sleeping) {
+ each(mutations, function () {
+ mutation = this;
+ mutationTarget = mutation.target;
+ mutationAttrName = mutation.attributeName;
+
+ if(!doUpdate) {
+ if (mutationAttrName === LEXICON.c)
+ doUpdate = hostClassNamesChanged(mutation.oldValue, mutationTarget.className);
+ else if (mutationAttrName === LEXICON.s)
+ doUpdate = mutation.oldValue !== mutationTarget[LEXICON.s].cssText;
+ else
+ doUpdate = true;
+ }
+
+ mutatedAttrs.push(mutationAttrName);
+ });
+
+ updateViewportAttrsFromTarget(mutatedAttrs);
+
+ if (doUpdate)
+ _base.update(_strAuto);
+ }
+ return doUpdate;
+ };
+ _mutationObserverContentCallback = function (mutations) {
+ var doUpdate = false;
+ var mutation;
+
+ if (_initialized && !_sleeping) {
+ each(mutations, function () {
+ mutation = this;
+ doUpdate = isUnknownMutation(mutation);
+ return !doUpdate;
+ });
+
+ if (doUpdate) {
+ now = COMPATIBILITY.now();
+ sizeAuto = (_heightAutoCache || _widthAutoCache);
+ action = function () {
+ if (!_destroyed) {
+ contentLastUpdate = now;
+
+ //if cols, rows or wrap attr was changed
+ if (_isTextarea)
+ textareaUpdate();
+
+ if (sizeAuto)
+ update();
+ else
+ _base.update(_strAuto);
+ }
+ };
+ clearTimeout(contentTimeout);
+ if (mutationObserverContentLag <= 0 || now - contentLastUpdate > mutationObserverContentLag || !sizeAuto)
+ action();
+ else
+ contentTimeout = setTimeout(action, mutationObserverContentLag);
+ }
+ }
+ return doUpdate;
+ }
+
+ _mutationObserverHost = new mutationObserver(_mutationObserverHostCallback);
+ _mutationObserverContent = new mutationObserver(_mutationObserverContentCallback);
+ }
+ }
+
+ /**
+ * Connects the MutationObservers if they are supported.
+ */
+ function connectMutationObservers() {
+ if (_supportMutationObserver && !_mutationObserversConnected) {
+ _mutationObserverHost.observe(_hostElementNative, {
+ attributes: true,
+ attributeOldValue: true,
+ attributeFilter: _mutationObserverAttrsHost
+ });
+
+ _mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, {
+ attributes: true,
+ attributeOldValue: true,
+ subtree: !_isTextarea,
+ childList: !_isTextarea,
+ characterData: !_isTextarea,
+ attributeFilter: _isTextarea ? _mutationObserverAttrsTextarea : _mutationObserverAttrsHost
+ });
+
+ _mutationObserversConnected = true;
+ }
+ }
+
+ /**
+ * Disconnects the MutationObservers if they are supported.
+ */
+ function disconnectMutationObservers() {
+ if (_supportMutationObserver && _mutationObserversConnected) {
+ _mutationObserverHost.disconnect();
+ _mutationObserverContent.disconnect();
+
+ _mutationObserversConnected = false;
+ }
+ }
+
+
+ //==== Events of elements ====//
+
+ /**
+ * This method gets called every time the host element gets resized. IMPORTANT: Padding changes are detected too!!
+ * It refreshes the hostResizedEventArgs and the hostSizeResizeCache.
+ * If there are any size changes, the update method gets called.
+ */
+ function hostOnResized() {
+ if (!_sleeping) {
+ var changed;
+ var hostSize = {
+ w: _sizeObserverElementNative[LEXICON.sW],
+ h: _sizeObserverElementNative[LEXICON.sH]
+ };
+
+ changed = checkCache(hostSize, _hostElementSizeChangeDetectedCache);
+ _hostElementSizeChangeDetectedCache = hostSize;
+ if (changed)
+ update({ _hostSizeChanged: true });
+ }
+ }
+
+ /**
+ * The mouse enter event of the host element. This event is only needed for the autoHide feature.
+ */
+ function hostOnMouseEnter() {
+ if (_scrollbarsAutoHideLeave)
+ refreshScrollbarsAutoHide(true);
+ }
+
+ /**
+ * The mouse leave event of the host element. This event is only needed for the autoHide feature.
+ */
+ function hostOnMouseLeave() {
+ if (_scrollbarsAutoHideLeave && !_bodyElement.hasClass(_classNameDragging))
+ refreshScrollbarsAutoHide(false);
+ }
+
+ /**
+ * The mouse move event of the host element. This event is only needed for the autoHide "move" feature.
+ */
+ function hostOnMouseMove() {
+ if (_scrollbarsAutoHideMove) {
+ refreshScrollbarsAutoHide(true);
+ clearTimeout(_scrollbarsAutoHideMoveTimeoutId);
+ _scrollbarsAutoHideMoveTimeoutId = setTimeout(function () {
+ if (_scrollbarsAutoHideMove && !_destroyed)
+ refreshScrollbarsAutoHide(false);
+ }, 100);
+ }
+ }
+
+ /**
+ * Prevents text from deselection if attached to the document element on the mousedown event of a DOM element.
+ * @param event The select start event.
+ */
+ function documentOnSelectStart(event) {
+ COMPATIBILITY.prvD(event);
+ return false;
+ }
+
+ /**
+ * A callback which will be called after a img element has downloaded its src asynchronous.
+ */
+ function imgOnLoad() {
+ update({ _contentSizeChanged: true });
+ }
+
+ /**
+ * Adds or removes mouse & touch events of the host element. (for handling auto-hiding of the scrollbars)
+ * @param destroy Indicates whether the events shall be added or removed.
+ */
+ function setupHostMouseTouchEvents(destroy) {
+ setupResponsiveEventListener(_hostElement,
+ _strMouseTouchMoveEvent,
+ hostOnMouseMove,
+ (_scrollbarsAutoHideMove ? destroy : true), true);
+ setupResponsiveEventListener(_hostElement,
+ [_strMouseTouchEnter, _strMouseTouchLeave],
+ [hostOnMouseEnter, hostOnMouseLeave],
+ (_scrollbarsAutoHideMove ? true : destroy), true);
+
+ //if the plugin is initialized and the mouse is over the host element, make the scrollbars visible
+ if (!_initialized && !destroy)
+ _hostElement.one('mouseover', hostOnMouseEnter);
+ }
+
+
+ //==== Update Detection ====//
+
+ /**
+ * Measures the min width and min height of the body element and refreshes the related cache.
+ * @returns {boolean} True if the min width or min height has changed, false otherwise.
+ */
+ function bodyMinSizeChanged() {
+ var bodyMinSize = {};
+ if (_isBody && _contentArrangeElement) {
+ bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth));
+ bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight));
+ bodyMinSize.c = checkCache(bodyMinSize, _bodyMinSizeCache);
+ bodyMinSize.f = true; //flag for "measured at least once"
+ }
+ _bodyMinSizeCache = bodyMinSize;
+ return !!bodyMinSize.c;
+ }
+
+ /**
+ * Returns true if the class names really changed (new class without plugin host prefix)
+ * @param oldCassNames The old ClassName string.
+ * @param newClassNames The new ClassName string.
+ * @returns {boolean} True if the class names has really changed, false otherwise.
+ */
+ function hostClassNamesChanged(oldCassNames, newClassNames) {
+ var currClasses = (newClassNames !== undefined && newClassNames !== null) ? newClassNames.split(_strSpace) : _strEmpty;
+ var oldClasses = (oldCassNames !== undefined && oldCassNames !== null) ? oldCassNames.split(_strSpace) : _strEmpty;
+ if (currClasses === _strEmpty && oldClasses === _strEmpty)
+ return false;
+ var diff = getArrayDifferences(oldClasses, currClasses);
+ var changed = false;
+ var oldClassNames = _oldClassName !== undefined && _oldClassName !== null ? _oldClassName.split(_strSpace) : [_strEmpty];
+ var currClassNames = _classNameCache !== undefined && _classNameCache !== null ? _classNameCache.split(_strSpace) : [_strEmpty];
+
+ //remove none theme from diff list to prevent update
+ var idx = inArray(_classNameThemeNone, diff);
+ var curr;
+ var i;
+ var v;
+ var o;
+ var c;
+
+ if (idx > -1)
+ diff.splice(idx, 1);
+
+ for (i = 0; i < diff.length; i++) {
+ curr = diff[i];
+ if (curr.indexOf(_classNameHostElement) !== 0) {
+ o = true;
+ c = true;
+ for (v = 0; v < oldClassNames.length; v++) {
+ if (curr === oldClassNames[v]) {
+ o = false;
+ break;
+ }
+ }
+ for (v = 0; v < currClassNames.length; v++) {
+ if (curr === currClassNames[v]) {
+ c = false;
+ break;
+ }
+ }
+ if (o && c) {
+ changed = true;
+ break;
+ }
+ }
+
+ }
+ return changed;
+ }
+
+ /**
+ * Returns true if the given mutation is not from a from the plugin generated element. If the target element is a textarea the mutation is always unknown.
+ * @param mutation The mutation which shall be checked.
+ * @returns {boolean} True if the mutation is from a unknown element, false otherwise.
+ */
+ function isUnknownMutation(mutation) {
+ var attributeName = mutation.attributeName;
+ var mutationTarget = mutation.target;
+ var mutationType = mutation.type;
+ var strClosest = 'closest';
+
+ if (mutationTarget === _contentElementNative)
+ return attributeName === null;
+ if (mutationType === 'attributes' && (attributeName === LEXICON.c || attributeName === LEXICON.s) && !_isTextarea) {
+ //ignore className changes by the plugin
+ if (attributeName === LEXICON.c && FRAMEWORK(mutationTarget).hasClass(_classNameHostElement))
+ return hostClassNamesChanged(mutation.oldValue, mutationTarget.getAttribute(LEXICON.c));
+
+ //only do it of browser support it natively
+ if (typeof mutationTarget[strClosest] != TYPES.f)
+ return true;
+ if (mutationTarget[strClosest](_strDot + _classNameResizeObserverElement) !== null ||
+ mutationTarget[strClosest](_strDot + _classNameScrollbar) !== null ||
+ mutationTarget[strClosest](_strDot + _classNameScrollbarCorner) !== null)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if the content size was changed since the last time this method was called.
+ * @returns {boolean} True if the content size was changed, false otherwise.
+ */
+ function updateAutoContentSizeChanged() {
+ if (_sleeping)
+ return false;
+
+ var contentMeasureElement = getContentMeasureElement();
+ var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0;
+ var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea;
+ var css = {};
+ var float;
+ var bodyMinSizeC;
+ var changed;
+ var contentElementScrollSize;
+
+ if (setCSS) {
+ float = _contentElement.css(_strFloat);
+ css[_strFloat] = _isRTL ? _strRight : _strLeft;
+ css[_strWidth] = _strAuto;
+ _contentElement.css(css);
+ }
+ contentElementScrollSize = {
+ w: contentMeasureElement[LEXICON.sW] + textareaValueLength,
+ h: contentMeasureElement[LEXICON.sH] + textareaValueLength
+ };
+ if (setCSS) {
+ css[_strFloat] = float;
+ css[_strWidth] = _strHundredPercent;
+ _contentElement.css(css);
+ }
+
+ bodyMinSizeC = bodyMinSizeChanged();
+ changed = checkCache(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache);
+
+ _contentElementScrollSizeChangeDetectedCache = contentElementScrollSize;
+
+ return changed || bodyMinSizeC;
+ }
+
+ /**
+ * Returns true when a attribute which the MutationObserver would observe has changed.
+ * @returns {boolean} True if one of the attributes which a MutationObserver would observe has changed, false or undefined otherwise.
+ */
+ function meaningfulAttrsChanged() {
+ if (_sleeping || _mutationObserversConnected)
+ return;
+
+ var elem;
+ var curr;
+ var cache;
+ var changedAttrs = [];
+ var checks = [
+ {
+ _elem: _hostElement,
+ _attrs: _mutationObserverAttrsHost.concat(':visible')
+ },
+ {
+ _elem: _isTextarea ? _targetElement : undefined,
+ _attrs: _mutationObserverAttrsTextarea
+ }
+ ];
+
+ each(checks, function (index, check) {
+ elem = check._elem;
+ if (elem) {
+ each(check._attrs, function (index, attr) {
+ curr = attr.charAt(0) === ':' ? elem.is(attr) : elem.attr(attr);
+ cache = _updateAutoCache[attr];
+
+ if(checkCache(curr, cache)) {
+ changedAttrs.push(attr);
+ }
+
+ _updateAutoCache[attr] = curr;
+ });
+ }
+ });
+
+ updateViewportAttrsFromTarget(changedAttrs);
+
+ return changedAttrs[LEXICON.l] > 0;
+ }
+
+ /**
+ * Checks is a CSS Property of a child element is affecting the scroll size of the content.
+ * @param propertyName The CSS property name.
+ * @returns {boolean} True if the property is affecting the content scroll size, false otherwise.
+ */
+ function isSizeAffectingCSSProperty(propertyName) {
+ if (!_initialized)
+ return true;
+ var flexGrow = 'flex-grow';
+ var flexShrink = 'flex-shrink';
+ var flexBasis = 'flex-basis';
+ var affectingPropsX = [
+ _strWidth,
+ _strMinMinus + _strWidth,
+ _strMaxMinus + _strWidth,
+ _strMarginMinus + _strLeft,
+ _strMarginMinus + _strRight,
+ _strLeft,
+ _strRight,
+ 'font-weight',
+ 'word-spacing',
+ flexGrow,
+ flexShrink,
+ flexBasis
+ ];
+ var affectingPropsXContentBox = [
+ _strPaddingMinus + _strLeft,
+ _strPaddingMinus + _strRight,
+ _strBorderMinus + _strLeft + _strWidth,
+ _strBorderMinus + _strRight + _strWidth
+ ];
+ var affectingPropsY = [
+ _strHeight,
+ _strMinMinus + _strHeight,
+ _strMaxMinus + _strHeight,
+ _strMarginMinus + _strTop,
+ _strMarginMinus + _strBottom,
+ _strTop,
+ _strBottom,
+ 'line-height',
+ flexGrow,
+ flexShrink,
+ flexBasis
+ ];
+ var affectingPropsYContentBox = [
+ _strPaddingMinus + _strTop,
+ _strPaddingMinus + _strBottom,
+ _strBorderMinus + _strTop + _strWidth,
+ _strBorderMinus + _strBottom + _strWidth
+ ];
+ var _strS = 's';
+ var _strVS = 'v-s';
+ var checkX = _overflowBehaviorCache.x === _strS || _overflowBehaviorCache.x === _strVS;
+ var checkY = _overflowBehaviorCache.y === _strS || _overflowBehaviorCache.y === _strVS;
+ var sizeIsAffected = false;
+ var checkPropertyName = function (arr, name) {
+ for (var i = 0; i < arr[LEXICON.l]; i++) {
+ if (arr[i] === name)
+ return true;
+ }
+ return false;
+ };
+
+ if (checkY) {
+ sizeIsAffected = checkPropertyName(affectingPropsY, propertyName);
+ if (!sizeIsAffected && !_isBorderBox)
+ sizeIsAffected = checkPropertyName(affectingPropsYContentBox, propertyName);
+ }
+ if (checkX && !sizeIsAffected) {
+ sizeIsAffected = checkPropertyName(affectingPropsX, propertyName);
+ if (!sizeIsAffected && !_isBorderBox)
+ sizeIsAffected = checkPropertyName(affectingPropsXContentBox, propertyName);
+ }
+ return sizeIsAffected;
+ }
+
+
+ //==== Update ====//
+
+ /**
+ * Sets the attribute values of the viewport element to the values from the target element.
+ * The value of a attribute is only set if the attribute is whitelisted.
+ * @attrs attrs The array of attributes which shall be set or undefined if all whitelisted shall be set.
+ */
+ function updateViewportAttrsFromTarget(attrs) {
+ attrs = attrs || _viewportAttrsFromTarget;
+ each(attrs, function (index, attr) {
+ if (COMPATIBILITY.inA(attr, _viewportAttrsFromTarget) > -1) {
+ var targetAttr = _targetElement.attr(attr);
+ if(type(targetAttr) == TYPES.s) {
+ _viewportElement.attr(attr, targetAttr);
+ }
+ else {
+ _viewportElement.removeAttr(attr);
+ }
+ }
+ });
+ }
+
+ /**
+ * Updates the variables and size of the textarea element, and manages the scroll on new line or new character.
+ */
+ function textareaUpdate() {
+ if (!_sleeping) {
+ var wrapAttrOff = !_textareaAutoWrappingCache;
+ var minWidth = _viewportSize.w;
+ var minHeight = _viewportSize.h;
+ var css = {};
+ var doMeasure = _widthAutoCache || wrapAttrOff;
+ var origWidth;
+ var width;
+ var origHeight;
+ var height;
+
+ //reset min size
+ css[_strMinMinus + _strWidth] = _strEmpty;
+ css[_strMinMinus + _strHeight] = _strEmpty;
+
+ //set width auto
+ css[_strWidth] = _strAuto;
+ _targetElement.css(css);
+
+ //measure width
+ origWidth = _targetElementNative[LEXICON.oW];
+ width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1;
+ /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/
+
+ //set measured width
+ css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent;
+ css[_strMinMinus + _strWidth] = _strHundredPercent;
+
+ //set height auto
+ css[_strHeight] = _strAuto;
+ _targetElement.css(css);
+
+ //measure height
+ origHeight = _targetElementNative[LEXICON.oH];
+ height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1);
+
+ //append correct size values
+ css[_strWidth] = width;
+ css[_strHeight] = height;
+ _textareaCoverElement.css(css);
+
+ //apply min width / min height to prevent textarea collapsing
+ css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/;
+ css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/;
+ _targetElement.css(css);
+
+ return {
+ _originalWidth: origWidth,
+ _originalHeight: origHeight,
+ _dynamicWidth: width,
+ _dynamicHeight: height
+ };
+ }
+ }
+
+ /**
+ * Updates the plugin and DOM to the current options.
+ * This method should only be called if a update is 100% required.
+ * @param updateHints A objects which contains hints for this update:
+ * {
+ * _hostSizeChanged : boolean,
+ * _contentSizeChanged : boolean,
+ * _force : boolean, == preventSwallowing
+ * _changedOptions : { }, == preventSwallowing && preventSleep
+ * }
+ */
+ function update(updateHints) {
+ clearTimeout(_swallowedUpdateTimeout);
+ updateHints = updateHints || {};
+ _swallowedUpdateHints._hostSizeChanged |= updateHints._hostSizeChanged;
+ _swallowedUpdateHints._contentSizeChanged |= updateHints._contentSizeChanged;
+ _swallowedUpdateHints._force |= updateHints._force;
+
+ var now = COMPATIBILITY.now();
+ var hostSizeChanged = !!_swallowedUpdateHints._hostSizeChanged;
+ var contentSizeChanged = !!_swallowedUpdateHints._contentSizeChanged;
+ var force = !!_swallowedUpdateHints._force;
+ var changedOptions = updateHints._changedOptions;
+ var swallow = _swallowUpdateLag > 0 && _initialized && !_destroyed && !force && !changedOptions && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache);
+ var displayIsHidden;
+
+ if (swallow)
+ _swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag);
+
+ //abort update due to:
+ //destroyed
+ //swallowing
+ //sleeping
+ //host is hidden or has false display
+ if (_destroyed || swallow || (_sleeping && !changedOptions) || (_initialized && !force && (displayIsHidden = _hostElement.is(':hidden'))) || _hostElement.css('display') === 'inline')
+ return;
+
+ _lastUpdateTime = now;
+ _swallowedUpdateHints = {};
+
+ //if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely.
+ if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
+ //native scrollbars are hidden, so change the values to zero
+ _nativeScrollbarSize.x = 0;
+ _nativeScrollbarSize.y = 0;
+ }
+ else {
+ //refresh native scrollbar size (in case of zoom)
+ _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
+ }
+
+ // Scrollbar padding is needed for firefox, because firefox hides scrollbar automatically if the size of the div is too small.
+ // The calculation: [scrollbar size +3 *3]
+ // (+3 because of possible decoration e.g. borders, margins etc., but only if native scrollbar is NOT a overlaid scrollbar)
+ // (*3 because (1)increase / (2)decrease -button and (3)resize handle)
+ _nativeScrollbarMinSize = {
+ x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3,
+ y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 3
+ };
+
+ //changedOptions = changedOptions || { };
+ //freezeResizeObserver(_sizeObserverElement, true);
+ //freezeResizeObserver(_sizeAutoObserverElement, true);
+
+ var checkCacheAutoForce = function () {
+ return checkCache.apply(this, [].slice.call(arguments).concat([force]));
+ };
+
+ //save current scroll offset
+ var currScroll = {
+ x: _viewportElement[_strScrollLeft](),
+ y: _viewportElement[_strScrollTop]()
+ };
+
+ var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars;
+ var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea;
+
+ //scrollbars visibility:
+ var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility;
+ var scrollbarsVisibilityChanged = checkCacheAutoForce(scrollbarsVisibility, _scrollbarsVisibilityCache);
+
+ //scrollbars autoHide:
+ var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide;
+ var scrollbarsAutoHideChanged = checkCacheAutoForce(scrollbarsAutoHide, _scrollbarsAutoHideCache);
+
+ //scrollbars click scrolling
+ var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling;
+ var scrollbarsClickScrollingChanged = checkCacheAutoForce(scrollbarsClickScrolling, _scrollbarsClickScrollingCache);
+
+ //scrollbars drag scrolling
+ var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling;
+ var scrollbarsDragScrollingChanged = checkCacheAutoForce(scrollbarsDragScrolling, _scrollbarsDragScrollingCache);
+
+ //className
+ var className = _currentPreparedOptions.className;
+ var classNameChanged = checkCacheAutoForce(className, _classNameCache);
+
+ //resize
+ var resize = _currentPreparedOptions.resize;
+ var resizeChanged = checkCacheAutoForce(resize, _resizeCache) && !_isBody; //body can't be resized since the window itself acts as resize possibility.
+
+ //paddingAbsolute
+ var paddingAbsolute = _currentPreparedOptions.paddingAbsolute;
+ var paddingAbsoluteChanged = checkCacheAutoForce(paddingAbsolute, _paddingAbsoluteCache);
+
+ //clipAlways
+ var clipAlways = _currentPreparedOptions.clipAlways;
+ var clipAlwaysChanged = checkCacheAutoForce(clipAlways, _clipAlwaysCache);
+
+ //sizeAutoCapable
+ var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport.
+ var sizeAutoCapableChanged = checkCacheAutoForce(sizeAutoCapable, _sizeAutoCapableCache);
+
+ //showNativeScrollbars
+ var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars;
+ var ignoreOverlayScrollbarHidingChanged = checkCacheAutoForce(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache);
+
+ //autoUpdate
+ var autoUpdate = _currentPreparedOptions.autoUpdate;
+ var autoUpdateChanged = checkCacheAutoForce(autoUpdate, _autoUpdateCache);
+
+ //overflowBehavior
+ var overflowBehavior = _currentPreparedOptions.overflowBehavior;
+ var overflowBehaviorChanged = checkCacheAutoForce(overflowBehavior, _overflowBehaviorCache, force);
+
+ //dynWidth:
+ var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth;
+ var textareaDynWidthChanged = checkCacheAutoForce(_textareaDynWidthCache, textareaDynWidth);
+
+ //dynHeight:
+ var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight;
+ var textareaDynHeightChanged = checkCacheAutoForce(_textareaDynHeightCache, textareaDynHeight);
+
+ //scrollbars visibility
+ _scrollbarsAutoHideNever = scrollbarsAutoHide === 'n';
+ _scrollbarsAutoHideScroll = scrollbarsAutoHide === 's';
+ _scrollbarsAutoHideMove = scrollbarsAutoHide === 'm';
+ _scrollbarsAutoHideLeave = scrollbarsAutoHide === 'l';
+
+ //scrollbars autoHideDelay
+ _scrollbarsAutoHideDelay = currentPreparedOptionsScrollbars.autoHideDelay;
+
+ //old className
+ _oldClassName = _classNameCache;
+
+ //resize
+ _resizeNone = resize === 'n';
+ _resizeBoth = resize === 'b';
+ _resizeHorizontal = resize === 'h';
+ _resizeVertical = resize === 'v';
+
+ //normalizeRTL
+ _normalizeRTLCache = _currentPreparedOptions.normalizeRTL;
+
+ //ignore overlay scrollbar hiding
+ ignoreOverlayScrollbarHiding = ignoreOverlayScrollbarHiding && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y);
+
+ //refresh options cache
+ _scrollbarsVisibilityCache = scrollbarsVisibility;
+ _scrollbarsAutoHideCache = scrollbarsAutoHide;
+ _scrollbarsClickScrollingCache = scrollbarsClickScrolling;
+ _scrollbarsDragScrollingCache = scrollbarsDragScrolling;
+ _classNameCache = className;
+ _resizeCache = resize;
+ _paddingAbsoluteCache = paddingAbsolute;
+ _clipAlwaysCache = clipAlways;
+ _sizeAutoCapableCache = sizeAutoCapable;
+ _ignoreOverlayScrollbarHidingCache = ignoreOverlayScrollbarHiding;
+ _autoUpdateCache = autoUpdate;
+ _overflowBehaviorCache = extendDeep({}, overflowBehavior);
+ _textareaDynWidthCache = textareaDynWidth;
+ _textareaDynHeightCache = textareaDynHeight;
+ _hasOverflowCache = _hasOverflowCache || { x: false, y: false };
+
+ //set correct class name to the host element
+ if (classNameChanged) {
+ removeClass(_hostElement, _oldClassName + _strSpace + _classNameThemeNone);
+ addClass(_hostElement, className !== undefined && className !== null && className.length > 0 ? className : _classNameThemeNone);
+ }
+
+ //set correct auto Update
+ if (autoUpdateChanged) {
+ if (autoUpdate === true) {
+ disconnectMutationObservers();
+ autoUpdateLoop.add(_base);
+ }
+ else if (autoUpdate === null) {
+ if (_autoUpdateRecommended) {
+ disconnectMutationObservers();
+ autoUpdateLoop.add(_base);
+ }
+ else {
+ autoUpdateLoop.remove(_base);
+ connectMutationObservers();
+ }
+ }
+ else {
+ autoUpdateLoop.remove(_base);
+ connectMutationObservers();
+ }
+ }
+
+ //activate or deactivate size auto capability
+ if (sizeAutoCapableChanged) {
+ if (sizeAutoCapable) {
+ if (!_contentGlueElement) {
+ _contentGlueElement = FRAMEWORK(generateDiv(_classNameContentGlueElement));
+ _paddingElement.before(_contentGlueElement);
+ }
+ else {
+ _contentGlueElement.show();
+ }
+ if (_sizeAutoObserverAdded) {
+ _sizeAutoObserverElement.show();
+ }
+ else {
+ _sizeAutoObserverElement = FRAMEWORK(generateDiv(_classNameSizeAutoObserverElement));
+ _sizeAutoObserverElementNative = _sizeAutoObserverElement[0];
+
+ _contentGlueElement.before(_sizeAutoObserverElement);
+ var oldSize = { w: -1, h: -1 };
+ setupResizeObserver(_sizeAutoObserverElement, function () {
+ var newSize = {
+ w: _sizeAutoObserverElementNative[LEXICON.oW],
+ h: _sizeAutoObserverElementNative[LEXICON.oH]
+ };
+ if (checkCache(newSize, oldSize)) {
+ if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) {
+ update();
+ }
+ else if (_initialized && (!_heightAutoCache && newSize.h === 0) || (!_widthAutoCache && newSize.w === 0)) {
+ update();
+ }
+ }
+ oldSize = newSize;
+ });
+ _sizeAutoObserverAdded = true;
+ //fix heightAuto detector bug if height is fixed but contentHeight is 0.
+ //the probability this bug will ever happen is very very low, thats why its ok if we use calc which isn't supported in IE8.
+ if (_cssCalc !== null)
+ _sizeAutoObserverElement.css(_strHeight, _cssCalc + '(100% + 1px)');
+ }
+ }
+ else {
+ if (_sizeAutoObserverAdded)
+ _sizeAutoObserverElement.hide();
+ if (_contentGlueElement)
+ _contentGlueElement.hide();
+ }
+ }
+
+ //if force, update all resizeObservers too
+ if (force) {
+ _sizeObserverElement.find('*').trigger(_strScroll);
+ if (_sizeAutoObserverAdded)
+ _sizeAutoObserverElement.find('*').trigger(_strScroll);
+ }
+
+ //display hidden:
+ displayIsHidden = displayIsHidden === undefined ? _hostElement.is(':hidden') : displayIsHidden;
+ var displayIsHiddenChanged = checkCacheAutoForce(displayIsHidden, _displayIsHiddenCache);
+
+ //textarea AutoWrapping:
+ var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false;
+ var textareaAutoWrappingChanged = checkCacheAutoForce(textareaAutoWrapping, _textareaAutoWrappingCache);
+
+ //detect direction:
+ var cssDirection = _hostElement.css('direction');
+ var cssDirectionChanged = checkCacheAutoForce(cssDirection, _cssDirectionCache);
+
+ //detect box-sizing:
+ var boxSizing = _hostElement.css('box-sizing');
+ var boxSizingChanged = checkCacheAutoForce(boxSizing, _cssBoxSizingCache);
+
+ //detect padding:
+ var padding = {
+ c: force,
+ t: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strTop)),
+ r: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strRight)),
+ b: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strBottom)),
+ l: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strLeft))
+ };
+
+ //width + height auto detecting var:
+ var sizeAutoObserverElementBCRect;
+ //exception occurs in IE8 sometimes (unknown exception)
+ try {
+ sizeAutoObserverElementBCRect = _sizeAutoObserverAdded ? _sizeAutoObserverElementNative[LEXICON.bCR]() : null;
+ } catch (ex) {
+ return;
+ }
+
+ _isRTL = cssDirection === 'rtl';
+ _isBorderBox = (boxSizing === 'border-box');
+ var isRTLLeft = _isRTL ? _strLeft : _strRight;
+ var isRTLRight = _isRTL ? _strRight : _strLeft;
+
+ //detect width auto:
+ var widthAutoResizeDetection = false;
+ var widthAutoObserverDetection = (_sizeAutoObserverAdded && (_hostElement.css(_strFloat) !== 'none' /*|| _isTextarea */)) ? (MATH.round(sizeAutoObserverElementBCRect.right - sizeAutoObserverElementBCRect.left) === 0) && (!paddingAbsolute ? (_hostElementNative[LEXICON.cW] - _paddingX) > 0 : true) : false;
+ if (sizeAutoCapable && !widthAutoObserverDetection) {
+ var tmpCurrHostWidth = _hostElementNative[LEXICON.oW];
+ var tmpCurrContentGlueWidth = _contentGlueElement.css(_strWidth);
+ _contentGlueElement.css(_strWidth, _strAuto);
+
+ var tmpNewHostWidth = _hostElementNative[LEXICON.oW];
+ _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
+ widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
+ if (!widthAutoResizeDetection) {
+ _contentGlueElement.css(_strWidth, tmpCurrHostWidth + 1);
+ tmpNewHostWidth = _hostElementNative[LEXICON.oW];
+ _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
+ widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
+ }
+ }
+ var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden;
+ var widthAutoChanged = checkCacheAutoForce(widthAuto, _widthAutoCache);
+ var wasWidthAuto = !widthAuto && _widthAutoCache;
+
+ //detect height auto:
+ var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false;
+ var heightAutoChanged = checkCacheAutoForce(heightAuto, _heightAutoCache);
+ var wasHeightAuto = !heightAuto && _heightAutoCache;
+
+ //detect border:
+ //we need the border only if border box and auto size
+ var strMinusWidth = '-' + _strWidth;
+ var updateBorderX = (widthAuto && _isBorderBox) || !_isBorderBox;
+ var updateBorderY = (heightAuto && _isBorderBox) || !_isBorderBox;
+ var border = {
+ c: force,
+ t: updateBorderY ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strTop + strMinusWidth), true) : 0,
+ r: updateBorderX ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strRight + strMinusWidth), true) : 0,
+ b: updateBorderY ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strBottom + strMinusWidth), true) : 0,
+ l: updateBorderX ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strLeft + strMinusWidth), true) : 0
+ };
+
+ //detect margin:
+ var margin = {
+ c: force,
+ t: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strTop)),
+ r: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strRight)),
+ b: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strBottom)),
+ l: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strLeft))
+ };
+
+ //detect css max width & height:
+ var cssMaxValue = {
+ h: String(_hostElement.css(_strMaxMinus + _strHeight)),
+ w: String(_hostElement.css(_strMaxMinus + _strWidth))
+ };
+
+ //vars to apply correct css
+ var contentElementCSS = {};
+ var contentGlueElementCSS = {};
+
+ //funcs
+ var getHostSize = function () {
+ //has to be clientSize because offsetSize respect borders
+ return {
+ w: _hostElementNative[LEXICON.cW],
+ h: _hostElementNative[LEXICON.cH]
+ };
+ };
+ var getViewportSize = function () {
+ //viewport size is padding container because it never has padding, margin and a border
+ //determine zoom rounding error -> sometimes scrollWidth/Height is smaller than clientWidth/Height
+ //if this happens add the difference to the viewportSize to compensate the rounding error
+ return {
+ w: _paddingElementNative[LEXICON.oW] + MATH.max(0, _contentElementNative[LEXICON.cW] - _contentElementNative[LEXICON.sW]),
+ h: _paddingElementNative[LEXICON.oH] + MATH.max(0, _contentElementNative[LEXICON.cH] - _contentElementNative[LEXICON.sH])
+ };
+ };
+
+ //set info for padding
+ var paddingAbsoluteX = _paddingX = padding.l + padding.r;
+ var paddingAbsoluteY = _paddingY = padding.t + padding.b;
+ paddingAbsoluteX *= paddingAbsolute ? 1 : 0;
+ paddingAbsoluteY *= paddingAbsolute ? 1 : 0;
+ padding.c = checkCacheAutoForce(padding, _cssPaddingCache);
+
+ //set info for border
+ _borderX = border.l + border.r;
+ _borderY = border.t + border.b;
+ border.c = checkCacheAutoForce(border, _cssBorderCache);
+
+ //set info for margin
+ _marginX = margin.l + margin.r;
+ _marginY = margin.t + margin.b;
+ margin.c = checkCacheAutoForce(margin, _cssMarginCache);
+
+ //set info for css max value
+ cssMaxValue.ih = parseToZeroOrNumber(cssMaxValue.h); //ih = integer height
+ cssMaxValue.iw = parseToZeroOrNumber(cssMaxValue.w); //iw = integer width
+ cssMaxValue.ch = cssMaxValue.h.indexOf('px') > -1; //ch = correct height
+ cssMaxValue.cw = cssMaxValue.w.indexOf('px') > -1; //cw = correct width
+ cssMaxValue.c = checkCacheAutoForce(cssMaxValue, _cssMaxValueCache);
+
+ //refresh cache
+ _displayIsHiddenCache = displayIsHidden;
+ _textareaAutoWrappingCache = textareaAutoWrapping;
+ _cssDirectionCache = cssDirection;
+ _cssBoxSizingCache = boxSizing;
+ _widthAutoCache = widthAuto;
+ _heightAutoCache = heightAuto;
+ _cssPaddingCache = padding;
+ _cssBorderCache = border;
+ _cssMarginCache = margin;
+ _cssMaxValueCache = cssMaxValue;
+
+ //IEFix direction changed
+ if (cssDirectionChanged && _sizeAutoObserverAdded)
+ _sizeAutoObserverElement.css(_strFloat, isRTLRight);
+
+ //apply padding:
+ if (padding.c || cssDirectionChanged || paddingAbsoluteChanged || widthAutoChanged || heightAutoChanged || boxSizingChanged || sizeAutoCapableChanged) {
+ var paddingElementCSS = {};
+ var textareaCSS = {};
+ setTopRightBottomLeft(contentGlueElementCSS, _strMarginMinus, [-padding.t, -padding.r, -padding.b, -padding.l]);
+ if (paddingAbsolute) {
+ setTopRightBottomLeft(paddingElementCSS, _strEmpty, [padding.t, padding.r, padding.b, padding.l]);
+ if (_isTextarea)
+ setTopRightBottomLeft(textareaCSS, _strPaddingMinus);
+ else
+ setTopRightBottomLeft(contentElementCSS, _strPaddingMinus);
+ }
+ else {
+ setTopRightBottomLeft(paddingElementCSS, _strEmpty);
+ if (_isTextarea)
+ setTopRightBottomLeft(textareaCSS, _strPaddingMinus, [padding.t, padding.r, padding.b, padding.l]);
+ else
+ setTopRightBottomLeft(contentElementCSS, _strPaddingMinus, [padding.t, padding.r, padding.b, padding.l]);
+ }
+ _paddingElement.css(paddingElementCSS);
+ _targetElement.css(textareaCSS);
+ }
+
+ //viewport size is padding container because it never has padding, margin and a border.
+ _viewportSize = getViewportSize();
+
+ //update Textarea
+ var textareaSize = _isTextarea ? textareaUpdate() : false;
+ var textareaSizeChanged = _isTextarea && checkCacheAutoForce(textareaSize, _textareaSizeCache);
+ var textareaDynOrigSize = _isTextarea && textareaSize ? {
+ w: textareaDynWidth ? textareaSize._dynamicWidth : textareaSize._originalWidth,
+ h: textareaDynHeight ? textareaSize._dynamicHeight : textareaSize._originalHeight
+ } : {};
+ _textareaSizeCache = textareaSize;
+
+ //fix height auto / width auto in cooperation with current padding & boxSizing behavior:
+ if (heightAuto && (heightAutoChanged || paddingAbsoluteChanged || boxSizingChanged || cssMaxValue.c || padding.c || border.c)) {
+ /*
+ if (cssMaxValue.ch)
+ contentElementCSS[_strMaxMinus + _strHeight] =
+ (cssMaxValue.ch ? (cssMaxValue.ih - paddingAbsoluteY + (_isBorderBox ? -_borderY : _paddingY))
+ : _strEmpty);
+ */
+ contentElementCSS[_strHeight] = _strAuto;
+ }
+ else if (heightAutoChanged || paddingAbsoluteChanged) {
+ contentElementCSS[_strMaxMinus + _strHeight] = _strEmpty;
+ contentElementCSS[_strHeight] = _strHundredPercent;
+ }
+ if (widthAuto && (widthAutoChanged || paddingAbsoluteChanged || boxSizingChanged || cssMaxValue.c || padding.c || border.c || cssDirectionChanged)) {
+ /*
+ if (cssMaxValue.cw)
+ contentElementCSS[_strMaxMinus + _strWidth] =
+ (cssMaxValue.cw ? (cssMaxValue.iw - paddingAbsoluteX + (_isBorderBox ? -_borderX : _paddingX)) +
+ (_nativeScrollbarIsOverlaid.y ? _overlayScrollbarDummySize.y : 0)
+ : _strEmpty);
+ */
+ contentElementCSS[_strWidth] = _strAuto;
+ contentGlueElementCSS[_strMaxMinus + _strWidth] = _strHundredPercent; //IE Fix
+ }
+ else if (widthAutoChanged || paddingAbsoluteChanged) {
+ contentElementCSS[_strMaxMinus + _strWidth] = _strEmpty;
+ contentElementCSS[_strWidth] = _strHundredPercent;
+ contentElementCSS[_strFloat] = _strEmpty;
+ contentGlueElementCSS[_strMaxMinus + _strWidth] = _strEmpty; //IE Fix
+ }
+ if (widthAuto) {
+ if (!cssMaxValue.cw)
+ contentElementCSS[_strMaxMinus + _strWidth] = _strEmpty;
+ //textareaDynOrigSize.w || _strAuto :: doesnt works because applied margin will shift width
+ contentGlueElementCSS[_strWidth] = _strAuto;
+
+ contentElementCSS[_strWidth] = _strAuto;
+ contentElementCSS[_strFloat] = isRTLRight;
+ }
+ else {
+ contentGlueElementCSS[_strWidth] = _strEmpty;
+ }
+ if (heightAuto) {
+ if (!cssMaxValue.ch)
+ contentElementCSS[_strMaxMinus + _strHeight] = _strEmpty;
+ //textareaDynOrigSize.h || _contentElementNative[LEXICON.cH] :: use for anti scroll jumping
+ contentGlueElementCSS[_strHeight] = textareaDynOrigSize.h || _contentElementNative[LEXICON.cH];
+ }
+ else {
+ contentGlueElementCSS[_strHeight] = _strEmpty;
+ }
+ if (sizeAutoCapable)
+ _contentGlueElement.css(contentGlueElementCSS);
+ _contentElement.css(contentElementCSS);
+
+ //CHECKPOINT HERE ~
+ contentElementCSS = {};
+ contentGlueElementCSS = {};
+
+ //if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true
+ if (hostSizeChanged || contentSizeChanged || textareaSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || cssMaxValue.c || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged) {
+ var strOverflow = 'overflow';
+ var strOverflowX = strOverflow + '-x';
+ var strOverflowY = strOverflow + '-y';
+ var strHidden = 'hidden';
+ var strVisible = 'visible';
+
+ //Reset the viewport (very important for natively overlaid scrollbars and zoom change
+ //don't change the overflow prop as it is very expensive and affects performance !A LOT!
+ if(!_nativeScrollbarStyling) {
+ var viewportElementResetCSS = {};
+ var resetXTmp = _hasOverflowCache.y && _hideOverflowCache.ys && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.y ? _viewportElement.css(isRTLLeft) : -_nativeScrollbarSize.y) : 0;
+ var resetBottomTmp = _hasOverflowCache.x && _hideOverflowCache.xs && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.x ? _viewportElement.css(_strBottom) : -_nativeScrollbarSize.x) : 0;
+ setTopRightBottomLeft(viewportElementResetCSS, _strEmpty);
+ _viewportElement.css(viewportElementResetCSS);
+ }
+
+ //measure several sizes:
+ var contentMeasureElement = getContentMeasureElement();
+ //in Firefox content element has to have overflow hidden, else element margins aren't calculated properly, this element prevents this bug, but only if scrollbars aren't overlaid
+ var contentSize = {
+ //use clientSize because natively overlaidScrollbars add borders
+ w: textareaDynOrigSize.w || contentMeasureElement[LEXICON.cW],
+ h: textareaDynOrigSize.h || contentMeasureElement[LEXICON.cH]
+ };
+ var scrollSize = {
+ w: contentMeasureElement[LEXICON.sW],
+ h: contentMeasureElement[LEXICON.sH]
+ };
+
+ //apply the correct viewport style and measure viewport size
+ if(!_nativeScrollbarStyling) {
+ viewportElementResetCSS[_strBottom] = wasHeightAuto ? _strEmpty : resetBottomTmp;
+ viewportElementResetCSS[isRTLLeft] = wasWidthAuto ? _strEmpty : resetXTmp;
+ _viewportElement.css(viewportElementResetCSS);
+ }
+ _viewportSize = getViewportSize();
+
+ //measure and correct several sizes
+ var hostSize = getHostSize();
+ var contentGlueSize = {
+ //client/scrollSize + AbsolutePadding -> because padding is only applied to the paddingElement if its absolute, so you have to add it manually
+ //hostSize is clientSize -> so padding should be added manually, right? FALSE! Because content glue is inside hostElement, so we don't have to worry about padding
+ w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostSize.w),
+ h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostSize.h)
+ };
+ contentGlueSize.c = checkCacheAutoForce(contentGlueSize, _contentGlueSizeCache);
+ _contentGlueSizeCache = contentGlueSize;
+
+ //apply correct contentGlue size
+ if (sizeAutoCapable) {
+ //size contentGlue correctly to make sure the element has correct size if the sizing switches to auto
+ if (contentGlueSize.c || (heightAuto || widthAuto)) {
+ contentGlueElementCSS[_strWidth] = contentGlueSize.w;
+ contentGlueElementCSS[_strHeight] = contentGlueSize.h;
+
+ //textarea-sizes are already calculated correctly at this point
+ if (!_isTextarea) {
+ contentSize = {
+ //use clientSize because natively overlaidScrollbars add borders
+ w: contentMeasureElement[LEXICON.cW],
+ h: contentMeasureElement[LEXICON.cH]
+ };
+ }
+ }
+ var textareaCoverCSS = {};
+ var setContentGlueElementCSSfunction = function (horizontal) {
+ var scrollbarVars = getScrollbarVars(horizontal);
+ var wh = scrollbarVars._w_h;
+ var strWH = scrollbarVars._width_height;
+ var autoSize = horizontal ? widthAuto : heightAuto;
+ var borderSize = horizontal ? _borderX : _borderY;
+ var paddingSize = horizontal ? _paddingX : _paddingY;
+ var marginSize = horizontal ? _marginX : _marginY;
+ var maxSize = contentGlueElementCSS[strWH] + (_isBorderBox ? borderSize : -paddingSize);
+
+ //make contentGlue size -1 if element is not auto sized, to make sure that a resize event happens when the element shrinks
+ if (!autoSize || (!autoSize && border.c))
+ contentGlueElementCSS[strWH] = hostSize[wh] - (_isBorderBox ? 0 : paddingSize + borderSize) - 1 - marginSize;
+
+ //if size is auto and host is same size as max size, make content glue size +1 to make sure size changes will be detected
+ if (autoSize && cssMaxValue['c' + wh] && cssMaxValue['i' + wh] === maxSize)
+ contentGlueElementCSS[strWH] = maxSize + (_isBorderBox ? 0 : paddingSize) + 1;
+
+ //if size is auto and host is smaller than size as min size, make content glue size -1 to make sure size changes will be detected (this is only needed if padding is 0)
+ if (autoSize && (contentSize[wh] < _viewportSize[wh]) && (horizontal && _isTextarea ? !textareaAutoWrapping : true)) {
+ if (_isTextarea)
+ textareaCoverCSS[strWH] = parseToZeroOrNumber(_textareaCoverElement.css(strWH)) - 1;
+ contentGlueElementCSS[strWH] -= 1;
+ }
+
+ //make sure content glue size is at least 1
+ if (contentSize[wh] > 0)
+ contentGlueElementCSS[strWH] = MATH.max(1, contentGlueElementCSS[strWH]);
+ };
+ setContentGlueElementCSSfunction(true);
+ setContentGlueElementCSSfunction(false);
+
+ if (_isTextarea)
+ _textareaCoverElement.css(textareaCoverCSS);
+ _contentGlueElement.css(contentGlueElementCSS);
+ }
+ if (widthAuto)
+ contentElementCSS[_strWidth] = _strHundredPercent;
+ if (widthAuto && !_isBorderBox && !_mutationObserversConnected)
+ contentElementCSS[_strFloat] = 'none';
+
+ //apply and reset content style
+ _contentElement.css(contentElementCSS);
+ contentElementCSS = {};
+
+ //measure again, but this time all correct sizes:
+ var contentScrollSize = {
+ w: contentMeasureElement[LEXICON.sW],
+ h: contentMeasureElement[LEXICON.sH],
+ };
+ contentScrollSize.c = contentSizeChanged = checkCacheAutoForce(contentScrollSize, _contentScrollSizeCache);
+ _contentScrollSizeCache = contentScrollSize;
+
+ //refresh viewport size after correct measuring
+ _viewportSize = getViewportSize();
+
+ hostSize = getHostSize();
+ hostSizeChanged = checkCacheAutoForce(hostSize, _hostSizeCache);
+ _hostSizeCache = hostSize;
+
+ var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0);
+ var previousOverflowAmount = _overflowAmountCache;
+ var overflowBehaviorIsVS = {};
+ var overflowBehaviorIsVH = {};
+ var overflowBehaviorIsS = {};
+ var overflowAmount = {};
+ var hasOverflow = {};
+ var hideOverflow = {};
+ var canScroll = {};
+ var viewportRect = _paddingElementNative[LEXICON.bCR]();
+ var setOverflowVariables = function (horizontal) {
+ var scrollbarVars = getScrollbarVars(horizontal);
+ var scrollbarVarsInverted = getScrollbarVars(!horizontal);
+ var xyI = scrollbarVarsInverted._x_y;
+ var xy = scrollbarVars._x_y;
+ var wh = scrollbarVars._w_h;
+ var widthHeight = scrollbarVars._width_height;
+ var scrollMax = _strScroll + scrollbarVars._Left_Top + 'Max';
+ var fractionalOverflowAmount = viewportRect[widthHeight] ? MATH.abs(viewportRect[widthHeight] - _viewportSize[wh]) : 0;
+ var checkFractionalOverflowAmount = previousOverflowAmount && previousOverflowAmount[xy] > 0 && _viewportElementNative[scrollMax] === 0;
+ overflowBehaviorIsVS[xy] = overflowBehavior[xy] === 'v-s';
+ overflowBehaviorIsVH[xy] = overflowBehavior[xy] === 'v-h';
+ overflowBehaviorIsS[xy] = overflowBehavior[xy] === 's';
+ overflowAmount[xy] = MATH.max(0, MATH.round((contentScrollSize[wh] - _viewportSize[wh]) * 100) / 100);
+ overflowAmount[xy] *= (hideOverflowForceTextarea || (checkFractionalOverflowAmount && fractionalOverflowAmount > 0 && fractionalOverflowAmount < 1)) ? 0 : 1;
+ hasOverflow[xy] = overflowAmount[xy] > 0;
+
+ //hideOverflow:
+ //x || y : true === overflow is hidden by "overflow: scroll" OR "overflow: hidden"
+ //xs || ys : true === overflow is hidden by "overflow: scroll"
+ hideOverflow[xy] = overflowBehaviorIsVS[xy] || overflowBehaviorIsVH[xy] ? (hasOverflow[xyI] && !overflowBehaviorIsVS[xyI] && !overflowBehaviorIsVH[xyI]) : hasOverflow[xy];
+ hideOverflow[xy + 's'] = hideOverflow[xy] ? (overflowBehaviorIsS[xy] || overflowBehaviorIsVS[xy]) : false;
+
+ canScroll[xy] = hasOverflow[xy] && hideOverflow[xy + 's'];
+ };
+ setOverflowVariables(true);
+ setOverflowVariables(false);
+
+ overflowAmount.c = checkCacheAutoForce(overflowAmount, _overflowAmountCache);
+ _overflowAmountCache = overflowAmount;
+ hasOverflow.c = checkCacheAutoForce(hasOverflow, _hasOverflowCache);
+ _hasOverflowCache = hasOverflow;
+ hideOverflow.c = checkCacheAutoForce(hideOverflow, _hideOverflowCache);
+ _hideOverflowCache = hideOverflow;
+
+ //if native scrollbar is overlay at x OR y axis, prepare DOM
+ if (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) {
+ var borderDesign = 'px solid transparent';
+ var contentArrangeElementCSS = {};
+ var arrangeContent = {};
+ var arrangeChanged = force;
+ var setContentElementCSS;
+
+ if (hasOverflow.x || hasOverflow.y) {
+ arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty;
+ arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty;
+ arrangeChanged = checkCacheAutoForce(arrangeContent, _arrangeContentSizeCache);
+ _arrangeContentSizeCache = arrangeContent;
+ }
+
+ if (hasOverflow.c || hideOverflow.c || contentScrollSize.c || cssDirectionChanged || widthAutoChanged || heightAutoChanged || widthAuto || heightAuto || ignoreOverlayScrollbarHidingChanged) {
+ contentElementCSS[_strMarginMinus + isRTLRight] = contentElementCSS[_strBorderMinus + isRTLRight] = _strEmpty;
+ setContentElementCSS = function (horizontal) {
+ var scrollbarVars = getScrollbarVars(horizontal);
+ var scrollbarVarsInverted = getScrollbarVars(!horizontal);
+ var xy = scrollbarVars._x_y;
+ var strDirection = horizontal ? _strBottom : isRTLLeft;
+ var invertedAutoSize = horizontal ? heightAuto : widthAuto;
+
+ if (_nativeScrollbarIsOverlaid[xy] && hasOverflow[xy] && hideOverflow[xy + 's']) {
+ contentElementCSS[_strMarginMinus + strDirection] = invertedAutoSize ? (ignoreOverlayScrollbarHiding ? _strEmpty : _overlayScrollbarDummySize[xy]) : _strEmpty;
+ contentElementCSS[_strBorderMinus + strDirection] = ((horizontal ? !invertedAutoSize : true) && !ignoreOverlayScrollbarHiding) ? (_overlayScrollbarDummySize[xy] + borderDesign) : _strEmpty;
+ }
+ else {
+ arrangeContent[scrollbarVarsInverted._w_h] =
+ contentElementCSS[_strMarginMinus + strDirection] =
+ contentElementCSS[_strBorderMinus + strDirection] = _strEmpty;
+ arrangeChanged = true;
+ }
+ };
+
+ if (_nativeScrollbarStyling) {
+ if (ignoreOverlayScrollbarHiding)
+ removeClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
+ else
+ addClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
+ }
+ else {
+ setContentElementCSS(true);
+ setContentElementCSS(false);
+ }
+ }
+ if (ignoreOverlayScrollbarHiding) {
+ arrangeContent.w = arrangeContent.h = _strEmpty;
+ arrangeChanged = true;
+ }
+ if (arrangeChanged && !_nativeScrollbarStyling) {
+ contentArrangeElementCSS[_strWidth] = hideOverflow.y ? arrangeContent.w : _strEmpty;
+ contentArrangeElementCSS[_strHeight] = hideOverflow.x ? arrangeContent.h : _strEmpty;
+
+ if (!_contentArrangeElement) {
+ _contentArrangeElement = FRAMEWORK(generateDiv(_classNameContentArrangeElement));
+ _viewportElement.prepend(_contentArrangeElement);
+ }
+ _contentArrangeElement.css(contentArrangeElementCSS);
+ }
+ _contentElement.css(contentElementCSS);
+ }
+
+ var viewportElementCSS = {};
+ var paddingElementCSS = {};
+ var setViewportCSS;
+ if (hostSizeChanged || hasOverflow.c || hideOverflow.c || contentScrollSize.c || overflowBehaviorChanged || boxSizingChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged || clipAlwaysChanged || heightAutoChanged) {
+ viewportElementCSS[isRTLRight] = _strEmpty;
+ setViewportCSS = function (horizontal) {
+ var scrollbarVars = getScrollbarVars(horizontal);
+ var scrollbarVarsInverted = getScrollbarVars(!horizontal);
+ var xy = scrollbarVars._x_y;
+ var XY = scrollbarVars._X_Y;
+ var strDirection = horizontal ? _strBottom : isRTLLeft;
+
+ var reset = function () {
+ viewportElementCSS[strDirection] = _strEmpty;
+ _contentBorderSize[scrollbarVarsInverted._w_h] = 0;
+ };
+ if (hasOverflow[xy] && hideOverflow[xy + 's']) {
+ viewportElementCSS[strOverflow + XY] = _strScroll;
+ if (ignoreOverlayScrollbarHiding || _nativeScrollbarStyling) {
+ reset();
+ }
+ else {
+ viewportElementCSS[strDirection] = -(_nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[xy] : _nativeScrollbarSize[xy]);
+ _contentBorderSize[scrollbarVarsInverted._w_h] = _nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[scrollbarVarsInverted._x_y] : 0;
+ }
+ } else {
+ viewportElementCSS[strOverflow + XY] = _strEmpty;
+ reset();
+ }
+ };
+ setViewportCSS(true);
+ setViewportCSS(false);
+
+ // if the scroll container is too small and if there is any overflow with no overlay scrollbar (and scrollbar styling isn't possible),
+ // make viewport element greater in size (Firefox hide Scrollbars fix)
+ // because firefox starts hiding scrollbars on too small elements
+ // with this behavior the overflow calculation may be incorrect or the scrollbars would appear suddenly
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=292284
+ if (!_nativeScrollbarStyling
+ && (_viewportSize.h < _nativeScrollbarMinSize.x || _viewportSize.w < _nativeScrollbarMinSize.y)
+ && ((hasOverflow.x && hideOverflow.x && !_nativeScrollbarIsOverlaid.x) || (hasOverflow.y && hideOverflow.y && !_nativeScrollbarIsOverlaid.y))) {
+ viewportElementCSS[_strPaddingMinus + _strTop] = _nativeScrollbarMinSize.x;
+ viewportElementCSS[_strMarginMinus + _strTop] = -_nativeScrollbarMinSize.x;
+
+ viewportElementCSS[_strPaddingMinus + isRTLRight] = _nativeScrollbarMinSize.y;
+ viewportElementCSS[_strMarginMinus + isRTLRight] = -_nativeScrollbarMinSize.y;
+ }
+ else {
+ viewportElementCSS[_strPaddingMinus + _strTop] =
+ viewportElementCSS[_strMarginMinus + _strTop] =
+ viewportElementCSS[_strPaddingMinus + isRTLRight] =
+ viewportElementCSS[_strMarginMinus + isRTLRight] = _strEmpty;
+ }
+ viewportElementCSS[_strPaddingMinus + isRTLLeft] =
+ viewportElementCSS[_strMarginMinus + isRTLLeft] = _strEmpty;
+
+ //if there is any overflow (x OR y axis) and this overflow shall be hidden, make overflow hidden, else overflow visible
+ if ((hasOverflow.x && hideOverflow.x) || (hasOverflow.y && hideOverflow.y) || hideOverflowForceTextarea) {
+ //only hide if is Textarea
+ if (_isTextarea && hideOverflowForceTextarea) {
+ paddingElementCSS[strOverflowX] =
+ paddingElementCSS[strOverflowY] = strHidden;
+ }
+ }
+ else {
+ if (!clipAlways || (overflowBehaviorIsVH.x || overflowBehaviorIsVS.x || overflowBehaviorIsVH.y || overflowBehaviorIsVS.y)) {
+ //only un-hide if Textarea
+ if (_isTextarea) {
+ paddingElementCSS[strOverflowX] =
+ paddingElementCSS[strOverflowY] = _strEmpty;
+ }
+ viewportElementCSS[strOverflowX] =
+ viewportElementCSS[strOverflowY] = strVisible;
+ }
+ }
+
+ _paddingElement.css(paddingElementCSS);
+ _viewportElement.css(viewportElementCSS);
+ viewportElementCSS = {};
+
+ //force soft redraw in webkit because without the scrollbars will may appear because DOM wont be redrawn under special conditions
+ if ((hasOverflow.c || boxSizingChanged || widthAutoChanged || heightAutoChanged) && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
+ var elementStyle = _contentElementNative[LEXICON.s];
+ var dump;
+ elementStyle.webkitTransform = 'scale(1)';
+ elementStyle.display = 'run-in';
+ dump = _contentElementNative[LEXICON.oH];
+ elementStyle.display = _strEmpty; //|| dump; //use dump to prevent it from deletion if minify
+ elementStyle.webkitTransform = _strEmpty;
+ }
+ /*
+ //force hard redraw in webkit if native overlaid scrollbars shall appear
+ if (ignoreOverlayScrollbarHidingChanged && ignoreOverlayScrollbarHiding) {
+ _hostElement.hide();
+ var dump = _hostElementNative[LEXICON.oH];
+ _hostElement.show();
+ }
+ */
+ }
+
+ //change to direction RTL and width auto Bugfix in Webkit
+ //without this fix, the DOM still thinks the scrollbar is LTR and thus the content is shifted to the left
+ contentElementCSS = {};
+ if (cssDirectionChanged || widthAutoChanged || heightAutoChanged) {
+ if (_isRTL && widthAuto) {
+ var floatTmp = _contentElement.css(_strFloat);
+ var posLeftWithoutFloat = MATH.round(_contentElement.css(_strFloat, _strEmpty).css(_strLeft, _strEmpty).position().left);
+ _contentElement.css(_strFloat, floatTmp);
+ var posLeftWithFloat = MATH.round(_contentElement.position().left);
+
+ if (posLeftWithoutFloat !== posLeftWithFloat)
+ contentElementCSS[_strLeft] = posLeftWithoutFloat;
+ }
+ else {
+ contentElementCSS[_strLeft] = _strEmpty;
+ }
+ }
+ _contentElement.css(contentElementCSS);
+
+ //handle scroll position
+ if (_isTextarea && contentSizeChanged) {
+ var textareaInfo = getTextareaInfo();
+ if (textareaInfo) {
+ var textareaRowsChanged = _textareaInfoCache === undefined ? true : textareaInfo._rows !== _textareaInfoCache._rows;
+ var cursorRow = textareaInfo._cursorRow;
+ var cursorCol = textareaInfo._cursorColumn;
+ var widestRow = textareaInfo._widestRow;
+ var lastRow = textareaInfo._rows;
+ var lastCol = textareaInfo._columns;
+ var cursorPos = textareaInfo._cursorPosition;
+ var cursorMax = textareaInfo._cursorMax;
+ var cursorIsLastPosition = (cursorPos >= cursorMax && _textareaHasFocus);
+ var textareaScrollAmount = {
+ x: (!textareaAutoWrapping && (cursorCol === lastCol && cursorRow === widestRow)) ? _overflowAmountCache.x : -1,
+ y: (textareaAutoWrapping ? cursorIsLastPosition || textareaRowsChanged && (previousOverflowAmount ? (currScroll.y === previousOverflowAmount.y) : false) : (cursorIsLastPosition || textareaRowsChanged) && cursorRow === lastRow) ? _overflowAmountCache.y : -1
+ };
+ currScroll.x = textareaScrollAmount.x > -1 ? (_isRTL && _normalizeRTLCache && _rtlScrollBehavior.i ? 0 : textareaScrollAmount.x) : currScroll.x; //if inverted, scroll to 0 -> normalized this means to max scroll offset.
+ currScroll.y = textareaScrollAmount.y > -1 ? textareaScrollAmount.y : currScroll.y;
+ }
+ _textareaInfoCache = textareaInfo;
+ }
+ if (_isRTL && _rtlScrollBehavior.i && _nativeScrollbarIsOverlaid.y && hasOverflow.x && _normalizeRTLCache)
+ currScroll.x += _contentBorderSize.w || 0;
+ if (widthAuto)
+ _hostElement[_strScrollLeft](0);
+ if (heightAuto)
+ _hostElement[_strScrollTop](0);
+ _viewportElement[_strScrollLeft](currScroll.x)[_strScrollTop](currScroll.y);
+
+ //scrollbars management:
+ var scrollbarsVisibilityVisible = scrollbarsVisibility === 'v';
+ var scrollbarsVisibilityHidden = scrollbarsVisibility === 'h';
+ var scrollbarsVisibilityAuto = scrollbarsVisibility === 'a';
+
+ var showScrollbarH = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, true, true, canScroll.x);
+ var showScrollbarV = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, false, true, canScroll.y);
+ var hideScrollbarH = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, true, false, canScroll.x);
+ var hideScrollbarV = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, false, false, canScroll.y);
+
+ //manage class name which indicates scrollable overflow
+ if (hideOverflow.x || hideOverflow.y)
+ addClass(_hostElement, _classNameHostOverflow);
+ else
+ removeClass(_hostElement, _classNameHostOverflow);
+ if (hideOverflow.x)
+ addClass(_hostElement, _classNameHostOverflowX);
+ else
+ removeClass(_hostElement, _classNameHostOverflowX);
+ if (hideOverflow.y)
+ addClass(_hostElement, _classNameHostOverflowY);
+ else
+ removeClass(_hostElement, _classNameHostOverflowY);
+
+ //add or remove rtl class name for styling purposes
+ if (cssDirectionChanged) {
+ if (_isRTL)
+ addClass(_hostElement, _classNameHostRTL);
+ else
+ removeClass(_hostElement, _classNameHostRTL);
+ }
+
+ //manage the resize feature (CSS3 resize "polyfill" for this plugin)
+ if (_isBody)
+ addClass(_hostElement, _classNameHostResizeDisabled);
+ if (resizeChanged) {
+ removeClass(_scrollbarCornerElement, [
+ _classNameScrollbarCornerResize,
+ _classNameScrollbarCornerResizeB,
+ _classNameScrollbarCornerResizeH,
+ _classNameScrollbarCornerResizeV].join(_strSpace));
+ if (_resizeNone) {
+ addClass(_hostElement, _classNameHostResizeDisabled);
+ }
+ else {
+ removeClass(_hostElement, _classNameHostResizeDisabled);
+ addClass(_scrollbarCornerElement, _classNameScrollbarCornerResize);
+ if (_resizeBoth)
+ addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeB);
+ else if (_resizeHorizontal)
+ addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeH);
+ else if (_resizeVertical)
+ addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV);
+ }
+ }
+
+ //manage the scrollbars general visibility + the scrollbar interactivity (unusable class name)
+ if (scrollbarsVisibilityChanged || overflowBehaviorChanged || hideOverflow.c || hasOverflow.c || ignoreOverlayScrollbarHidingChanged) {
+ if (ignoreOverlayScrollbarHiding) {
+ if (ignoreOverlayScrollbarHidingChanged) {
+ removeClass(_hostElement, _classNameHostScrolling);
+ if (ignoreOverlayScrollbarHiding) {
+ hideScrollbarH();
+ hideScrollbarV();
+ }
+ }
+ }
+ else if (scrollbarsVisibilityAuto) {
+ if (canScroll.x)
+ showScrollbarH();
+ else
+ hideScrollbarH();
+
+ if (canScroll.y)
+ showScrollbarV();
+ else
+ hideScrollbarV();
+ }
+ else if (scrollbarsVisibilityVisible) {
+ showScrollbarH();
+ showScrollbarV();
+ }
+ else if (scrollbarsVisibilityHidden) {
+ hideScrollbarH();
+ hideScrollbarV();
+ }
+ }
+
+ //manage the scrollbars auto hide feature (auto hide them after specific actions)
+ if (scrollbarsAutoHideChanged || ignoreOverlayScrollbarHidingChanged) {
+ if (_scrollbarsAutoHideLeave || _scrollbarsAutoHideMove) {
+ setupHostMouseTouchEvents(true);
+ setupHostMouseTouchEvents();
+ }
+ else {
+ setupHostMouseTouchEvents(true);
+ }
+
+ if (_scrollbarsAutoHideNever)
+ refreshScrollbarsAutoHide(true);
+ else
+ refreshScrollbarsAutoHide(false, true);
+ }
+
+ //manage scrollbars handle length & offset - don't remove!
+ if (hostSizeChanged || overflowAmount.c || heightAutoChanged || widthAutoChanged || resizeChanged || boxSizingChanged || paddingAbsoluteChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged) {
+ refreshScrollbarHandleLength(true);
+ refreshScrollbarHandleOffset(true);
+ refreshScrollbarHandleLength(false);
+ refreshScrollbarHandleOffset(false);
+ }
+
+ //manage interactivity
+ if (scrollbarsClickScrollingChanged)
+ refreshScrollbarsInteractive(true, scrollbarsClickScrolling);
+ if (scrollbarsDragScrollingChanged)
+ refreshScrollbarsInteractive(false, scrollbarsDragScrolling);
+
+ //callbacks:
+ if (cssDirectionChanged) {
+ dispatchCallback('onDirectionChanged', {
+ isRTL: _isRTL,
+ dir: cssDirection
+ });
+ }
+ if (hostSizeChanged) {
+ dispatchCallback('onHostSizeChanged', {
+ width: _hostSizeCache.w,
+ height: _hostSizeCache.h
+ });
+ }
+ if (contentSizeChanged) {
+ dispatchCallback('onContentSizeChanged', {
+ width: _contentScrollSizeCache.w,
+ height: _contentScrollSizeCache.h
+ });
+ }
+ if (hasOverflow.c || hideOverflow.c) {
+ dispatchCallback('onOverflowChanged', {
+ x: hasOverflow.x,
+ y: hasOverflow.y,
+ xScrollable: hideOverflow.xs,
+ yScrollable: hideOverflow.ys,
+ clipped: hideOverflow.x || hideOverflow.y
+ });
+ }
+ if (overflowAmount.c) {
+ dispatchCallback('onOverflowAmountChanged', {
+ x: overflowAmount.x,
+ y: overflowAmount.y
+ });
+ }
+ }
+
+ //fix body min size
+ if (_isBody && _bodyMinSizeCache && (_hasOverflowCache.c || _bodyMinSizeCache.c)) {
+ //its possible that no min size was measured until now, because the content arrange element was just added now, in this case, measure now the min size.
+ if (!_bodyMinSizeCache.f)
+ bodyMinSizeChanged();
+ if (_nativeScrollbarIsOverlaid.y && _hasOverflowCache.x)
+ _contentElement.css(_strMinMinus + _strWidth, _bodyMinSizeCache.w + _overlayScrollbarDummySize.y);
+ if (_nativeScrollbarIsOverlaid.x && _hasOverflowCache.y)
+ _contentElement.css(_strMinMinus + _strHeight, _bodyMinSizeCache.h + _overlayScrollbarDummySize.x);
+ _bodyMinSizeCache.c = false;
+ }
+
+ //freezeResizeObserver(_sizeObserverElement, false);
+ //freezeResizeObserver(_sizeAutoObserverElement, false);
+
+ dispatchCallback('onUpdated', { forced: force });
+ }
+
+
+ //==== Options ====//
+
+ /**
+ * Sets new options but doesn't call the update method.
+ * @param newOptions The object which contains the new options.
+ * @returns {*} A object which contains the changed options.
+ */
+ function setOptions(newOptions) {
+ var validatedOpts = _pluginsOptions._validate(newOptions, _pluginsOptions._template, true, _currentOptions)
+
+ _currentOptions = extendDeep({}, _currentOptions, validatedOpts._default);
+ _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, validatedOpts._prepared);
+
+ return validatedOpts._prepared;
+ }
+
+
+ //==== Structure ====//
+
+ /**
+ * Builds or destroys the wrapper and helper DOM elements.
+ * @param destroy Indicates whether the DOM shall be build or destroyed.
+ */
+ function setupStructureDOM(destroy) {
+ var strParent = 'parent';
+ var classNameResizeObserverHost = 'os-resize-observer-host';
+ var classNameTextareaElementFull = _classNameTextareaElement + _strSpace + _classNameTextInherit;
+ var textareaClass = _isTextarea ? _strSpace + _classNameTextInherit : _strEmpty;
+ var adoptAttrs = _currentPreparedOptions.textarea.inheritedAttrs;
+ var adoptAttrsMap = {};
+ var applyAdoptedAttrs = function () {
+ var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement;
+ each(adoptAttrsMap, function (key, value) {
+ if (type(value) == TYPES.s) {
+ if (key == LEXICON.c)
+ applyAdoptedAttrsElm.addClass(value);
+ else
+ applyAdoptedAttrsElm.attr(key, value);
+ }
+ });
+ };
+ var hostElementClassNames = [
+ _classNameHostElement,
+ _classNameHostTextareaElement,
+ _classNameHostResizeDisabled,
+ _classNameHostRTL,
+ _classNameHostScrollbarHorizontalHidden,
+ _classNameHostScrollbarVerticalHidden,
+ _classNameHostTransition,
+ _classNameHostScrolling,
+ _classNameHostOverflow,
+ _classNameHostOverflowX,
+ _classNameHostOverflowY,
+ _classNameThemeNone,
+ _classNameTextareaElement,
+ _classNameTextInherit,
+ _classNameCache].join(_strSpace);
+ var hostElementCSS = {};
+
+ //get host element as first element, because that's the most upper element and required for the other elements
+ _hostElement = _hostElement || (_isTextarea ? (_domExists ? _targetElement[strParent]()[strParent]()[strParent]()[strParent]() : FRAMEWORK(generateDiv(_classNameHostTextareaElement))) : _targetElement);
+ _contentElement = _contentElement || selectOrGenerateDivByClass(_classNameContentElement + textareaClass);
+ _viewportElement = _viewportElement || selectOrGenerateDivByClass(_classNameViewportElement + textareaClass);
+ _paddingElement = _paddingElement || selectOrGenerateDivByClass(_classNamePaddingElement + textareaClass);
+ _sizeObserverElement = _sizeObserverElement || selectOrGenerateDivByClass(classNameResizeObserverHost);
+ _textareaCoverElement = _textareaCoverElement || (_isTextarea ? selectOrGenerateDivByClass(_classNameTextareaCoverElement) : undefined);
+
+ //on destroy, remove all generated class names from the host element before collecting the adopted attributes
+ //to prevent adopting generated class names
+ if (destroy)
+ removeClass(_hostElement, hostElementClassNames);
+
+ //collect all adopted attributes
+ adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(_strSpace) : adoptAttrs;
+ if (type(adoptAttrs) == TYPES.a && _isTextarea) {
+ each(adoptAttrs, function (i, v) {
+ if (type(v) == TYPES.s) {
+ adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v);
+ }
+ });
+ }
+
+ if (!destroy) {
+ if (_isTextarea) {
+ if (!_currentPreparedOptions.sizeAutoCapable) {
+ hostElementCSS[_strWidth] = _targetElement.css(_strWidth);
+ hostElementCSS[_strHeight] = _targetElement.css(_strHeight);
+ }
+
+ if (!_domExists)
+ _targetElement.addClass(_classNameTextInherit).wrap(_hostElement);
+
+ //jQuery clones elements in wrap functions, so we have to select them again
+ _hostElement = _targetElement[strParent]().css(hostElementCSS);
+ }
+
+ if (!_domExists) {
+ //add the correct class to the target element
+ addClass(_targetElement, _isTextarea ? classNameTextareaElementFull : _classNameHostElement);
+
+ //wrap the content into the generated elements to create the required DOM
+ _hostElement.wrapInner(_contentElement)
+ .wrapInner(_viewportElement)
+ .wrapInner(_paddingElement)
+ .prepend(_sizeObserverElement);
+
+ //jQuery clones elements in wrap functions, so we have to select them again
+ _contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);
+ _viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);
+ _paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);
+
+ if (_isTextarea) {
+ _contentElement.prepend(_textareaCoverElement);
+ applyAdoptedAttrs();
+ }
+ }
+
+ if (_nativeScrollbarStyling)
+ addClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
+ if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)
+ addClass(_viewportElement, _classNameViewportNativeScrollbarsOverlaid);
+ if (_isBody)
+ addClass(_htmlElement, _classNameHTMLElement);
+
+ _sizeObserverElementNative = _sizeObserverElement[0];
+ _hostElementNative = _hostElement[0];
+ _paddingElementNative = _paddingElement[0];
+ _viewportElementNative = _viewportElement[0];
+ _contentElementNative = _contentElement[0];
+
+ updateViewportAttrsFromTarget();
+ }
+ else {
+ if (_domExists && _initialized) {
+ //clear size observer
+ _sizeObserverElement.children().remove();
+
+ //remove the style property and classes from already generated elements
+ each([_paddingElement, _viewportElement, _contentElement, _textareaCoverElement], function (i, elm) {
+ if (elm) {
+ removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
+ }
+ });
+
+ //add classes to the host element which was removed previously to match the expected DOM
+ addClass(_hostElement, _isTextarea ? _classNameHostTextareaElement : _classNameHostElement);
+ }
+ else {
+ //remove size observer
+ remove(_sizeObserverElement);
+
+ //unwrap the content to restore DOM
+ _contentElement.contents()
+ .unwrap()
+ .unwrap()
+ .unwrap();
+
+ if (_isTextarea) {
+ _targetElement.unwrap();
+ remove(_hostElement);
+ remove(_textareaCoverElement);
+ applyAdoptedAttrs();
+ }
+ }
+
+ if (_isTextarea)
+ _targetElement.removeAttr(LEXICON.s);
+
+ if (_isBody)
+ removeClass(_htmlElement, _classNameHTMLElement);
+ }
+ }
+
+ /**
+ * Adds or removes all wrapper elements interactivity events.
+ * @param destroy Indicates whether the Events shall be added or removed.
+ */
+ function setupStructureEvents() {
+ var textareaKeyDownRestrictedKeyCodes = [
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, //F1 to F12
+ 33, 34, //page up, page down
+ 37, 38, 39, 40, //left, up, right, down arrows
+ 16, 17, 18, 19, 20, 144 //Shift, Ctrl, Alt, Pause, CapsLock, NumLock
+ ];
+ var textareaKeyDownKeyCodesList = [];
+ var textareaUpdateIntervalID;
+ var scrollStopTimeoutId;
+ var scrollStopDelay = 175;
+ var strFocus = 'focus';
+
+ function updateTextarea(doClearInterval) {
+ textareaUpdate();
+ _base.update(_strAuto);
+ if (doClearInterval && _autoUpdateRecommended)
+ clearInterval(textareaUpdateIntervalID);
+ }
+ function textareaOnScroll(event) {
+ _targetElement[_strScrollLeft](_rtlScrollBehavior.i && _normalizeRTLCache ? 9999999 : 0);
+ _targetElement[_strScrollTop](0);
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ return false;
+ }
+ function textareaOnDrop(event) {
+ setTimeout(function () {
+ if (!_destroyed)
+ updateTextarea();
+ }, 50);
+ }
+ function textareaOnFocus() {
+ _textareaHasFocus = true;
+ addClass(_hostElement, strFocus);
+ }
+ function textareaOnFocusout() {
+ _textareaHasFocus = false;
+ textareaKeyDownKeyCodesList = [];
+ removeClass(_hostElement, strFocus);
+ updateTextarea(true);
+ }
+ function textareaOnKeyDown(event) {
+ var keyCode = event.keyCode;
+
+ if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {
+ if (!textareaKeyDownKeyCodesList[LEXICON.l]) {
+ updateTextarea();
+ textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60);
+ }
+ if (inArray(keyCode, textareaKeyDownKeyCodesList) < 0)
+ textareaKeyDownKeyCodesList.push(keyCode);
+ }
+ }
+ function textareaOnKeyUp(event) {
+ var keyCode = event.keyCode;
+ var index = inArray(keyCode, textareaKeyDownKeyCodesList);
+
+ if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {
+ if (index > -1)
+ textareaKeyDownKeyCodesList.splice(index, 1);
+ if (!textareaKeyDownKeyCodesList[LEXICON.l])
+ updateTextarea(true);
+ }
+ }
+ function contentOnTransitionEnd(event) {
+ if (_autoUpdateCache === true)
+ return;
+ event = event.originalEvent || event;
+ if (isSizeAffectingCSSProperty(event.propertyName))
+ _base.update(_strAuto);
+ }
+ function viewportOnScroll(event) {
+ if (!_sleeping) {
+ if (scrollStopTimeoutId !== undefined)
+ clearTimeout(scrollStopTimeoutId);
+ else {
+ if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
+ refreshScrollbarsAutoHide(true);
+
+ if (!nativeOverlayScrollbarsAreActive())
+ addClass(_hostElement, _classNameHostScrolling);
+
+ dispatchCallback('onScrollStart', event);
+ }
+
+ //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset
+ //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point
+ //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove
+ if (!_scrollbarsHandlesDefineScrollPos) {
+ refreshScrollbarHandleOffset(true);
+ refreshScrollbarHandleOffset(false);
+ }
+ dispatchCallback('onScroll', event);
+
+ scrollStopTimeoutId = setTimeout(function () {
+ if (!_destroyed) {
+ //OnScrollStop:
+ clearTimeout(scrollStopTimeoutId);
+ scrollStopTimeoutId = undefined;
+
+ if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
+ refreshScrollbarsAutoHide(false);
+
+ if (!nativeOverlayScrollbarsAreActive())
+ removeClass(_hostElement, _classNameHostScrolling);
+
+ dispatchCallback('onScrollStop', event);
+ }
+ }, scrollStopDelay);
+ }
+ }
+
+
+ if (_isTextarea) {
+ if (_msieVersion > 9 || !_autoUpdateRecommended) {
+ addDestroyEventListener(_targetElement, 'input', updateTextarea);
+ }
+ else {
+ addDestroyEventListener(_targetElement,
+ [_strKeyDownEvent, _strKeyUpEvent],
+ [textareaOnKeyDown, textareaOnKeyUp]);
+ }
+
+ addDestroyEventListener(_targetElement,
+ [_strScroll, 'drop', strFocus, strFocus + 'out'],
+ [textareaOnScroll, textareaOnDrop, textareaOnFocus, textareaOnFocusout]);
+ }
+ else {
+ addDestroyEventListener(_contentElement, _strTransitionEndEvent, contentOnTransitionEnd);
+ }
+ addDestroyEventListener(_viewportElement, _strScroll, viewportOnScroll, true);
+ }
+
+
+ //==== Scrollbars ====//
+
+ /**
+ * Builds or destroys all scrollbar DOM elements (scrollbar, track, handle)
+ * @param destroy Indicates whether the DOM shall be build or destroyed.
+ */
+ function setupScrollbarsDOM(destroy) {
+ var selectOrGenerateScrollbarDOM = function (isHorizontal) {
+ var scrollbarClassName = isHorizontal ? _classNameScrollbarHorizontal : _classNameScrollbarVertical;
+ var scrollbar = selectOrGenerateDivByClass(_classNameScrollbar + _strSpace + scrollbarClassName, true);
+ var track = selectOrGenerateDivByClass(_classNameScrollbarTrack, scrollbar);
+ var handle = selectOrGenerateDivByClass(_classNameScrollbarHandle, scrollbar);
+
+ if (!_domExists && !destroy) {
+ scrollbar.append(track);
+ track.append(handle);
+ }
+
+ return {
+ _scrollbar: scrollbar,
+ _track: track,
+ _handle: handle
+ };
+ };
+ function resetScrollbarDOM(isHorizontal) {
+ var scrollbarVars = getScrollbarVars(isHorizontal);
+ var scrollbar = scrollbarVars._scrollbar;
+ var track = scrollbarVars._track;
+ var handle = scrollbarVars._handle;
+
+ if (_domExists && _initialized) {
+ each([scrollbar, track, handle], function (i, elm) {
+ removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
+ });
+ }
+ else {
+ remove(scrollbar || selectOrGenerateScrollbarDOM(isHorizontal)._scrollbar);
+ }
+ }
+ var horizontalElements;
+ var verticalElements;
+
+ if (!destroy) {
+ horizontalElements = selectOrGenerateScrollbarDOM(true);
+ verticalElements = selectOrGenerateScrollbarDOM();
+
+ _scrollbarHorizontalElement = horizontalElements._scrollbar;
+ _scrollbarHorizontalTrackElement = horizontalElements._track;
+ _scrollbarHorizontalHandleElement = horizontalElements._handle;
+ _scrollbarVerticalElement = verticalElements._scrollbar;
+ _scrollbarVerticalTrackElement = verticalElements._track;
+ _scrollbarVerticalHandleElement = verticalElements._handle;
+
+ if (!_domExists) {
+ _paddingElement.after(_scrollbarVerticalElement);
+ _paddingElement.after(_scrollbarHorizontalElement);
+ }
+ }
+ else {
+ resetScrollbarDOM(true);
+ resetScrollbarDOM();
+ }
+ }
+
+ /**
+ * Initializes all scrollbar interactivity events. (track and handle dragging, clicking, scrolling)
+ * @param isHorizontal True if the target scrollbar is the horizontal scrollbar, false if the target scrollbar is the vertical scrollbar.
+ */
+ function setupScrollbarEvents(isHorizontal) {
+ var scrollbarVars = getScrollbarVars(isHorizontal);
+ var scrollbarVarsInfo = scrollbarVars._info;
+ var insideIFrame = _windowElementNative.top !== _windowElementNative;
+ var xy = scrollbarVars._x_y;
+ var XY = scrollbarVars._X_Y;
+ var scroll = _strScroll + scrollbarVars._Left_Top;
+ var strActive = 'active';
+ var strSnapHandle = 'snapHandle';
+ var scrollDurationFactor = 1;
+ var increaseDecreaseScrollAmountKeyCodes = [16, 17]; //shift, ctrl
+ var trackTimeout;
+ var mouseDownScroll;
+ var mouseDownOffset;
+ var mouseDownInvertedScale;
+
+ function getPointerPosition(event) {
+ return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames.
+ }
+ function getPreparedScrollbarsOption(name) {
+ return _currentPreparedOptions.scrollbars[name];
+ }
+ function increaseTrackScrollAmount() {
+ scrollDurationFactor = 0.5;
+ }
+ function decreaseTrackScrollAmount() {
+ scrollDurationFactor = 1;
+ }
+ function documentKeyDown(event) {
+ if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
+ increaseTrackScrollAmount();
+ }
+ function documentKeyUp(event) {
+ if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
+ decreaseTrackScrollAmount();
+ }
+ function onMouseTouchDownContinue(event) {
+ var originalEvent = event.originalEvent || event;
+ var isTouchEvent = originalEvent.touches !== undefined;
+ return _sleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
+ }
+ function documentDragMove(event) {
+ if (onMouseTouchDownContinue(event)) {
+ var trackLength = scrollbarVarsInfo._trackLength;
+ var handleLength = scrollbarVarsInfo._handleLength;
+ var scrollRange = scrollbarVarsInfo._maxScroll;
+ var scrollRaw = (getPointerPosition(event) - mouseDownOffset) * mouseDownInvertedScale;
+ var scrollDeltaPercent = scrollRaw / (trackLength - handleLength);
+ var scrollDelta = (scrollRange * scrollDeltaPercent);
+ scrollDelta = isFinite(scrollDelta) ? scrollDelta : 0;
+ if (_isRTL && isHorizontal && !_rtlScrollBehavior.i)
+ scrollDelta *= -1;
+
+ _viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta));
+
+ if (_scrollbarsHandlesDefineScrollPos)
+ refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta);
+
+ if (!_supportPassiveEvents)
+ COMPATIBILITY.prvD(event);
+ }
+ else
+ documentMouseTouchUp(event);
+ }
+ function documentMouseTouchUp(event) {
+ event = event || event.originalEvent;
+
+ setupResponsiveEventListener(_documentElement,
+ [_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],
+ [documentDragMove, documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart],
+ true);
+
+ if (_scrollbarsHandlesDefineScrollPos)
+ refreshScrollbarHandleOffset(isHorizontal, true);
+
+ _scrollbarsHandlesDefineScrollPos = false;
+ removeClass(_bodyElement, _classNameDragging);
+ removeClass(scrollbarVars._handle, strActive);
+ removeClass(scrollbarVars._track, strActive);
+ removeClass(scrollbarVars._scrollbar, strActive);
+
+ mouseDownScroll = undefined;
+ mouseDownOffset = undefined;
+ mouseDownInvertedScale = 1;
+
+ decreaseTrackScrollAmount();
+
+ if (trackTimeout !== undefined) {
+ _base.scrollStop();
+ clearTimeout(trackTimeout);
+ trackTimeout = undefined;
+ }
+
+ if (event) {
+ var rect = _hostElementNative[LEXICON.bCR]();
+ var mouseInsideHost = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
+
+ //if mouse is outside host element
+ if (!mouseInsideHost)
+ hostOnMouseLeave();
+
+ if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
+ refreshScrollbarsAutoHide(false);
+ }
+ }
+ function onHandleMouseTouchDown(event) {
+ if (onMouseTouchDownContinue(event))
+ onHandleMouseTouchDownAction(event);
+ }
+ function onHandleMouseTouchDownAction(event) {
+ mouseDownScroll = _viewportElement[scroll]();
+ mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll;
+ if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL)
+ mouseDownScroll = mouseDownScroll < 0 ? 0 : mouseDownScroll;
+
+ mouseDownInvertedScale = getHostElementInvertedScale()[xy];
+ mouseDownOffset = getPointerPosition(event);
+
+ _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);
+ addClass(_bodyElement, _classNameDragging);
+ addClass(scrollbarVars._handle, strActive);
+ addClass(scrollbarVars._scrollbar, strActive);
+
+ setupResponsiveEventListener(_documentElement,
+ [_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strSelectStartEvent],
+ [documentDragMove, documentMouseTouchUp, documentOnSelectStart]);
+
+ if (_msieVersion || !_documentMixed)
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ }
+ function onTrackMouseTouchDown(event) {
+ if (onMouseTouchDownContinue(event)) {
+ var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h]);
+ var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top];
+ var ctrlKey = event.ctrlKey;
+ var instantScroll = event.shiftKey;
+ var instantScrollTransition = instantScroll && ctrlKey;
+ var isFirstIteration = true;
+ var easing = 'linear';
+ var decreaseScroll;
+ var finishedCondition;
+ var scrollActionFinsished = function (transition) {
+ if (_scrollbarsHandlesDefineScrollPos)
+ refreshScrollbarHandleOffset(isHorizontal, transition);
+ };
+ var scrollActionInstantFinished = function () {
+ scrollActionFinsished();
+ onHandleMouseTouchDownAction(event);
+ };
+ var scrollAction = function () {
+ if (!_destroyed) {
+ var mouseOffset = (mouseDownOffset - trackOffset) * mouseDownInvertedScale;
+ var handleOffset = scrollbarVarsInfo._handleOffset;
+ var trackLength = scrollbarVarsInfo._trackLength;
+ var handleLength = scrollbarVarsInfo._handleLength;
+ var scrollRange = scrollbarVarsInfo._maxScroll;
+ var currScroll = scrollbarVarsInfo._currentScroll;
+ var scrollDuration = 270 * scrollDurationFactor;
+ var timeoutDelay = isFirstIteration ? MATH.max(400, scrollDuration) : scrollDuration;
+ var instantScrollPosition = scrollRange * ((mouseOffset - (handleLength / 2)) / (trackLength - handleLength)); // 100% * positionPercent
+ var rtlIsNormal = _isRTL && isHorizontal && ((!_rtlScrollBehavior.i && !_rtlScrollBehavior.n) || _normalizeRTLCache);
+ var decreaseScrollCondition = rtlIsNormal ? handleOffset < mouseOffset : handleOffset > mouseOffset;
+ var scrollObj = {};
+ var animationObj = {
+ easing: easing,
+ step: function (now) {
+ if (_scrollbarsHandlesDefineScrollPos) {
+ _viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/4340
+ refreshScrollbarHandleOffset(isHorizontal, now);
+ }
+ }
+ };
+ instantScrollPosition = isFinite(instantScrollPosition) ? instantScrollPosition : 0;
+ instantScrollPosition = _isRTL && isHorizontal && !_rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
+
+ //_base.scrollStop();
+
+ if (instantScroll) {
+ _viewportElement[scroll](instantScrollPosition); //scroll instantly to new position
+ if (instantScrollTransition) {
+ //get the scroll position after instant scroll (in case CSS Snap Points are used) to get the correct snapped scroll position
+ //and the animation stops at the correct point
+ instantScrollPosition = _viewportElement[scroll]();
+ //scroll back to the position before instant scrolling so animation can be performed
+ _viewportElement[scroll](currScroll);
+
+ instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
+ instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.n ? -instantScrollPosition : instantScrollPosition;
+
+ scrollObj[xy] = instantScrollPosition;
+ _base.scroll(scrollObj, extendDeep(animationObj, {
+ duration: 130,
+ complete: scrollActionInstantFinished
+ }));
+ }
+ else
+ scrollActionInstantFinished();
+ }
+ else {
+ decreaseScroll = isFirstIteration ? decreaseScrollCondition : decreaseScroll;
+ finishedCondition = rtlIsNormal
+ ? (decreaseScroll ? handleOffset + handleLength >= mouseOffset : handleOffset <= mouseOffset)
+ : (decreaseScroll ? handleOffset <= mouseOffset : handleOffset + handleLength >= mouseOffset);
+
+ if (finishedCondition) {
+ clearTimeout(trackTimeout);
+ _base.scrollStop();
+ trackTimeout = undefined;
+ scrollActionFinsished(true);
+ }
+ else {
+ trackTimeout = setTimeout(scrollAction, timeoutDelay);
+
+ scrollObj[xy] = (decreaseScroll ? '-=' : '+=') + scrollDistance;
+ _base.scroll(scrollObj, extendDeep(animationObj, {
+ duration: scrollDuration
+ }));
+ }
+ isFirstIteration = false;
+ }
+ }
+ };
+ if (ctrlKey)
+ increaseTrackScrollAmount();
+
+ mouseDownInvertedScale = getHostElementInvertedScale()[xy];
+ mouseDownOffset = COMPATIBILITY.page(event)[xy];
+
+ _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);
+ addClass(_bodyElement, _classNameDragging);
+ addClass(scrollbarVars._track, strActive);
+ addClass(scrollbarVars._scrollbar, strActive);
+
+ setupResponsiveEventListener(_documentElement,
+ [_strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],
+ [documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart]);
+
+ scrollAction();
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ }
+ }
+ function onTrackMouseTouchEnter(event) {
+ //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move".
+ _scrollbarsHandleHovered = true;
+ if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
+ refreshScrollbarsAutoHide(true);
+ }
+ function onTrackMouseTouchLeave(event) {
+ _scrollbarsHandleHovered = false;
+ if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
+ refreshScrollbarsAutoHide(false);
+ }
+ function onScrollbarMouseTouchDown(event) {
+ COMPATIBILITY.stpP(event);
+ }
+
+ addDestroyEventListener(scrollbarVars._handle,
+ _strMouseTouchDownEvent,
+ onHandleMouseTouchDown);
+ addDestroyEventListener(scrollbarVars._track,
+ [_strMouseTouchDownEvent, _strMouseTouchEnter, _strMouseTouchLeave],
+ [onTrackMouseTouchDown, onTrackMouseTouchEnter, onTrackMouseTouchLeave]);
+ addDestroyEventListener(scrollbarVars._scrollbar,
+ _strMouseTouchDownEvent,
+ onScrollbarMouseTouchDown);
+
+ if (_supportTransition) {
+ addDestroyEventListener(scrollbarVars._scrollbar, _strTransitionEndEvent, function (event) {
+ if (event.target !== scrollbarVars._scrollbar[0])
+ return;
+ refreshScrollbarHandleLength(isHorizontal);
+ refreshScrollbarHandleOffset(isHorizontal);
+ });
+ }
+ }
+
+ /**
+ * Shows or hides the given scrollbar and applied a class name which indicates if the scrollbar is scrollable or not.
+ * @param isHorizontal True if the horizontal scrollbar is the target, false if the vertical scrollbar is the target.
+ * @param shallBeVisible True if the scrollbar shall be shown, false if hidden.
+ * @param canScroll True if the scrollbar is scrollable, false otherwise.
+ */
+ function refreshScrollbarAppearance(isHorizontal, shallBeVisible, canScroll) {
+ var scrollbarClassName = isHorizontal ? _classNameHostScrollbarHorizontalHidden : _classNameHostScrollbarVerticalHidden;
+ var scrollbarElement = isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement;
+
+ if (shallBeVisible)
+ removeClass(_hostElement, scrollbarClassName);
+ else
+ addClass(_hostElement, scrollbarClassName);
+
+ if (canScroll)
+ removeClass(scrollbarElement, _classNameScrollbarUnusable);
+ else
+ addClass(scrollbarElement, _classNameScrollbarUnusable);
+ }
+
+ /**
+ * Autoshows / autohides both scrollbars with.
+ * @param shallBeVisible True if the scrollbars shall be autoshown (only the case if they are hidden by a autohide), false if the shall be auto hidden.
+ * @param delayfree True if the scrollbars shall be hidden without a delay, false or undefined otherwise.
+ */
+ function refreshScrollbarsAutoHide(shallBeVisible, delayfree) {
+ clearTimeout(_scrollbarsAutoHideTimeoutId);
+ if (shallBeVisible) {
+ //if(_hasOverflowCache.x && _hideOverflowCache.xs)
+ removeClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
+ //if(_hasOverflowCache.y && _hideOverflowCache.ys)
+ removeClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
+ }
+ else {
+ var anyActive;
+ var strActive = 'active';
+ var hide = function () {
+ if (!_scrollbarsHandleHovered && !_destroyed) {
+ anyActive = _scrollbarHorizontalHandleElement.hasClass(strActive) || _scrollbarVerticalHandleElement.hasClass(strActive);
+ if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
+ addClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
+ if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
+ addClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
+ }
+ };
+ if (_scrollbarsAutoHideDelay > 0 && delayfree !== true)
+ _scrollbarsAutoHideTimeoutId = setTimeout(hide, _scrollbarsAutoHideDelay);
+ else
+ hide();
+ }
+ }
+
+ /**
+ * Refreshes the handle length of the given scrollbar.
+ * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
+ */
+ function refreshScrollbarHandleLength(isHorizontal) {
+ var handleCSS = {};
+ var scrollbarVars = getScrollbarVars(isHorizontal);
+ var scrollbarVarsInfo = scrollbarVars._info;
+ var digit = 1000000;
+ //get and apply intended handle length
+ var handleRatio = MATH.min(1, (_hostSizeCache[scrollbarVars._w_h] - (_paddingAbsoluteCache ? (isHorizontal ? _paddingX : _paddingY) : 0)) / _contentScrollSizeCache[scrollbarVars._w_h]);
+ handleCSS[scrollbarVars._width_height] = (MATH.floor(handleRatio * 100 * digit) / digit) + '%'; //the last * digit / digit is for flooring to the 4th digit
+
+ if (!nativeOverlayScrollbarsAreActive())
+ scrollbarVars._handle.css(handleCSS);
+
+ //measure the handle length to respect min & max length
+ scrollbarVarsInfo._handleLength = scrollbarVars._handle[0]['offset' + scrollbarVars._Width_Height];
+ scrollbarVarsInfo._handleLengthRatio = handleRatio;
+ }
+
+ /**
+ * Refreshes the handle offset of the given scrollbar.
+ * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
+ * @param scrollOrTransition The scroll position of the given scrollbar axis to which the handle shall be moved or a boolean which indicates whether a transition shall be applied. If undefined or boolean if the current scroll-offset is taken. (if isHorizontal ? scrollLeft : scrollTop)
+ */
+ function refreshScrollbarHandleOffset(isHorizontal, scrollOrTransition) {
+ var transition = type(scrollOrTransition) == TYPES.b;
+ var transitionDuration = 250;
+ var isRTLisHorizontal = _isRTL && isHorizontal;
+ var scrollbarVars = getScrollbarVars(isHorizontal);
+ var scrollbarVarsInfo = scrollbarVars._info;
+ var strTranslateBrace = 'translate(';
+ var strTransform = VENDORS._cssProperty('transform');
+ var strTransition = VENDORS._cssProperty('transition');
+ var nativeScroll = isHorizontal ? _viewportElement[_strScrollLeft]() : _viewportElement[_strScrollTop]();
+ var currentScroll = scrollOrTransition === undefined || transition ? nativeScroll : scrollOrTransition;
+
+ //measure the handle length to respect min & max length
+ var handleLength = scrollbarVarsInfo._handleLength;
+ var trackLength = scrollbarVars._track[0]['offset' + scrollbarVars._Width_Height];
+ var handleTrackDiff = trackLength - handleLength;
+ var handleCSS = {};
+ var transformOffset;
+ var translateValue;
+
+ //DONT use the variable '_contentScrollSizeCache[scrollbarVars._w_h]' instead of '_viewportElement[0]['scroll' + scrollbarVars._Width_Height]'
+ // because its a bit behind during the small delay when content size updates
+ //(delay = mutationObserverContentLag, if its 0 then this var could be used)
+ var maxScroll = (_viewportElementNative[_strScroll + scrollbarVars._Width_Height] - _viewportElementNative['client' + scrollbarVars._Width_Height]) * (_rtlScrollBehavior.n && isRTLisHorizontal ? -1 : 1); //* -1 if rtl scroll max is negative
+ var getScrollRatio = function (base) {
+ return isNaN(base / maxScroll) ? 0 : MATH.max(0, MATH.min(1, base / maxScroll));
+ };
+ var getHandleOffset = function (scrollRatio) {
+ var offset = handleTrackDiff * scrollRatio;
+ offset = isNaN(offset) ? 0 : offset;
+ offset = (isRTLisHorizontal && !_rtlScrollBehavior.i) ? (trackLength - handleLength - offset) : offset;
+ offset = MATH.max(0, offset);
+ return offset;
+ };
+ var scrollRatio = getScrollRatio(nativeScroll);
+ var unsnappedScrollRatio = getScrollRatio(currentScroll);
+ var handleOffset = getHandleOffset(unsnappedScrollRatio);
+ var snappedHandleOffset = getHandleOffset(scrollRatio);
+
+ scrollbarVarsInfo._maxScroll = maxScroll;
+ scrollbarVarsInfo._currentScroll = nativeScroll;
+ scrollbarVarsInfo._currentScrollRatio = scrollRatio;
+
+ if (_supportTransform) {
+ transformOffset = isRTLisHorizontal ? -(trackLength - handleLength - handleOffset) : handleOffset; //in px
+ //transformOffset = (transformOffset / trackLength * 100) * (trackLength / handleLength); //in %
+ translateValue = isHorizontal ? strTranslateBrace + transformOffset + 'px, 0)' : strTranslateBrace + '0, ' + transformOffset + 'px)';
+
+ handleCSS[strTransform] = translateValue;
+
+ //apply or clear up transition
+ if (_supportTransition)
+ handleCSS[strTransition] = transition && MATH.abs(handleOffset - scrollbarVarsInfo._handleOffset) > 1 ? getCSSTransitionString(scrollbarVars._handle) + ', ' + (strTransform + _strSpace + transitionDuration + 'ms') : _strEmpty;
+ }
+ else
+ handleCSS[scrollbarVars._left_top] = handleOffset;
+
+
+ //only apply css if offset has changed and overflow exists.
+ if (!nativeOverlayScrollbarsAreActive()) {
+ scrollbarVars._handle.css(handleCSS);
+
+ //clear up transition
+ if (_supportTransform && _supportTransition && transition) {
+ scrollbarVars._handle.one(_strTransitionEndEvent, function () {
+ if (!_destroyed)
+ scrollbarVars._handle.css(strTransition, _strEmpty);
+ });
+ }
+ }
+
+ scrollbarVarsInfo._handleOffset = handleOffset;
+ scrollbarVarsInfo._snappedHandleOffset = snappedHandleOffset;
+ scrollbarVarsInfo._trackLength = trackLength;
+ }
+
+ /**
+ * Refreshes the interactivity of the given scrollbar element.
+ * @param isTrack True if the track element is the target, false if the handle element is the target.
+ * @param value True for interactivity false for no interactivity.
+ */
+ function refreshScrollbarsInteractive(isTrack, value) {
+ var action = value ? 'removeClass' : 'addClass';
+ var element1 = isTrack ? _scrollbarHorizontalTrackElement : _scrollbarHorizontalHandleElement;
+ var element2 = isTrack ? _scrollbarVerticalTrackElement : _scrollbarVerticalHandleElement;
+ var className = isTrack ? _classNameScrollbarTrackOff : _classNameScrollbarHandleOff;
+
+ element1[action](className);
+ element2[action](className);
+ }
+
+ /**
+ * Returns a object which is used for fast access for specific variables.
+ * @param isHorizontal True if the horizontal scrollbar vars shall be accessed, false if the vertical scrollbar vars shall be accessed.
+ * @returns {{wh: string, WH: string, lt: string, _wh: string, _lt: string, t: *, h: *, c: {}, s: *}}
+ */
+ function getScrollbarVars(isHorizontal) {
+ return {
+ _width_height: isHorizontal ? _strWidth : _strHeight,
+ _Width_Height: isHorizontal ? 'Width' : 'Height',
+ _left_top: isHorizontal ? _strLeft : _strTop,
+ _Left_Top: isHorizontal ? 'Left' : 'Top',
+ _x_y: isHorizontal ? _strX : _strY,
+ _X_Y: isHorizontal ? 'X' : 'Y',
+ _w_h: isHorizontal ? 'w' : 'h',
+ _l_t: isHorizontal ? 'l' : 't',
+ _track: isHorizontal ? _scrollbarHorizontalTrackElement : _scrollbarVerticalTrackElement,
+ _handle: isHorizontal ? _scrollbarHorizontalHandleElement : _scrollbarVerticalHandleElement,
+ _scrollbar: isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement,
+ _info: isHorizontal ? _scrollHorizontalInfo : _scrollVerticalInfo
+ };
+ }
+
+
+ //==== Scrollbar Corner ====//
+
+ /**
+ * Builds or destroys the scrollbar corner DOM element.
+ * @param destroy Indicates whether the DOM shall be build or destroyed.
+ */
+ function setupScrollbarCornerDOM(destroy) {
+ _scrollbarCornerElement = _scrollbarCornerElement || selectOrGenerateDivByClass(_classNameScrollbarCorner, true);
+
+ if (!destroy) {
+ if (!_domExists) {
+ _hostElement.append(_scrollbarCornerElement);
+ }
+ }
+ else {
+ if (_domExists && _initialized) {
+ removeClass(_scrollbarCornerElement.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
+ }
+ else {
+ remove(_scrollbarCornerElement);
+ }
+ }
+ }
+
+ /**
+ * Initializes all scrollbar corner interactivity events.
+ */
+ function setupScrollbarCornerEvents() {
+ var insideIFrame = _windowElementNative.top !== _windowElementNative;
+ var mouseDownPosition = {};
+ var mouseDownSize = {};
+ var mouseDownInvertedScale = {};
+ var reconnectMutationObserver;
+
+ function documentDragMove(event) {
+ if (onMouseTouchDownContinue(event)) {
+ var pageOffset = getCoordinates(event);
+ var hostElementCSS = {};
+ if (_resizeHorizontal || _resizeBoth)
+ hostElementCSS[_strWidth] = (mouseDownSize.w + (pageOffset.x - mouseDownPosition.x) * mouseDownInvertedScale.x);
+ if (_resizeVertical || _resizeBoth)
+ hostElementCSS[_strHeight] = (mouseDownSize.h + (pageOffset.y - mouseDownPosition.y) * mouseDownInvertedScale.y);
+ _hostElement.css(hostElementCSS);
+ COMPATIBILITY.stpP(event);
+ }
+ else {
+ documentMouseTouchUp(event);
+ }
+ }
+ function documentMouseTouchUp(event) {
+ var eventIsTrusted = event !== undefined;
+
+ setupResponsiveEventListener(_documentElement,
+ [_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],
+ [documentOnSelectStart, documentDragMove, documentMouseTouchUp],
+ true);
+
+ removeClass(_bodyElement, _classNameDragging);
+ if (_scrollbarCornerElement.releaseCapture)
+ _scrollbarCornerElement.releaseCapture();
+
+ if (eventIsTrusted) {
+ if (reconnectMutationObserver)
+ connectMutationObservers();
+ _base.update(_strAuto);
+ }
+ reconnectMutationObserver = false;
+ }
+ function onMouseTouchDownContinue(event) {
+ var originalEvent = event.originalEvent || event;
+ var isTouchEvent = originalEvent.touches !== undefined;
+ return _sleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
+ }
+ function getCoordinates(event) {
+ return _msieVersion && insideIFrame ? { x: event.screenX, y: event.screenY } : COMPATIBILITY.page(event);
+ }
+
+ addDestroyEventListener(_scrollbarCornerElement, _strMouseTouchDownEvent, function (event) {
+ if (onMouseTouchDownContinue(event) && !_resizeNone) {
+ if (_mutationObserversConnected) {
+ reconnectMutationObserver = true;
+ disconnectMutationObservers();
+ }
+
+ mouseDownPosition = getCoordinates(event);
+
+ mouseDownSize.w = _hostElementNative[LEXICON.oW] - (!_isBorderBox ? _paddingX : 0);
+ mouseDownSize.h = _hostElementNative[LEXICON.oH] - (!_isBorderBox ? _paddingY : 0);
+ mouseDownInvertedScale = getHostElementInvertedScale();
+
+ setupResponsiveEventListener(_documentElement,
+ [_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],
+ [documentOnSelectStart, documentDragMove, documentMouseTouchUp]);
+
+ addClass(_bodyElement, _classNameDragging);
+ if (_scrollbarCornerElement.setCapture)
+ _scrollbarCornerElement.setCapture();
+
+ COMPATIBILITY.prvD(event);
+ COMPATIBILITY.stpP(event);
+ }
+ });
+ }
+
+
+ //==== Utils ====//
+
+ /**
+ * Calls the callback with the given name. The Context of this callback is always _base (this).
+ * @param name The name of the target which shall be called.
+ * @param args The args with which the callback shall be called.
+ */
+ function dispatchCallback(name, args) {
+ if (_initialized) {
+ var callback = _currentPreparedOptions.callbacks[name];
+ var extensionOnName = name;
+ var ext;
+
+ if (extensionOnName.substr(0, 2) === 'on')
+ extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3);
+
+ if (type(callback) == TYPES.f)
+ callback.call(_base, args);
+
+ each(_extensions, function () {
+ ext = this;
+ if (type(ext.on) == TYPES.f)
+ ext.on(extensionOnName, args);
+ });
+ }
+ else if (!_destroyed)
+ _callbacksInitQeueue.push({ n: name, a: args });
+ }
+
+ /**
+ * Sets the "top, right, bottom, left" properties, with a given prefix, of the given css object.
+ * @param targetCSSObject The css object to which the values shall be applied.
+ * @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
+ * @param values A array of values which shall be applied to the "top, right, bottom, left" -properties. The array order is [top, right, bottom, left].
+ * If this argument is undefined the value '' (empty string) will be applied to all properties.
+ */
+ function setTopRightBottomLeft(targetCSSObject, prefix, values) {
+ if (values === undefined)
+ values = [_strEmpty, _strEmpty, _strEmpty, _strEmpty];
+
+ targetCSSObject[prefix + _strTop] = values[0];
+ targetCSSObject[prefix + _strRight] = values[1];
+ targetCSSObject[prefix + _strBottom] = values[2];
+ targetCSSObject[prefix + _strLeft] = values[3];
+ }
+
+ /**
+ * Returns the computed CSS transition string from the given element.
+ * @param element The element from which the transition string shall be returned.
+ * @returns {string} The CSS transition string from the given element.
+ */
+ function getCSSTransitionString(element) {
+ var transitionStr = VENDORS._cssProperty('transition');
+ var assembledValue = element.css(transitionStr);
+ if (assembledValue)
+ return assembledValue;
+ var regExpString = '\\s*(' + '([^,(]+(\\(.+?\\))?)+' + ')[\\s,]*';
+ var regExpMain = new RegExp(regExpString);
+ var regExpValidate = new RegExp('^(' + regExpString + ')+$');
+ var properties = 'property duration timing-function delay'.split(' ');
+ var result = [];
+ var strResult;
+ var valueArray;
+ var i = 0;
+ var j;
+ var splitCssStyleByComma = function (str) {
+ strResult = [];
+ if (!str.match(regExpValidate))
+ return str;
+ while (str.match(regExpMain)) {
+ strResult.push(RegExp.$1);
+ str = str.replace(regExpMain, _strEmpty);
+ }
+
+ return strResult;
+ };
+ for (; i < properties[LEXICON.l]; i++) {
+ valueArray = splitCssStyleByComma(element.css(transitionStr + '-' + properties[i]));
+ for (j = 0; j < valueArray[LEXICON.l]; j++)
+ result[j] = (result[j] ? result[j] + _strSpace : _strEmpty) + valueArray[j];
+ }
+ return result.join(', ');
+ }
+
+ /**
+ * Calculates the host-elements inverted scale. (invertedScale = 1 / scale)
+ * @returns {{x: number, y: number}} The scale of the host-element.
+ */
+ function getHostElementInvertedScale() {
+ var rect = _paddingElementNative[LEXICON.bCR]();
+ return {
+ x: _supportTransform ? 1 / (MATH.round(rect.width) / _paddingElementNative[LEXICON.oW]) || 1 : 1,
+ y: _supportTransform ? 1 / (MATH.round(rect.height) / _paddingElementNative[LEXICON.oH]) || 1 : 1
+ };
+ }
+
+ /**
+ * Checks whether the given object is a HTMLElement.
+ * @param o The object which shall be checked.
+ * @returns {boolean} True the given object is a HTMLElement, false otherwise.
+ */
+ function isHTMLElement(o) {
+ var strOwnerDocument = 'ownerDocument';
+ var strHTMLElement = 'HTMLElement';
+ var wnd = o && o[strOwnerDocument] ? (o[strOwnerDocument].parentWindow || window) : window;
+ return (
+ typeof wnd[strHTMLElement] == TYPES.o ? o instanceof wnd[strHTMLElement] : //DOM2
+ o && typeof o == TYPES.o && o !== null && o.nodeType === 1 && typeof o.nodeName == TYPES.s
+ );
+ }
+
+ /**
+ * Compares 2 arrays and returns the differences between them as a array.
+ * @param a1 The first array which shall be compared.
+ * @param a2 The second array which shall be compared.
+ * @returns {Array} The differences between the two arrays.
+ */
+ function getArrayDifferences(a1, a2) {
+ var a = [];
+ var diff = [];
+ var i;
+ var k;
+ for (i = 0; i < a1.length; i++)
+ a[a1[i]] = true;
+ for (i = 0; i < a2.length; i++) {
+ if (a[a2[i]])
+ delete a[a2[i]];
+ else
+ a[a2[i]] = true;
+ }
+ for (k in a)
+ diff.push(k);
+ return diff;
+ }
+
+ /**
+ * Returns Zero or the number to which the value can be parsed.
+ * @param value The value which shall be parsed.
+ * @param toFloat Indicates whether the number shall be parsed to a float.
+ */
+ function parseToZeroOrNumber(value, toFloat) {
+ var num = toFloat ? parseFloat(value) : parseInt(value, 10);
+ return isNaN(num) ? 0 : num;
+ }
+
+ /**
+ * Gets several information of the textarea and returns them as a object or undefined if the browser doesn't support it.
+ * @returns {{cursorRow: Number, cursorCol, rows: Number, cols: number, wRow: number, pos: number, max : number}} or undefined if not supported.
+ */
+ function getTextareaInfo() {
+ //read needed values
+ var textareaCursorPosition = _targetElementNative.selectionStart;
+ if (textareaCursorPosition === undefined)
+ return;
+
+ var textareaValue = _targetElement.val();
+ var textareaLength = textareaValue[LEXICON.l];
+ var textareaRowSplit = textareaValue.split('\n');
+ var textareaLastRow = textareaRowSplit[LEXICON.l];
+ var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split('\n');
+ var widestRow = 0;
+ var textareaLastCol = 0;
+ var cursorRow = textareaCurrentCursorRowSplit[LEXICON.l];
+ var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[LEXICON.l] - 1][LEXICON.l];
+ var rowCols;
+ var i;
+
+ //get widest Row and the last column of the textarea
+ for (i = 0; i < textareaRowSplit[LEXICON.l]; i++) {
+ rowCols = textareaRowSplit[i][LEXICON.l];
+ if (rowCols > textareaLastCol) {
+ widestRow = i + 1;
+ textareaLastCol = rowCols;
+ }
+ }
+
+ return {
+ _cursorRow: cursorRow, //cursorRow
+ _cursorColumn: cursorCol, //cursorCol
+ _rows: textareaLastRow, //rows
+ _columns: textareaLastCol, //cols
+ _widestRow: widestRow, //wRow
+ _cursorPosition: textareaCursorPosition, //pos
+ _cursorMax: textareaLength //max
+ };
+ }
+
+ /**
+ * Determines whether native overlay scrollbars are active.
+ * @returns {boolean} True if native overlay scrollbars are active, false otherwise.
+ */
+ function nativeOverlayScrollbarsAreActive() {
+ return (_ignoreOverlayScrollbarHidingCache && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y));
+ }
+
+ /**
+ * Gets the element which is used to measure the content size.
+ * @returns {*} TextareaCover if target element is textarea else the ContentElement.
+ */
+ function getContentMeasureElement() {
+ return _isTextarea ? _textareaCoverElement[0] : _contentElementNative;
+ }
+
+ /**
+ * Generates a string which represents a HTML div with the given classes or attributes.
+ * @param classesOrAttrs The class of the div as string or a object which represents the attributes of the div. (The class attribute can also be written as "className".)
+ * @param content The content of the div as string.
+ * @returns {string} The concated string which represents a HTML div and its content.
+ */
+ function generateDiv(classesOrAttrs, content) {
+ return '
' +
+ (content || _strEmpty) +
+ '
';
+ }
+
+ /**
+ * Selects or generates a div with the given class attribute.
+ * @param className The class names (divided by spaces) of the div which shall be selected or generated.
+ * @param selectParentOrOnlyChildren The parent element from which of the element shall be selected. (if undefined or boolean its hostElement)
+ * If its a boolean it decides whether only the children of the host element shall be selected.
+ * @returns {*} The generated or selected element.
+ */
+ function selectOrGenerateDivByClass(className, selectParentOrOnlyChildren) {
+ var onlyChildren = type(selectParentOrOnlyChildren) == TYPES.b;
+ var selectParent = onlyChildren ? _hostElement : (selectParentOrOnlyChildren || _hostElement);
+
+ return (_domExists && !selectParent[LEXICON.l])
+ ? null
+ : _domExists
+ ? selectParent[onlyChildren ? 'children' : 'find'](_strDot + className.replace(/\s/g, _strDot)).eq(0)
+ : FRAMEWORK(generateDiv(className))
+ }
+
+ /**
+ * Gets the value of the given property from the given object.
+ * @param obj The object from which the property value shall be got.
+ * @param path The property of which the value shall be got.
+ * @returns {*} Returns the value of the searched property or undefined of the property wasn't found.
+ */
+ function getObjectPropVal(obj, path) {
+ var splits = path.split(_strDot);
+ var i = 0;
+ var val;
+ for (; i < splits.length; i++) {
+ if (!obj[LEXICON.hOP](splits[i]))
+ return;
+ val = obj[splits[i]];
+ if (i < splits.length && type(val) == TYPES.o)
+ obj = val;
+ }
+ return val;
+ }
+
+ /**
+ * Sets the value of the given property from the given object.
+ * @param obj The object from which the property value shall be set.
+ * @param path The property of which the value shall be set.
+ * @param val The value of the property which shall be set.
+ */
+ function setObjectPropVal(obj, path, val) {
+ var splits = path.split(_strDot);
+ var splitsLength = splits.length;
+ var i = 0;
+ var extendObj = {};
+ var extendObjRoot = extendObj;
+ for (; i < splitsLength; i++)
+ extendObj = extendObj[splits[i]] = i + 1 < splitsLength ? {} : val;
+ FRAMEWORK.extend(obj, extendObjRoot, true);
+ }
+
+
+ //==== Utils Cache ====//
+
+ /**
+ * Compares two values or objects and returns true if they aren't equal.
+ * @param current The first value or object which shall be compared.
+ * @param cache The second value or object which shall be compared.
+ * @param force If true the returned value is always true.
+ * @returns {boolean} True if both values or objects aren't equal or force is true, false otherwise.
+ */
+ function checkCache(current, cache, force) {
+ if (force)
+ return force;
+ if (type(current) == TYPES.o && type(cache) == TYPES.o) {
+ for (var prop in current) {
+ if (prop !== 'c') {
+ if (current[LEXICON.hOP](prop) && cache[LEXICON.hOP](prop)) {
+ if (checkCache(current[prop], cache[prop]))
+ return true;
+ }
+ else {
+ return true;
+ }
+ }
+ }
+ }
+ else {
+ return current !== cache;
+ }
+ return false;
+ }
+
+
+ //==== Shortcuts ====//
+
+ /**
+ * jQuery extend method shortcut with a appended "true" as first argument.
+ */
+ function extendDeep() {
+ return FRAMEWORK.extend.apply(this, [true].concat([].slice.call(arguments)));
+ }
+
+ /**
+ * jQuery addClass method shortcut.
+ */
+ function addClass(el, classes) {
+ return _frameworkProto.addClass.call(el, classes);
+ }
+
+ /**
+ * jQuery removeClass method shortcut.
+ */
+ function removeClass(el, classes) {
+ return _frameworkProto.removeClass.call(el, classes);
+ }
+
+ /**
+ * jQuery remove method shortcut.
+ */
+ function remove(el) {
+ return _frameworkProto.remove.call(el);
+ }
+
+ /**
+ * Finds the first child element with the given selector of the given element.
+ * @param el The root element from which the selector shall be valid.
+ * @param selector The selector of the searched element.
+ * @returns {*} The first element which is a child of the given element and matches the givens selector.
+ */
+ function findFirst(el, selector) {
+ return _frameworkProto.find.call(el, selector).eq(0);
+ }
+
+
+ //==== API ====//
+
+ /**
+ * Puts the instance to sleep. It wont respond to any changes in the DOM and won't update. Scrollbar Interactivity is also disabled as well as the resize handle.
+ * This behavior can be reset by calling the update method.
+ */
+ _base.sleep = function () {
+ _sleeping = true;
+ };
+
+ /**
+ * Updates the plugin and DOM to the current options.
+ * This method should only be called if a update is 100% required.
+ * @param force True if every property shall be updated and the cache shall be ignored.
+ * !INTERNAL USAGE! : force can be a string "auto", "sync" or "zoom" too
+ * if "auto" then before a real update the content size and host element attributes gets checked, and if they changed only then the update method will be called.
+ * if "sync" then the async update process (MutationObserver or UpdateLoop) gets synchronized and a corresponding update takes place if one was needed due to pending changes.
+ * if "zoom" then a update takes place where it's assumed that content and host size changed
+ * @returns {boolean|undefined}
+ * If force is "sync" then a boolean is returned which indicates whether a update was needed due to pending changes.
+ * If force is "auto" then a boolean is returned whether a update was needed due to attribute or size changes.
+ * undefined otherwise.
+ */
+ _base.update = function (force) {
+ if (_destroyed)
+ return;
+
+ var attrsChanged;
+ var contentSizeC;
+ var isString = type(force) == TYPES.s;
+ var imgElementSelector = 'img';
+ var imgElementLoadEvent = 'load';
+ var doUpdateAuto;
+ var mutHost;
+ var mutContent;
+
+ if (isString) {
+ if (force === _strAuto) {
+ attrsChanged = meaningfulAttrsChanged();
+ contentSizeC = updateAutoContentSizeChanged();
+ doUpdateAuto = attrsChanged || contentSizeC;
+ if (doUpdateAuto) {
+ update({
+ _contentSizeChanged: contentSizeC,
+ _changedOptions: _initialized ? undefined : _currentPreparedOptions
+ });
+ }
+ }
+ else if (force === _strSync) {
+ if (_mutationObserversConnected) {
+ mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords());
+ mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords());
+ }
+ else {
+ mutHost = _base.update(_strAuto);
+ }
+ }
+ else if (force === 'zoom') {
+ update({
+ _hostSizeChanged: true,
+ _contentSizeChanged: true
+ });
+ }
+ }
+ else {
+ force = _sleeping || force;
+ _sleeping = false;
+ if (!_base.update(_strSync) || force)
+ update({ _force: force });
+ }
+ if (!_isTextarea) {
+ _contentElement.find(imgElementSelector).each(function (i, el) {
+ var index = COMPATIBILITY.inA(el, _imgs);
+ if (index === -1)
+ FRAMEWORK(el).off(imgElementLoadEvent, imgOnLoad).on(imgElementLoadEvent, imgOnLoad);
+ });
+ }
+ return doUpdateAuto || mutHost || mutContent;
+ };
+
+ /**
+ Gets or sets the current options. The update method will be called automatically if new options were set.
+ * @param newOptions If new options are given, then the new options will be set, if new options aren't given (undefined or a not a plain object) then the current options will be returned.
+ * @param value If new options is a property path string, then this value will be used to set the option to which the property path string leads.
+ * @returns {*}
+ */
+ _base.options = function (newOptions, value) {
+ var option = {};
+ var changedOps;
+
+ //return current options if newOptions are undefined or empty
+ if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) {
+ if (type(newOptions) == TYPES.s) {
+ if (arguments.length > 1) {
+ setObjectPropVal(option, newOptions, value);
+ changedOps = setOptions(option);
+ }
+ else
+ return getObjectPropVal(_currentOptions, newOptions);
+ }
+ else
+ return _currentOptions;
+ }
+ else {
+ changedOps = setOptions(newOptions);
+ }
+
+ if (!FRAMEWORK.isEmptyObject(changedOps)) {
+ update({ _changedOptions: changedOps });
+ }
+ };
+
+ /**
+ * Restore the DOM, disconnects all observers, remove all resize observers and put the instance to sleep.
+ */
+ _base.destroy = function () {
+ if (_destroyed)
+ return;
+
+ //remove this instance from auto update loop
+ autoUpdateLoop.remove(_base);
+
+ //disconnect all mutation observers
+ disconnectMutationObservers();
+
+ //remove all resize observers
+ setupResizeObserver(_sizeObserverElement);
+ setupResizeObserver(_sizeAutoObserverElement);
+
+ //remove all extensions
+ for (var extName in _extensions)
+ _base.removeExt(extName);
+
+ //remove all 'destroy' events
+ while (_destroyEvents[LEXICON.l] > 0)
+ _destroyEvents.pop()();
+
+ //remove all events from host element
+ setupHostMouseTouchEvents(true);
+
+ //remove all helper / detection elements
+ if (_contentGlueElement)
+ remove(_contentGlueElement);
+ if (_contentArrangeElement)
+ remove(_contentArrangeElement);
+ if (_sizeAutoObserverAdded)
+ remove(_sizeAutoObserverElement);
+
+ //remove all generated DOM
+ setupScrollbarsDOM(true);
+ setupScrollbarCornerDOM(true);
+ setupStructureDOM(true);
+
+ //remove all generated image load events
+ for (var i = 0; i < _imgs[LEXICON.l]; i++)
+ FRAMEWORK(_imgs[i]).off('load', imgOnLoad);
+ _imgs = undefined;
+
+ _destroyed = true;
+ _sleeping = true;
+
+ //remove this instance from the instances list
+ INSTANCES(pluginTargetElement, 0);
+ dispatchCallback('onDestroyed');
+
+ //remove all properties and methods
+ //for (var property in _base)
+ // delete _base[property];
+ //_base = undefined;
+ };
+
+ /**
+ * Scrolls to a given position or element.
+ * @param coordinates
+ * 1. Can be "coordinates" which looks like:
+ * { x : ?, y : ? } OR Object with x and y properties
+ * { left : ?, top : ? } OR Object with left and top properties
+ * { l : ?, t : ? } OR Object with l and t properties
+ * [ ?, ? ] OR Array where the first two element are the coordinates (first is x, second is y)
+ * ? A single value which stays for both axis
+ * A value can be a number, a string or a calculation.
+ *
+ * Operators:
+ * [NONE] The current scroll will be overwritten by the value.
+ * '+=' The value will be added to the current scroll offset
+ * '-=' The value will be subtracted from the current scroll offset
+ * '*=' The current scroll wil be multiplicated by the value.
+ * '/=' The current scroll wil be divided by the value.
+ *
+ * Units:
+ * [NONE] The value is the final scroll amount. final = (value * 1)
+ * 'px' Same as none
+ * '%' The value is dependent on the current scroll value. final = ((currentScrollValue / 100) * value)
+ * 'vw' The value is multiplicated by the viewport width. final = (value * viewportWidth)
+ * 'vh' The value is multiplicated by the viewport height. final = (value * viewportHeight)
+ *
+ * example final values:
+ * 200, '200px', '50%', '1vw', '1vh', '+=200', '/=1vw', '*=2px', '-=5vh', '+=33%', '+= 50% - 2px', '-= 1vw - 50%'
+ *
+ * 2. Can be a HTML or jQuery element:
+ * The final scroll offset is the offset (without margin) of the given HTML / jQuery element.
+ *
+ * 3. Can be a object with a HTML or jQuery element with additional settings:
+ * {
+ * el : [HTMLElement, jQuery element], MUST be specified, else this object isn't valid.
+ * scroll : [string, array, object], Default value is 'always'.
+ * block : [string, array, object], Default value is 'begin'.
+ * margin : [number, boolean, array, object] Default value is false.
+ * }
+ *
+ * Possible scroll settings are:
+ * 'always' Scrolls always.
+ * 'ifneeded' Scrolls only if the element isnt fully in view.
+ * 'never' Scrolls never.
+ *
+ * Possible block settings are:
+ * 'begin' Both axis shall be docked to the "begin" edge. - The element will be docked to the top and left edge of the viewport.
+ * 'end' Both axis shall be docked to the "end" edge. - The element will be docked to the bottom and right edge of the viewport. (If direction is RTL to the bottom and left edge.)
+ * 'center' Both axis shall be docked to "center". - The element will be centered in the viewport.
+ * 'nearest' The element will be docked to the nearest edge(s).
+ *
+ * Possible margin settings are: -- The actual margin of the element wont be affect, this option affects only the final scroll offset.
+ * [BOOLEAN] If true the css margin of the element will be used, if false no margin will be used.
+ * [NUMBER] The margin will be used for all edges.
+ *
+ * @param duration The duration of the scroll animation, OR a jQuery animation configuration object.
+ * @param easing The animation easing.
+ * @param complete The animation complete callback.
+ * @returns {{
+ * position: {x: number, y: number},
+ * ratio: {x: number, y: number},
+ * max: {x: number, y: number},
+ * handleOffset: {x: number, y: number},
+ * handleLength: {x: number, y: number},
+ * handleLengthRatio: {x: number, y: number}, t
+ * rackLength: {x: number, y: number},
+ * isRTL: boolean,
+ * isRTLNormalized: boolean
+ * }}
+ */
+ _base.scroll = function (coordinates, duration, easing, complete) {
+ if (arguments.length === 0 || coordinates === undefined) {
+ var infoX = _scrollHorizontalInfo;
+ var infoY = _scrollVerticalInfo;
+ var normalizeInvert = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.i;
+ var normalizeNegate = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.n;
+ var scrollX = infoX._currentScroll;
+ var scrollXRatio = infoX._currentScrollRatio;
+ var maxScrollX = infoX._maxScroll;
+ scrollXRatio = normalizeInvert ? 1 - scrollXRatio : scrollXRatio;
+ scrollX = normalizeInvert ? maxScrollX - scrollX : scrollX;
+ scrollX *= normalizeNegate ? -1 : 1;
+ maxScrollX *= normalizeNegate ? -1 : 1;
+
+ return {
+ position: {
+ x: scrollX,
+ y: infoY._currentScroll
+ },
+ ratio: {
+ x: scrollXRatio,
+ y: infoY._currentScrollRatio
+ },
+ max: {
+ x: maxScrollX,
+ y: infoY._maxScroll
+ },
+ handleOffset: {
+ x: infoX._handleOffset,
+ y: infoY._handleOffset
+ },
+ handleLength: {
+ x: infoX._handleLength,
+ y: infoY._handleLength
+ },
+ handleLengthRatio: {
+ x: infoX._handleLengthRatio,
+ y: infoY._handleLengthRatio
+ },
+ trackLength: {
+ x: infoX._trackLength,
+ y: infoY._trackLength
+ },
+ snappedHandleOffset: {
+ x: infoX._snappedHandleOffset,
+ y: infoY._snappedHandleOffset
+ },
+ isRTL: _isRTL,
+ isRTLNormalized: _normalizeRTLCache
+ };
+ }
+
+ _base.update(_strSync);
+
+ var normalizeRTL = _normalizeRTLCache;
+ var coordinatesXAxisProps = [_strX, _strLeft, 'l'];
+ var coordinatesYAxisProps = [_strY, _strTop, 't'];
+ var coordinatesOperators = ['+=', '-=', '*=', '/='];
+ var durationIsObject = type(duration) == TYPES.o;
+ var completeCallback = durationIsObject ? duration.complete : complete;
+ var i;
+ var finalScroll = {};
+ var specialEasing = {};
+ var doScrollLeft;
+ var doScrollTop;
+ var animationOptions;
+ var strEnd = 'end';
+ var strBegin = 'begin';
+ var strCenter = 'center';
+ var strNearest = 'nearest';
+ var strAlways = 'always';
+ var strNever = 'never';
+ var strIfNeeded = 'ifneeded';
+ var strLength = LEXICON.l;
+ var settingsAxis;
+ var settingsScroll;
+ var settingsBlock;
+ var settingsMargin;
+ var finalElement;
+ var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx'];
+ var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest];
+ var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded];
+ var coordinatesIsElementObj = coordinates[LEXICON.hOP]('el');
+ var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates;
+ var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false;
+ var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement);
+ var updateScrollbarInfos = function () {
+ if (doScrollLeft)
+ refreshScrollbarHandleOffset(true);
+ if (doScrollTop)
+ refreshScrollbarHandleOffset(false);
+ };
+ var proxyCompleteCallback = type(completeCallback) != TYPES.f ? undefined : function () {
+ updateScrollbarInfos();
+ completeCallback();
+ };
+ function checkSettingsStringValue(currValue, allowedValues) {
+ for (i = 0; i < allowedValues[strLength]; i++) {
+ if (currValue === allowedValues[i])
+ return true;
+ }
+ return false;
+ }
+ function getRawScroll(isX, coordinates) {
+ var coordinateProps = isX ? coordinatesXAxisProps : coordinatesYAxisProps;
+ coordinates = type(coordinates) == TYPES.s || type(coordinates) == TYPES.n ? [coordinates, coordinates] : coordinates;
+
+ if (type(coordinates) == TYPES.a)
+ return isX ? coordinates[0] : coordinates[1];
+ else if (type(coordinates) == TYPES.o) {
+ //decides RTL normalization "hack" with .n
+ //normalizeRTL = type(coordinates.n) == TYPES.b ? coordinates.n : normalizeRTL;
+ for (i = 0; i < coordinateProps[strLength]; i++)
+ if (coordinateProps[i] in coordinates)
+ return coordinates[coordinateProps[i]];
+ }
+ }
+ function getFinalScroll(isX, rawScroll) {
+ var isString = type(rawScroll) == TYPES.s;
+ var operator;
+ var amount;
+ var scrollInfo = isX ? _scrollHorizontalInfo : _scrollVerticalInfo;
+ var currScroll = scrollInfo._currentScroll;
+ var maxScroll = scrollInfo._maxScroll;
+ var mult = ' * ';
+ var finalValue;
+ var isRTLisX = _isRTL && isX;
+ var normalizeShortcuts = isRTLisX && _rtlScrollBehavior.n && !normalizeRTL;
+ var strReplace = 'replace';
+ var evalFunc = eval;
+ var possibleOperator;
+ if (isString) {
+ //check operator
+ if (rawScroll[strLength] > 2) {
+ possibleOperator = rawScroll.substr(0, 2);
+ if (inArray(possibleOperator, coordinatesOperators) > -1)
+ operator = possibleOperator;
+ }
+
+ //calculate units and shortcuts
+ rawScroll = operator ? rawScroll.substr(2) : rawScroll;
+ rawScroll = rawScroll
+ [strReplace](/min/g, 0) //'min' = 0%
+ [strReplace](//g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'>' = 100%
+ [strReplace](/px/g, _strEmpty)
+ [strReplace](/%/g, mult + (maxScroll * (isRTLisX && _rtlScrollBehavior.n ? -1 : 1) / 100.0))
+ [strReplace](/vw/g, mult + _viewportSize.w)
+ [strReplace](/vh/g, mult + _viewportSize.h);
+ amount = parseToZeroOrNumber(isNaN(rawScroll) ? parseToZeroOrNumber(evalFunc(rawScroll), true).toFixed() : rawScroll);
+ }
+ else {
+ amount = rawScroll;
+ }
+
+ if (amount !== undefined && !isNaN(amount) && type(amount) == TYPES.n) {
+ var normalizeIsRTLisX = normalizeRTL && isRTLisX;
+ var operatorCurrScroll = currScroll * (normalizeIsRTLisX && _rtlScrollBehavior.n ? -1 : 1);
+ var invert = normalizeIsRTLisX && _rtlScrollBehavior.i;
+ var negate = normalizeIsRTLisX && _rtlScrollBehavior.n;
+ operatorCurrScroll = invert ? (maxScroll - operatorCurrScroll) : operatorCurrScroll;
+ switch (operator) {
+ case '+=':
+ finalValue = operatorCurrScroll + amount;
+ break;
+ case '-=':
+ finalValue = operatorCurrScroll - amount;
+ break;
+ case '*=':
+ finalValue = operatorCurrScroll * amount;
+ break;
+ case '/=':
+ finalValue = operatorCurrScroll / amount;
+ break;
+ default:
+ finalValue = amount;
+ break;
+ }
+ finalValue = invert ? maxScroll - finalValue : finalValue;
+ finalValue *= negate ? -1 : 1;
+ finalValue = isRTLisX && _rtlScrollBehavior.n ? MATH.min(0, MATH.max(maxScroll, finalValue)) : MATH.max(0, MATH.min(maxScroll, finalValue));
+ }
+ return finalValue === currScroll ? undefined : finalValue;
+ }
+ function getPerAxisValue(value, valueInternalType, defaultValue, allowedValues) {
+ var resultDefault = [defaultValue, defaultValue];
+ var valueType = type(value);
+ var valueArrLength;
+ var valueArrItem;
+
+ //value can be [ string, or array of two strings ]
+ if (valueType == valueInternalType) {
+ value = [value, value];
+ }
+ else if (valueType == TYPES.a) {
+ valueArrLength = value[strLength];
+ if (valueArrLength > 2 || valueArrLength < 1)
+ value = resultDefault;
+ else {
+ if (valueArrLength === 1)
+ value[1] = defaultValue;
+ for (i = 0; i < valueArrLength; i++) {
+ valueArrItem = value[i];
+ if (type(valueArrItem) != valueInternalType || !checkSettingsStringValue(valueArrItem, allowedValues)) {
+ value = resultDefault;
+ break;
+ }
+ }
+ }
+ }
+ else if (valueType == TYPES.o)
+ value = [value[_strX] || defaultValue, value[_strY] || defaultValue];
+ else
+ value = resultDefault;
+ return { x: value[0], y: value[1] };
+ }
+ function generateMargin(marginTopRightBottomLeftArray) {
+ var result = [];
+ var currValue;
+ var currValueType;
+ var valueDirections = [_strTop, _strRight, _strBottom, _strLeft];
+ for (i = 0; i < marginTopRightBottomLeftArray[strLength]; i++) {
+ if (i === valueDirections[strLength])
+ break;
+ currValue = marginTopRightBottomLeftArray[i];
+ currValueType = type(currValue);
+ if (currValueType == TYPES.b)
+ result.push(currValue ? parseToZeroOrNumber(finalElement.css(_strMarginMinus + valueDirections[i])) : 0);
+ else
+ result.push(currValueType == TYPES.n ? currValue : 0);
+ }
+ return result;
+ }
+
+ if (possibleElementIsJQuery || possibleElementIsHTMLElement) {
+ //get settings
+ var margin = coordinatesIsElementObj ? coordinates.margin : 0;
+ var axis = coordinatesIsElementObj ? coordinates.axis : 0;
+ var scroll = coordinatesIsElementObj ? coordinates.scroll : 0;
+ var block = coordinatesIsElementObj ? coordinates.block : 0;
+ var marginDefault = [0, 0, 0, 0];
+ var marginType = type(margin);
+ var marginLength;
+ finalElement = possibleElementIsJQuery ? possibleElement : FRAMEWORK(possibleElement);
+
+ if (finalElement[strLength] > 0) {
+ //margin can be [ boolean, number, array of 2, array of 4, object ]
+ if (marginType == TYPES.n || marginType == TYPES.b)
+ margin = generateMargin([margin, margin, margin, margin]);
+ else if (marginType == TYPES.a) {
+ marginLength = margin[strLength];
+ if (marginLength === 2)
+ margin = generateMargin([margin[0], margin[1], margin[0], margin[1]]);
+ else if (marginLength >= 4)
+ margin = generateMargin(margin);
+ else
+ margin = marginDefault;
+ }
+ else if (marginType == TYPES.o)
+ margin = generateMargin([margin[_strTop], margin[_strRight], margin[_strBottom], margin[_strLeft]]);
+ else
+ margin = marginDefault;
+
+ //block = type(block) === TYPES.b ? block ? [ strNearest, strBegin ] : [ strNearest, strEnd ] : block;
+ settingsAxis = checkSettingsStringValue(axis, elementObjSettingsAxisValues) ? axis : 'xy';
+ settingsScroll = getPerAxisValue(scroll, TYPES.s, strAlways, elementObjSettingsScrollValues);
+ settingsBlock = getPerAxisValue(block, TYPES.s, strBegin, elementObjSettingsBlockValues);
+ settingsMargin = margin;
+
+ var viewportScroll = {
+ l: _scrollHorizontalInfo._currentScroll,
+ t: _scrollVerticalInfo._currentScroll
+ };
+ // use padding element instead of viewport element because padding element has never padding, margin or position applied.
+ var viewportOffset = _paddingElement.offset();
+
+ //get coordinates
+ var elementOffset = finalElement.offset();
+ var doNotScroll = {
+ x: settingsScroll.x == strNever || settingsAxis == _strY,
+ y: settingsScroll.y == strNever || settingsAxis == _strX
+ };
+ elementOffset[_strTop] -= settingsMargin[0];
+ elementOffset[_strLeft] -= settingsMargin[3];
+ var elementScrollCoordinates = {
+ x: MATH.round(elementOffset[_strLeft] - viewportOffset[_strLeft] + viewportScroll.l),
+ y: MATH.round(elementOffset[_strTop] - viewportOffset[_strTop] + viewportScroll.t)
+ };
+ if (_isRTL) {
+ if (!_rtlScrollBehavior.n && !_rtlScrollBehavior.i)
+ elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + viewportScroll.l);
+ if (_rtlScrollBehavior.n && normalizeRTL)
+ elementScrollCoordinates.x *= -1;
+ if (_rtlScrollBehavior.i && normalizeRTL)
+ elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + (_scrollHorizontalInfo._maxScroll - viewportScroll.l));
+ }
+
+ //measuring is required
+ if (settingsBlock.x != strBegin || settingsBlock.y != strBegin || settingsScroll.x == strIfNeeded || settingsScroll.y == strIfNeeded || _isRTL) {
+ var measuringElm = finalElement[0];
+ var rawElementSize = _supportTransform ? measuringElm[LEXICON.bCR]() : {
+ width: measuringElm[LEXICON.oW],
+ height: measuringElm[LEXICON.oH]
+ };
+ var elementSize = {
+ w: rawElementSize[_strWidth] + settingsMargin[3] + settingsMargin[1],
+ h: rawElementSize[_strHeight] + settingsMargin[0] + settingsMargin[2]
+ };
+ var finalizeBlock = function (isX) {
+ var vars = getScrollbarVars(isX);
+ var wh = vars._w_h;
+ var lt = vars._left_top;
+ var xy = vars._x_y;
+ var blockIsEnd = settingsBlock[xy] == (isX ? _isRTL ? strBegin : strEnd : strEnd);
+ var blockIsCenter = settingsBlock[xy] == strCenter;
+ var blockIsNearest = settingsBlock[xy] == strNearest;
+ var scrollNever = settingsScroll[xy] == strNever;
+ var scrollIfNeeded = settingsScroll[xy] == strIfNeeded;
+ var vpSize = _viewportSize[wh];
+ var vpOffset = viewportOffset[lt];
+ var elSize = elementSize[wh];
+ var elOffset = elementOffset[lt];
+ var divide = blockIsCenter ? 2 : 1;
+ var elementCenterOffset = elOffset + (elSize / 2);
+ var viewportCenterOffset = vpOffset + (vpSize / 2);
+ var isInView =
+ elSize <= vpSize
+ && elOffset >= vpOffset
+ && elOffset + elSize <= vpOffset + vpSize;
+
+ if (scrollNever)
+ doNotScroll[xy] = true;
+ else if (!doNotScroll[xy]) {
+ if (blockIsNearest || scrollIfNeeded) {
+ doNotScroll[xy] = scrollIfNeeded ? isInView : false;
+ blockIsEnd = elSize < vpSize ? elementCenterOffset > viewportCenterOffset : elementCenterOffset < viewportCenterOffset;
+ }
+ elementScrollCoordinates[xy] -= blockIsEnd || blockIsCenter ? ((vpSize / divide) - (elSize / divide)) * (isX && _isRTL && normalizeRTL ? -1 : 1) : 0;
+ }
+ };
+ finalizeBlock(true);
+ finalizeBlock(false);
+ }
+
+ if (doNotScroll.y)
+ delete elementScrollCoordinates.y;
+ if (doNotScroll.x)
+ delete elementScrollCoordinates.x;
+
+ coordinates = elementScrollCoordinates;
+ }
+ }
+
+ finalScroll[_strScrollLeft] = getFinalScroll(true, getRawScroll(true, coordinates));
+ finalScroll[_strScrollTop] = getFinalScroll(false, getRawScroll(false, coordinates));
+ doScrollLeft = finalScroll[_strScrollLeft] !== undefined;
+ doScrollTop = finalScroll[_strScrollTop] !== undefined;
+
+ if ((doScrollLeft || doScrollTop) && (duration > 0 || durationIsObject)) {
+ if (durationIsObject) {
+ duration.complete = proxyCompleteCallback;
+ _viewportElement.animate(finalScroll, duration);
+ }
+ else {
+ animationOptions = {
+ duration: duration,
+ complete: proxyCompleteCallback
+ };
+ if (type(easing) == TYPES.a || FRAMEWORK.isPlainObject(easing)) {
+ specialEasing[_strScrollLeft] = easing[0] || easing.x;
+ specialEasing[_strScrollTop] = easing[1] || easing.y;
+ animationOptions.specialEasing = specialEasing;
+ }
+ else {
+ animationOptions.easing = easing;
+ }
+ _viewportElement.animate(finalScroll, animationOptions);
+ }
+ }
+ else {
+ if (doScrollLeft)
+ _viewportElement[_strScrollLeft](finalScroll[_strScrollLeft]);
+ if (doScrollTop)
+ _viewportElement[_strScrollTop](finalScroll[_strScrollTop]);
+ updateScrollbarInfos();
+ }
+ };
+
+ /**
+ * Stops all scroll animations.
+ * @returns {*} The current OverlayScrollbars instance (for chaining).
+ */
+ _base.scrollStop = function (param1, param2, param3) {
+ _viewportElement.stop(param1, param2, param3);
+ return _base;
+ };
+
+ /**
+ * Returns all relevant elements.
+ * @param elementName The name of the element which shall be returned.
+ * @returns {{target: *, host: *, padding: *, viewport: *, content: *, scrollbarHorizontal: {scrollbar: *, track: *, handle: *}, scrollbarVertical: {scrollbar: *, track: *, handle: *}, scrollbarCorner: *} | *}
+ */
+ _base.getElements = function (elementName) {
+ var obj = {
+ target: _targetElementNative,
+ host: _hostElementNative,
+ padding: _paddingElementNative,
+ viewport: _viewportElementNative,
+ content: _contentElementNative,
+ scrollbarHorizontal: {
+ scrollbar: _scrollbarHorizontalElement[0],
+ track: _scrollbarHorizontalTrackElement[0],
+ handle: _scrollbarHorizontalHandleElement[0]
+ },
+ scrollbarVertical: {
+ scrollbar: _scrollbarVerticalElement[0],
+ track: _scrollbarVerticalTrackElement[0],
+ handle: _scrollbarVerticalHandleElement[0]
+ },
+ scrollbarCorner: _scrollbarCornerElement[0]
+ };
+ return type(elementName) == TYPES.s ? getObjectPropVal(obj, elementName) : obj;
+ };
+
+ /**
+ * Returns a object which describes the current state of this instance.
+ * @param stateProperty A specific property from the state object which shall be returned.
+ * @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *}
+ */
+ _base.getState = function (stateProperty) {
+ function prepare(obj) {
+ if (!FRAMEWORK.isPlainObject(obj))
+ return obj;
+ var extended = extendDeep({}, obj);
+ var changePropertyName = function (from, to) {
+ if (extended[LEXICON.hOP](from)) {
+ extended[to] = extended[from];
+ delete extended[from];
+ }
+ };
+ changePropertyName('w', _strWidth); //change w to width
+ changePropertyName('h', _strHeight); //change h to height
+ delete extended.c; //delete c (the 'changed' prop)
+ return extended;
+ };
+ var obj = {
+ destroyed: !!prepare(_destroyed),
+ sleeping: !!prepare(_sleeping),
+ autoUpdate: prepare(!_mutationObserversConnected),
+ widthAuto: prepare(_widthAutoCache),
+ heightAuto: prepare(_heightAutoCache),
+ padding: prepare(_cssPaddingCache),
+ overflowAmount: prepare(_overflowAmountCache),
+ hideOverflow: prepare(_hideOverflowCache),
+ hasOverflow: prepare(_hasOverflowCache),
+ contentScrollSize: prepare(_contentScrollSizeCache),
+ viewportSize: prepare(_viewportSize),
+ hostSize: prepare(_hostSizeCache),
+ documentMixed: prepare(_documentMixed)
+ };
+ return type(stateProperty) == TYPES.s ? getObjectPropVal(obj, stateProperty) : obj;
+ };
+
+ /**
+ * Gets all or specific extension instance.
+ * @param extName The name of the extension from which the instance shall be got.
+ * @returns {{}} The instance of the extension with the given name or undefined if the instance couldn't be found.
+ */
+ _base.ext = function (extName) {
+ var result;
+ var privateMethods = _extensionsPrivateMethods.split(' ');
+ var i = 0;
+ if (type(extName) == TYPES.s) {
+ if (_extensions[LEXICON.hOP](extName)) {
+ result = extendDeep({}, _extensions[extName]);
+ for (; i < privateMethods.length; i++)
+ delete result[privateMethods[i]];
+ }
+ }
+ else {
+ result = {};
+ for (i in _extensions)
+ result[i] = extendDeep({}, _base.ext(i));
+ }
+ return result;
+ };
+
+ /**
+ * Adds a extension to this instance.
+ * @param extName The name of the extension which shall be added.
+ * @param extensionOptions The extension options which shall be used.
+ * @returns {{}} The instance of the added extension or undefined if the extension couldn't be added properly.
+ */
+ _base.addExt = function (extName, extensionOptions) {
+ var registeredExtensionObj = _plugin.extension(extName);
+ var instance;
+ var instanceAdded;
+ var instanceContract;
+ var contractResult;
+ var contractFulfilled = true;
+ if (registeredExtensionObj) {
+ if (!_extensions[LEXICON.hOP](extName)) {
+ instance = registeredExtensionObj.extensionFactory.call(_base,
+ extendDeep({}, registeredExtensionObj.defaultOptions),
+ FRAMEWORK,
+ COMPATIBILITY);
+
+ if (instance) {
+ instanceContract = instance.contract;
+ if (type(instanceContract) == TYPES.f) {
+ contractResult = instanceContract(window);
+ contractFulfilled = type(contractResult) == TYPES.b ? contractResult : contractFulfilled;
+ }
+ if (contractFulfilled) {
+ _extensions[extName] = instance;
+ instanceAdded = instance.added;
+ if (type(instanceAdded) == TYPES.f)
+ instanceAdded(extensionOptions);
+
+ return _base.ext(extName);
+ }
+ }
+ }
+ else
+ return _base.ext(extName);
+ }
+ else
+ console.warn("A extension with the name \"" + extName + "\" isn't registered.");
+ };
+
+ /**
+ * Removes a extension from this instance.
+ * @param extName The name of the extension which shall be removed.
+ * @returns {boolean} True if the extension was removed, false otherwise e.g. if the extension wasn't added before.
+ */
+ _base.removeExt = function (extName) {
+ var instance = _extensions[extName];
+ var instanceRemoved;
+ if (instance) {
+ delete _extensions[extName];
+
+ instanceRemoved = instance.removed;
+ if (type(instanceRemoved) == TYPES.f)
+ instanceRemoved();
+
+ return true;
+ }
+ return false;
+ };
+
+ /**
+ * Constructs the plugin.
+ * @param targetElement The element to which the plugin shall be applied.
+ * @param options The initial options of the plugin.
+ * @param extensions The extension(s) which shall be added right after the initialization.
+ * @returns {boolean} True if the plugin was successfully initialized, false otherwise.
+ */
+ function construct(targetElement, options, extensions) {
+ _defaultOptions = globals.defaultOptions;
+ _nativeScrollbarStyling = globals.nativeScrollbarStyling;
+ _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
+ _nativeScrollbarIsOverlaid = extendDeep({}, globals.nativeScrollbarIsOverlaid);
+ _overlayScrollbarDummySize = extendDeep({}, globals.overlayScrollbarDummySize);
+ _rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior);
+
+ //parse & set options but don't update
+ setOptions(extendDeep({}, _defaultOptions, options));
+
+ _cssCalc = globals.cssCalc;
+ _msieVersion = globals.msie;
+ _autoUpdateRecommended = globals.autoUpdateRecommended;
+ _supportTransition = globals.supportTransition;
+ _supportTransform = globals.supportTransform;
+ _supportPassiveEvents = globals.supportPassiveEvents;
+ _supportResizeObserver = globals.supportResizeObserver;
+ _supportMutationObserver = globals.supportMutationObserver;
+ _restrictedMeasuring = globals.restrictedMeasuring;
+ _documentElement = FRAMEWORK(targetElement.ownerDocument);
+ _documentElementNative = _documentElement[0];
+ _windowElement = FRAMEWORK(_documentElementNative.defaultView || _documentElementNative.parentWindow);
+ _windowElementNative = _windowElement[0];
+ _htmlElement = findFirst(_documentElement, 'html');
+ _bodyElement = findFirst(_htmlElement, 'body');
+ _targetElement = FRAMEWORK(targetElement);
+ _targetElementNative = _targetElement[0];
+ _isTextarea = _targetElement.is('textarea');
+ _isBody = _targetElement.is('body');
+ _documentMixed = _documentElementNative !== document;
+
+ /* On a div Element The if checks only whether:
+ * - the targetElement has the class "os-host"
+ * - the targetElement has a a child with the class "os-padding"
+ *
+ * If that's the case, its assumed the DOM has already the following structure:
+ * (The ".os-host" element is the targetElement)
+ *
+ *
+ *
+ * =====================================================================================
+ *
+ * On a Textarea Element The if checks only whether:
+ * - the targetElement has the class "os-textarea"
+ * - the targetElement is inside a element with the class "os-content"
+ *
+ * If that's the case, its assumed the DOM has already the following structure:
+ * (The ".os-textarea" (textarea) element is the targetElement)
+ *
+ *
+ */
+ _domExists = _isTextarea
+ ? _targetElement.hasClass(_classNameTextareaElement) && _targetElement.parent().hasClass(_classNameContentElement)
+ : _targetElement.hasClass(_classNameHostElement) && _targetElement.children(_strDot + _classNamePaddingElement)[LEXICON.l];
+
+ var initBodyScroll;
+ var bodyMouseTouchDownListener;
+
+ //check if the plugin hasn't to be initialized
+ if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) {
+ dispatchCallback('onInitializationWithdrawn');
+ if (_domExists) {
+ setupStructureDOM(true);
+ setupScrollbarsDOM(true);
+ setupScrollbarCornerDOM(true);
+ }
+
+ _destroyed = true;
+ _sleeping = true;
+
+ return _base;
+ }
+
+ if (_isBody) {
+ initBodyScroll = {};
+ initBodyScroll.l = MATH.max(_targetElement[_strScrollLeft](), _htmlElement[_strScrollLeft](), _windowElement[_strScrollLeft]());
+ initBodyScroll.t = MATH.max(_targetElement[_strScrollTop](), _htmlElement[_strScrollTop](), _windowElement[_strScrollTop]());
+
+ bodyMouseTouchDownListener = function () {
+ _viewportElement.removeAttr(LEXICON.ti);
+ setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, true, true);
+ }
+ }
+
+ //build OverlayScrollbars DOM
+ setupStructureDOM();
+ setupScrollbarsDOM();
+ setupScrollbarCornerDOM();
+
+ //create OverlayScrollbars events
+ setupStructureEvents();
+ setupScrollbarEvents(true);
+ setupScrollbarEvents(false);
+ setupScrollbarCornerEvents();
+
+ //create mutation observers
+ createMutationObservers();
+
+ //build resize observer for the host element
+ setupResizeObserver(_sizeObserverElement, hostOnResized);
+
+ if (_isBody) {
+ //apply the body scroll to handle it right in the update method
+ _viewportElement[_strScrollLeft](initBodyScroll.l)[_strScrollTop](initBodyScroll.t);
+
+ //set the focus on the viewport element so you dont have to click on the page to use keyboard keys (up / down / space) for scrolling
+ if (document.activeElement == targetElement && _viewportElementNative.focus) {
+ //set a tabindex to make the viewportElement focusable
+ _viewportElement.attr(LEXICON.ti, '-1');
+ _viewportElementNative.focus();
+
+ /* the tabindex has to be removed due to;
+ * If you set the tabindex attribute on an
, then its child content cannot be scrolled with the arrow keys unless you set tabindex on the content, too
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
+ */
+ setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, false, true);
+ }
+ }
+
+ //update for the first time & initialize cache
+ _base.update(_strAuto);
+
+ //the plugin is initialized now!
+ _initialized = true;
+ dispatchCallback('onInitialized');
+
+ //call all callbacks which would fire before the initialized was complete
+ each(_callbacksInitQeueue, function (index, value) { dispatchCallback(value.n, value.a); });
+ _callbacksInitQeueue = [];
+
+ //add extensions
+ if (type(extensions) == TYPES.s)
+ extensions = [extensions];
+ if (COMPATIBILITY.isA(extensions))
+ each(extensions, function (index, value) { _base.addExt(value); });
+ else if (FRAMEWORK.isPlainObject(extensions))
+ each(extensions, function (key, value) { _base.addExt(key, value); });
+
+ //add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions)
+ setTimeout(function () {
+ if (_supportTransition && !_destroyed)
+ addClass(_hostElement, _classNameHostTransition);
+ }, 333);
+
+ return _base;
+ }
+
+ if (_plugin.valid(construct(pluginTargetElement, options, extensions))) {
+ INSTANCES(pluginTargetElement, _base);
+ }
+
+ return _base;
+ }
+
+ /**
+ * Initializes a new OverlayScrollbarsInstance object or changes options if already initialized or returns the current instance.
+ * @param pluginTargetElements The elements to which the Plugin shall be initialized.
+ * @param options The custom options with which the plugin shall be initialized.
+ * @param extensions The extension(s) which shall be added right after initialization.
+ * @returns {*}
+ */
+ _plugin = window[PLUGINNAME] = function (pluginTargetElements, options, extensions) {
+ if (arguments[LEXICON.l] === 0)
+ return this;
+
+ var arr = [];
+ var optsIsPlainObj = FRAMEWORK.isPlainObject(options);
+ var inst;
+ var result;
+
+ //pluginTargetElements is null or undefined
+ if (!pluginTargetElements)
+ return optsIsPlainObj || !options ? result : arr;
+
+ /*
+ pluginTargetElements will be converted to:
+ 1. A jQueryElement Array
+ 2. A HTMLElement Array
+ 3. A Array with a single HTML Element
+ so pluginTargetElements is always a array.
+ */
+ pluginTargetElements = pluginTargetElements[LEXICON.l] != undefined ? pluginTargetElements : [pluginTargetElements[0] || pluginTargetElements];
+ initOverlayScrollbarsStatics();
+
+ if (pluginTargetElements[LEXICON.l] > 0) {
+ if (optsIsPlainObj) {
+ FRAMEWORK.each(pluginTargetElements, function (i, v) {
+ inst = v;
+ if (inst !== undefined)
+ arr.push(OverlayScrollbarsInstance(inst, options, extensions, _pluginsGlobals, _pluginsAutoUpdateLoop));
+ });
+ }
+ else {
+ FRAMEWORK.each(pluginTargetElements, function (i, v) {
+ inst = INSTANCES(v);
+ if ((options === '!' && _plugin.valid(inst)) || (COMPATIBILITY.type(options) == TYPES.f && options(v, inst)))
+ arr.push(inst);
+ else if (options === undefined)
+ arr.push(inst);
+ });
+ }
+ result = arr[LEXICON.l] === 1 ? arr[0] : arr;
+ }
+ return result;
+ };
+
+ /**
+ * Returns a object which contains global information about the plugin and each instance of it.
+ * The returned object is just a copy, that means that changes to the returned object won't have any effect to the original object.
+ */
+ _plugin.globals = function () {
+ initOverlayScrollbarsStatics();
+ var globals = FRAMEWORK.extend(true, {}, _pluginsGlobals);
+ delete globals['msie'];
+ return globals;
+ };
+
+ /**
+ * Gets or Sets the default options for each new plugin initialization.
+ * @param newDefaultOptions The object with which the default options shall be extended.
+ */
+ _plugin.defaultOptions = function (newDefaultOptions) {
+ initOverlayScrollbarsStatics();
+ var currDefaultOptions = _pluginsGlobals.defaultOptions;
+ if (newDefaultOptions === undefined)
+ return FRAMEWORK.extend(true, {}, currDefaultOptions);
+
+ //set the new default options
+ _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, {}, currDefaultOptions, _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true, currDefaultOptions)._default);
+ };
+
+ /**
+ * Checks whether the passed instance is a non-destroyed OverlayScrollbars instance.
+ * @param osInstance The potential OverlayScrollbars instance which shall be checked.
+ * @returns {boolean} True if the passed value is a non-destroyed OverlayScrollbars instance, false otherwise.
+ */
+ _plugin.valid = function (osInstance) {
+ return osInstance instanceof _plugin && !osInstance.getState().destroyed;
+ };
+
+ /**
+ * Registers, Unregisters or returns a extension.
+ * Register: Pass the name and the extension. (defaultOptions is optional)
+ * Unregister: Pass the name and anything except a function as extension parameter.
+ * Get extension: Pass the name of the extension which shall be got.
+ * Get all extensions: Pass no arguments.
+ * @param extensionName The name of the extension which shall be registered, unregistered or returned.
+ * @param extension A function which generates the instance of the extension or anything other to remove a already registered extension.
+ * @param defaultOptions The default options which shall be used for the registered extension.
+ */
+ _plugin.extension = function (extensionName, extension, defaultOptions) {
+ var extNameTypeString = COMPATIBILITY.type(extensionName) == TYPES.s;
+ var argLen = arguments[LEXICON.l];
+ var i = 0;
+ if (argLen < 1 || !extNameTypeString) {
+ //return a copy of all extension objects
+ return FRAMEWORK.extend(true, { length: _pluginsExtensions[LEXICON.l] }, _pluginsExtensions);
+ }
+ else if (extNameTypeString) {
+ if (COMPATIBILITY.type(extension) == TYPES.f) {
+ //register extension
+ _pluginsExtensions.push({
+ name: extensionName,
+ extensionFactory: extension,
+ defaultOptions: defaultOptions
+ });
+ }
+ else {
+ for (; i < _pluginsExtensions[LEXICON.l]; i++) {
+ if (_pluginsExtensions[i].name === extensionName) {
+ if (argLen > 1)
+ _pluginsExtensions.splice(i, 1); //remove extension
+ else
+ return FRAMEWORK.extend(true, {}, _pluginsExtensions[i]); //return extension with the given name
+ }
+ }
+ }
+ }
+ };
+
+ return _plugin;
+ })();
+
+ if (JQUERY && JQUERY.fn) {
+ /**
+ * The jQuery initialization interface.
+ * @param options The initial options for the construction of the plugin. To initialize the plugin, this option has to be a object! If it isn't a object, the instance(s) are returned and the plugin wont be initialized.
+ * @param extensions The extension(s) which shall be added right after initialization.
+ * @returns {*} After initialization it returns the jQuery element array, else it returns the instance(s) of the elements which are selected.
+ */
+ JQUERY.fn.overlayScrollbars = function (options, extensions) {
+ var _elements = this;
+ if (JQUERY.isPlainObject(options)) {
+ JQUERY.each(_elements, function () { PLUGIN(this, options, extensions); });
+ return _elements;
+ }
+ else
+ return PLUGIN(_elements, options);
+ };
+ }
+ return PLUGIN;
+ }
));
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/af.js b/plugins/select2/js/i18n/af.js
index 60a2ef329..32e5ac7de 100644
--- a/plugins/select2/js/i18n/af.js
+++ b/plugins/select2/js/i18n/af.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/af",[],function(){return{errorLoading:function(){return"Die resultate kon nie gelaai word nie."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Verwyders asseblief "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Voer asseblief "+(e.minimum-e.input.length)+" of meer karakters"},loadingMore:function(){return"Meer resultate word gelaai…"},maximumSelected:function(e){var n="Kies asseblief net "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"Geen resultate gevind"},searching:function(){return"Besig…"},removeAllItems:function(){return"Verwyder alle items"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/ar.js b/plugins/select2/js/i18n/ar.js
index 5866da06a..64e1caad3 100644
--- a/plugins/select2/js/i18n/ar.js
+++ b/plugins/select2/js/i18n/ar.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(n){return"الرجاء حذف "+(n.input.length-n.maximum)+" عناصر"},inputTooShort:function(n){return"الرجاء إضافة "+(n.minimum-n.input.length)+" عناصر"},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(n){return"تستطيع إختيار "+n.maximum+" بنود فقط"},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"},removeAllItems:function(){return"قم بإزالة كل العناصر"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/az.js b/plugins/select2/js/i18n/az.js
index f15047a50..1d52c260f 100644
--- a/plugins/select2/js/i18n/az.js
+++ b/plugins/select2/js/i18n/az.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/az",[],function(){return{inputTooLong:function(n){return n.input.length-n.maximum+" simvol silin"},inputTooShort:function(n){return n.minimum-n.input.length+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(n){return"Sadəcə "+n.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"},removeAllItems:function(){return"Bütün elementləri sil"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/bg.js b/plugins/select2/js/i18n/bg.js
index ad8915ee4..73b730a70 100644
--- a/plugins/select2/js/i18n/bg.js
+++ b/plugins/select2/js/i18n/bg.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bg",[],function(){return{inputTooLong:function(n){var e=n.input.length-n.maximum,u="Моля въведете с "+e+" по-малко символ";return e>1&&(u+="a"),u},inputTooShort:function(n){var e=n.minimum-n.input.length,u="Моля въведете още "+e+" символ";return e>1&&(u+="a"),u},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(n){var e="Можете да направите до "+n.maximum+" ";return n.maximum>1?e+="избора":e+="избор",e},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"},removeAllItems:function(){return"Премахнете всички елементи"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/bn.js b/plugins/select2/js/i18n/bn.js
index e2a3926a9..2d17b9d8e 100644
--- a/plugins/select2/js/i18n/bn.js
+++ b/plugins/select2/js/i18n/bn.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bn",[],function(){return{errorLoading:function(){return"ফলাফলগুলি লোড করা যায়নি।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।";return 1!=e&&(u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।"),u},inputTooShort:function(n){return n.minimum-n.input.length+" টি অক্ষর অথবা অধিক অক্ষর লিখুন।"},loadingMore:function(){return"আরো ফলাফল লোড হচ্ছে ..."},maximumSelected:function(n){var e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।";return 1!=n.maximum&&(e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।"),e},noResults:function(){return"কোন ফলাফল পাওয়া যায়নি।"},searching:function(){return"অনুসন্ধান করা হচ্ছে ..."}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/bs.js b/plugins/select2/js/i18n/bs.js
index 89a88988f..46b084d75 100644
--- a/plugins/select2/js/i18n/bs.js
+++ b/plugins/select2/js/i18n/bs.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/bs",[],function(){function e(e,n,r,t){return e%10==1&&e%100!=11?n:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspijelo."},inputTooLong:function(n){var r=n.input.length-n.maximum,t="Obrišite "+r+" simbol";return t+=e(r,"","a","a")},inputTooShort:function(n){var r=n.minimum-n.input.length,t="Ukucajte bar još "+r+" simbol";return t+=e(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(n){var r="Možete izabrati samo "+n.maximum+" stavk";return r+=e(n.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Uklonite sve stavke"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/ca.js b/plugins/select2/js/i18n/ca.js
index 9e9e5ab97..82dbbb7a2 100644
--- a/plugins/select2/js/i18n/ca.js
+++ b/plugins/select2/js/i18n/ca.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Si us plau, elimina "+n+" car";return r+=1==n?"àcter":"àcters"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Si us plau, introdueix "+n+" car";return r+=1==n?"àcter":"àcters"},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var n="Només es pot seleccionar "+e.maximum+" element";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"},removeAllItems:function(){return"Treu tots els elements"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/cs.js b/plugins/select2/js/i18n/cs.js
index 3b05cec10..7116d6c1d 100644
--- a/plugins/select2/js/i18n/cs.js
+++ b/plugins/select2/js/i18n/cs.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/cs",[],function(){function e(e,n){switch(e){case 2:return n?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadejte o jeden znak méně.":t<=4?"Prosím, zadejte o "+e(t,!0)+" znaky méně.":"Prosím, zadejte o "+t+" znaků méně."},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadejte ještě jeden znak.":t<=4?"Prosím, zadejte ještě další "+e(t,!0)+" znaky.":"Prosím, zadejte ještě dalších "+t+" znaků."},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(n){var t=n.maximum;return 1==t?"Můžete zvolit jen jednu položku.":t<=4?"Můžete zvolit maximálně "+e(t,!1)+" položky.":"Můžete zvolit maximálně "+t+" položek."},noResults:function(){return"Nenalezeny žádné položky."},searching:function(){return"Vyhledávání…"},removeAllItems:function(){return"Odstraňte všechny položky"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/da.js b/plugins/select2/js/i18n/da.js
index cfa74f485..cda32c34a 100644
--- a/plugins/select2/js/i18n/da.js
+++ b/plugins/select2/js/i18n/da.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){return"Angiv venligst "+(e.input.length-e.maximum)+" tegn mindre"},inputTooShort:function(e){return"Angiv venligst "+(e.minimum-e.input.length)+" tegn mere"},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var n="Du kan kun vælge "+e.maximum+" emne";return 1!=e.maximum&&(n+="r"),n},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/de.js b/plugins/select2/js/i18n/de.js
index 57e210f81..c2e61e580 100644
--- a/plugins/select2/js/i18n/de.js
+++ b/plugins/select2/js/i18n/de.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/de",[],function(){return{errorLoading:function(){return"Die Ergebnisse konnten nicht geladen werden."},inputTooLong:function(e){return"Bitte "+(e.input.length-e.maximum)+" Zeichen weniger eingeben"},inputTooShort:function(e){return"Bitte "+(e.minimum-e.input.length)+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var n="Sie können nur "+e.maximum+" Element";return 1!=e.maximum&&(n+="e"),n+=" auswählen"},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"},removeAllItems:function(){return"Entferne alle Elemente"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/dsb.js b/plugins/select2/js/i18n/dsb.js
index 7bee0a002..02f283aba 100644
--- a/plugins/select2/js/i18n/dsb.js
+++ b/plugins/select2/js/i18n/dsb.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/dsb",[],function(){var n=["znamuško","znamušce","znamuška","znamuškow"],e=["zapisk","zapiska","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njejsu se dali zacytaś."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Pšosym lašuj "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Pšosym zapódaj nanejmjenjej "+a+" "+u(a,n)},loadingMore:function(){return"Dalšne wuslědki se zacytaju…"},maximumSelected:function(n){return"Móžoš jano "+n.maximum+" "+u(n.maximum,e)+"wubraś."},noResults:function(){return"Žedne wuslědki namakane"},searching:function(){return"Pyta se…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/el.js b/plugins/select2/js/i18n/el.js
index d345ab213..d4922a1df 100644
--- a/plugins/select2/js/i18n/el.js
+++ b/plugins/select2/js/i18n/el.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(n){var e=n.input.length-n.maximum,u="Παρακαλώ διαγράψτε "+e+" χαρακτήρ";return 1==e&&(u+="α"),1!=e&&(u+="ες"),u},inputTooShort:function(n){return"Παρακαλώ συμπληρώστε "+(n.minimum-n.input.length)+" ή περισσότερους χαρακτήρες"},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(n){var e="Μπορείτε να επιλέξετε μόνο "+n.maximum+" επιλογ";return 1==n.maximum&&(e+="ή"),1!=n.maximum&&(e+="ές"),e},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"},removeAllItems:function(){return"Καταργήστε όλα τα στοιχεία"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/en.js b/plugins/select2/js/i18n/en.js
index 5b99c9668..3b1928573 100644
--- a/plugins/select2/js/i18n/en.js
+++ b/plugins/select2/js/i18n/en.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Please delete "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Please enter "+(e.minimum-e.input.length)+" or more characters"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var n="You can only select "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No results found"},searching:function(){return"Searching…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/es.js b/plugins/select2/js/i18n/es.js
index 2354519b8..68afd6d25 100644
--- a/plugins/select2/js/i18n/es.js
+++ b/plugins/select2/js/i18n/es.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"No se pudieron cargar los resultados"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Por favor, elimine "+n+" car";return r+=1==n?"ácter":"acteres"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Por favor, introduzca "+n+" car";return r+=1==n?"ácter":"acteres"},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var n="Sólo puede seleccionar "+e.maximum+" elemento";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Eliminar todos los elementos"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/et.js b/plugins/select2/js/i18n/et.js
index af186735b..070b61a26 100644
--- a/plugins/select2/js/i18n/et.js
+++ b/plugins/select2/js/i18n/et.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var n=e.input.length-e.maximum,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" vähem"},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" rohkem"},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var n="Saad vaid "+e.maximum+" tulemus";return 1==e.maximum?n+="e":n+="t",n+=" valida"},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"},removeAllItems:function(){return"Eemalda kõik esemed"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/eu.js b/plugins/select2/js/i18n/eu.js
index 96751ad4b..90d5e73f8 100644
--- a/plugins/select2/js/i18n/eu.js
+++ b/plugins/select2/js/i18n/eu.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gutxiago"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gehiago"},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return 1===e.maximum?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"},removeAllItems:function(){return"Kendu elementu guztiak"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/fa.js b/plugins/select2/js/i18n/fa.js
index 0180ad1b7..e1ffdbed0 100644
--- a/plugins/select2/js/i18n/fa.js
+++ b/plugins/select2/js/i18n/fa.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(n){return"لطفاً "+(n.input.length-n.maximum)+" کاراکتر را حذف نمایید"},inputTooShort:function(n){return"لطفاً تعداد "+(n.minimum-n.input.length)+" کاراکتر یا بیشتر وارد نمایید"},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(n){return"شما تنها میتوانید "+n.maximum+" آیتم را انتخاب نمایید"},noResults:function(){return"هیچ نتیجهای یافت نشد"},searching:function(){return"در حال جستجو..."},removeAllItems:function(){return"همه موارد را حذف کنید"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/fi.js b/plugins/select2/js/i18n/fi.js
index 630144e10..ffed1247d 100644
--- a/plugins/select2/js/i18n/fi.js
+++ b/plugins/select2/js/i18n/fi.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fi",[],function(){return{errorLoading:function(){return"Tuloksia ei saatu ladattua."},inputTooLong:function(n){return"Ole hyvä ja anna "+(n.input.length-n.maximum)+" merkkiä vähemmän"},inputTooShort:function(n){return"Ole hyvä ja anna "+(n.minimum-n.input.length)+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(n){return"Voit valita ainoastaan "+n.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){return"Haetaan…"},removeAllItems:function(){return"Poista kaikki kohteet"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/fr.js b/plugins/select2/js/i18n/fr.js
index 5c7c285f9..dd02f973f 100644
--- a/plugins/select2/js/i18n/fr.js
+++ b/plugins/select2/js/i18n/fr.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var n=e.input.length-e.maximum;return"Supprimez "+n+" caractère"+(n>1?"s":"")},inputTooShort:function(e){var n=e.minimum-e.input.length;return"Saisissez au moins "+n+" caractère"+(n>1?"s":"")},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){return"Vous pouvez seulement sélectionner "+e.maximum+" élément"+(e.maximum>1?"s":"")},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"},removeAllItems:function(){return"Supprimer tous les éléments"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/gl.js b/plugins/select2/js/i18n/gl.js
index 6a78d84c9..208a00570 100644
--- a/plugins/select2/js/i18n/gl.js
+++ b/plugins/select2/js/i18n/gl.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/gl",[],function(){return{errorLoading:function(){return"Non foi posíbel cargar os resultados."},inputTooLong:function(e){var n=e.input.length-e.maximum;return 1===n?"Elimine un carácter":"Elimine "+n+" caracteres"},inputTooShort:function(e){var n=e.minimum-e.input.length;return 1===n?"Engada un carácter":"Engada "+n+" caracteres"},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){return 1===e.maximum?"Só pode seleccionar un elemento":"Só pode seleccionar "+e.maximum+" elementos"},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Elimina todos os elementos"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/he.js b/plugins/select2/js/i18n/he.js
index 2904dd221..25a8805aa 100644
--- a/plugins/select2/js/i18n/he.js
+++ b/plugins/select2/js/i18n/he.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="נא למחוק ";return r+=1===e?"תו אחד":e+" תווים"},inputTooShort:function(n){var e=n.minimum-n.input.length,r="נא להכניס ";return r+=1===e?"תו אחד":e+" תווים",r+=" או יותר"},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(n){var e="באפשרותך לבחור עד ";return 1===n.maximum?e+="פריט אחד":e+=n.maximum+" פריטים",e},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"},removeAllItems:function(){return"הסר את כל הפריטים"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/hi.js b/plugins/select2/js/i18n/hi.js
index 9428c29cf..f3ed79843 100644
--- a/plugins/select2/js/i18n/hi.js
+++ b/plugins/select2/js/i18n/hi.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(n){var e=n.input.length-n.maximum,r=e+" अक्षर को हटा दें";return e>1&&(r=e+" अक्षरों को हटा दें "),r},inputTooShort:function(n){return"कृपया "+(n.minimum-n.input.length)+" या अधिक अक्षर दर्ज करें"},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(n){return"आप केवल "+n.maximum+" आइटम का चयन कर सकते हैं"},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."},removeAllItems:function(){return"सभी वस्तुओं को हटा दें"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/hr.js b/plugins/select2/js/i18n/hr.js
index 3a5ede48f..cb3268db1 100644
--- a/plugins/select2/js/i18n/hr.js
+++ b/plugins/select2/js/i18n/hr.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hr",[],function(){function n(n){var e=" "+n+" znak";return n%10<5&&n%10>0&&(n%100<5||n%100>19)?n%10>1&&(e+="a"):e+="ova",e}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(e){return"Unesite "+n(e.input.length-e.maximum)},inputTooShort:function(e){return"Unesite još "+n(e.minimum-e.input.length)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(n){return"Maksimalan broj odabranih stavki je "+n.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Ukloni sve stavke"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/hsb.js b/plugins/select2/js/i18n/hsb.js
index 160318e8e..3d5bf09db 100644
--- a/plugins/select2/js/i18n/hsb.js
+++ b/plugins/select2/js/i18n/hsb.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hsb",[],function(){var n=["znamješko","znamješce","znamješka","znamješkow"],e=["zapisk","zapiskaj","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njedachu so začitać."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Prošu zhašej "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Prošu zapodaj znajmjeńša "+a+" "+u(a,n)},loadingMore:function(){return"Dalše wuslědki so začitaja…"},maximumSelected:function(n){return"Móžeš jenož "+n.maximum+" "+u(n.maximum,e)+"wubrać"},noResults:function(){return"Žane wuslědki namakane"},searching:function(){return"Pyta so…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/hu.js b/plugins/select2/js/i18n/hu.js
index 73debe098..4893aa2f7 100644
--- a/plugins/select2/js/i18n/hu.js
+++ b/plugins/select2/js/i18n/hu.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/hu",[],function(){return{errorLoading:function(){return"Az eredmények betöltése nem sikerült."},inputTooLong:function(e){return"Túl hosszú. "+(e.input.length-e.maximum)+" karakterrel több, mint kellene."},inputTooShort:function(e){return"Túl rövid. Még "+(e.minimum-e.input.length)+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"},removeAllItems:function(){return"Távolítson el minden elemet"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/hy.js b/plugins/select2/js/i18n/hy.js
index d7f11dcd0..823000714 100644
--- a/plugins/select2/js/i18n/hy.js
+++ b/plugins/select2/js/i18n/hy.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hy",[],function(){return{errorLoading:function(){return"Արդյունքները հնարավոր չէ բեռնել։"},inputTooLong:function(n){return"Խնդրում ենք հեռացնել "+(n.input.length-n.maximum)+" նշան"},inputTooShort:function(n){return"Խնդրում ենք մուտքագրել "+(n.minimum-n.input.length)+" կամ ավել նշաններ"},loadingMore:function(){return"Բեռնվում են նոր արդյունքներ․․․"},maximumSelected:function(n){return"Դուք կարող եք ընտրել առավելագույնը "+n.maximum+" կետ"},noResults:function(){return"Արդյունքներ չեն գտնվել"},searching:function(){return"Որոնում․․․"},removeAllItems:function(){return"Հեռացնել բոլոր տարրերը"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/id.js b/plugins/select2/js/i18n/id.js
index f9479b602..4a0b3bf00 100644
--- a/plugins/select2/js/i18n/id.js
+++ b/plugins/select2/js/i18n/id.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(n){return"Hapuskan "+(n.input.length-n.maximum)+" huruf"},inputTooShort:function(n){return"Masukkan "+(n.minimum-n.input.length)+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(n){return"Anda hanya dapat memilih "+n.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Hapus semua item"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/is.js b/plugins/select2/js/i18n/is.js
index b6770703e..cca5bbecf 100644
--- a/plugins/select2/js/i18n/is.js
+++ b/plugins/select2/js/i18n/is.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/is",[],function(){return{inputTooLong:function(n){var t=n.input.length-n.maximum,e="Vinsamlegast styttið texta um "+t+" staf";return t<=1?e:e+"i"},inputTooShort:function(n){var t=n.minimum-n.input.length,e="Vinsamlegast skrifið "+t+" staf";return t>1&&(e+="i"),e+=" í viðbót"},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(n){return"Þú getur aðeins valið "+n.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"},removeAllItems:function(){return"Fjarlægðu öll atriði"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/it.js b/plugins/select2/js/i18n/it.js
index 05f87cf04..507c7d9f2 100644
--- a/plugins/select2/js/i18n/it.js
+++ b/plugins/select2/js/i18n/it.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Per favore cancella "+n+" caratter";return t+=1!==n?"i":"e"},inputTooShort:function(e){return"Per favore inserisci "+(e.minimum-e.input.length)+" o più caratteri"},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var n="Puoi selezionare solo "+e.maximum+" element";return 1!==e.maximum?n+="i":n+="o",n},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"},removeAllItems:function(){return"Rimuovi tutti gli oggetti"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/ja.js b/plugins/select2/js/i18n/ja.js
index 3f546061e..451025e2c 100644
--- a/plugins/select2/js/i18n/ja.js
+++ b/plugins/select2/js/i18n/ja.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(n){return n.input.length-n.maximum+" 文字を削除してください"},inputTooShort:function(n){return"少なくとも "+(n.minimum-n.input.length)+" 文字を入力してください"},loadingMore:function(){return"読み込み中…"},maximumSelected:function(n){return n.maximum+" 件しか選択できません"},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"},removeAllItems:function(){return"すべてのアイテムを削除"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/ka.js b/plugins/select2/js/i18n/ka.js
index 5d3ca4acc..60c593b70 100644
--- a/plugins/select2/js/i18n/ka.js
+++ b/plugins/select2/js/i18n/ka.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ka",[],function(){return{errorLoading:function(){return"მონაცემების ჩატვირთვა შეუძლებელია."},inputTooLong:function(n){return"გთხოვთ აკრიფეთ "+(n.input.length-n.maximum)+" სიმბოლოთი ნაკლები"},inputTooShort:function(n){return"გთხოვთ აკრიფეთ "+(n.minimum-n.input.length)+" სიმბოლო ან მეტი"},loadingMore:function(){return"მონაცემების ჩატვირთვა…"},maximumSelected:function(n){return"თქვენ შეგიძლიათ აირჩიოთ არაუმეტეს "+n.maximum+" ელემენტი"},noResults:function(){return"რეზულტატი არ მოიძებნა"},searching:function(){return"ძიება…"},removeAllItems:function(){return"ამოიღე ყველა ელემენტი"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/km.js b/plugins/select2/js/i18n/km.js
index bd78a0d3e..4dca94f41 100644
--- a/plugins/select2/js/i18n/km.js
+++ b/plugins/select2/js/i18n/km.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(n){return"សូមលុបចេញ "+(n.input.length-n.maximum)+" អក្សរ"},inputTooShort:function(n){return"សូមបញ្ចូល"+(n.minimum-n.input.length)+" អក្សរ រឺ ច្រើនជាងនេះ"},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(n){return"អ្នកអាចជ្រើសរើសបានតែ "+n.maximum+" ជម្រើសប៉ុណ្ណោះ"},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."},removeAllItems:function(){return"លុបធាតុទាំងអស់"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/ko.js b/plugins/select2/js/i18n/ko.js
index 91a470aa6..f2880fb00 100644
--- a/plugins/select2/js/i18n/ko.js
+++ b/plugins/select2/js/i18n/ko.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(n){return"너무 깁니다. "+(n.input.length-n.maximum)+" 글자 지워주세요."},inputTooShort:function(n){return"너무 짧습니다. "+(n.minimum-n.input.length)+" 글자 더 입력해주세요."},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(n){return"최대 "+n.maximum+"개까지만 선택 가능합니다."},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"},removeAllItems:function(){return"모든 항목 삭제"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/lt.js b/plugins/select2/js/i18n/lt.js
index ece6f6927..f6a42155a 100644
--- a/plugins/select2/js/i18n/lt.js
+++ b/plugins/select2/js/i18n/lt.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/lt",[],function(){function n(n,e,i,t){return n%10==1&&(n%100<11||n%100>19)?e:n%10>=2&&n%10<=9&&(n%100<11||n%100>19)?i:t}return{inputTooLong:function(e){var i=e.input.length-e.maximum,t="Pašalinkite "+i+" simbol";return t+=n(i,"į","ius","ių")},inputTooShort:function(e){var i=e.minimum-e.input.length,t="Įrašykite dar "+i+" simbol";return t+=n(i,"į","ius","ių")},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(e){var i="Jūs galite pasirinkti tik "+e.maximum+" element";return i+=n(e.maximum,"ą","us","ų")},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"},removeAllItems:function(){return"Pašalinti visus elementus"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/lv.js b/plugins/select2/js/i18n/lv.js
index 815d799b0..806dc5c43 100644
--- a/plugins/select2/js/i18n/lv.js
+++ b/plugins/select2/js/i18n/lv.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/lv",[],function(){function e(e,n,u,i){return 11===e?n:e%10==1?u:i}return{inputTooLong:function(n){var u=n.input.length-n.maximum,i="Lūdzu ievadiet par "+u;return(i+=" simbol"+e(u,"iem","u","iem"))+" mazāk"},inputTooShort:function(n){var u=n.minimum-n.input.length,i="Lūdzu ievadiet vēl "+u;return i+=" simbol"+e(u,"us","u","us")},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(n){var u="Jūs varat izvēlēties ne vairāk kā "+n.maximum;return u+=" element"+e(n.maximum,"us","u","us")},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"},removeAllItems:function(){return"Noņemt visus vienumus"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/mk.js b/plugins/select2/js/i18n/mk.js
index 79e870e4f..cb7b84a26 100644
--- a/plugins/select2/js/i18n/mk.js
+++ b/plugins/select2/js/i18n/mk.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/mk",[],function(){return{inputTooLong:function(n){var e=(n.input.length,n.maximum,"Ве молиме внесете "+n.maximum+" помалку карактер");return 1!==n.maximum&&(e+="и"),e},inputTooShort:function(n){var e=(n.minimum,n.input.length,"Ве молиме внесете уште "+n.maximum+" карактер");return 1!==n.maximum&&(e+="и"),e},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(n){var e="Можете да изберете само "+n.maximum+" ставк";return 1===n.maximum?e+="а":e+="и",e},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"},removeAllItems:function(){return"Отстрани ги сите предмети"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/ms.js b/plugins/select2/js/i18n/ms.js
index d3feef2b5..6bd7eaa3e 100644
--- a/plugins/select2/js/i18n/ms.js
+++ b/plugins/select2/js/i18n/ms.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(n){return"Sila hapuskan "+(n.input.length-n.maximum)+" aksara"},inputTooShort:function(n){return"Sila masukkan "+(n.minimum-n.input.length)+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(n){return"Anda hanya boleh memilih "+n.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Keluarkan semua item"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/nb.js b/plugins/select2/js/i18n/nb.js
index 953ff21e4..25d89c687 100644
--- a/plugins/select2/js/i18n/nb.js
+++ b/plugins/select2/js/i18n/nb.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){return"Vennligst fjern "+(e.input.length-e.maximum)+" tegn"},inputTooShort:function(e){return"Vennligst skriv inn "+(e.minimum-e.input.length)+" tegn til"},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/ne.js b/plugins/select2/js/i18n/ne.js
index 536fbab84..1c39f6721 100644
--- a/plugins/select2/js/i18n/ne.js
+++ b/plugins/select2/js/i18n/ne.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ne",[],function(){return{errorLoading:function(){return"नतिजाहरु देखाउन सकिएन।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="कृपया "+e+" अक्षर मेटाउनुहोस्।";return 1!=e&&(u+="कृपया "+e+" अक्षरहरु मेटाउनुहोस्।"),u},inputTooShort:function(n){return"कृपया बाँकी रहेका "+(n.minimum-n.input.length)+" वा अरु धेरै अक्षरहरु भर्नुहोस्।"},loadingMore:function(){return"अरु नतिजाहरु भरिँदैछन् …"},maximumSelected:function(n){var e="तँपाई "+n.maximum+" वस्तु मात्र छान्न पाउँनुहुन्छ।";return 1!=n.maximum&&(e="तँपाई "+n.maximum+" वस्तुहरु मात्र छान्न पाउँनुहुन्छ।"),e},noResults:function(){return"कुनै पनि नतिजा भेटिएन।"},searching:function(){return"खोजि हुँदैछ…"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/nl.js b/plugins/select2/js/i18n/nl.js
index 776c2df6a..2b74058d2 100644
--- a/plugins/select2/js/i18n/nl.js
+++ b/plugins/select2/js/i18n/nl.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){return"Gelieve "+(e.input.length-e.maximum)+" karakters te verwijderen"},inputTooShort:function(e){return"Gelieve "+(e.minimum-e.input.length)+" of meer karakters in te voeren"},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var n=1==e.maximum?"kan":"kunnen",r="Er "+n+" maar "+e.maximum+" item";return 1!=e.maximum&&(r+="s"),r+=" worden geselecteerd"},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"},removeAllItems:function(){return"Verwijder alle items"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/pl.js b/plugins/select2/js/i18n/pl.js
index 7790a50c3..4ca5748c3 100644
--- a/plugins/select2/js/i18n/pl.js
+++ b/plugins/select2/js/i18n/pl.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/pl",[],function(){var n=["znak","znaki","znaków"],e=["element","elementy","elementów"],r=function(n,e){return 1===n?e[0]:n>1&&n<=4?e[1]:n>=5?e[2]:void 0};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Usuń "+t+" "+r(t,n)},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Podaj przynajmniej "+t+" "+r(t,n)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(n){return"Możesz zaznaczyć tylko "+n.maximum+" "+r(n.maximum,e)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"},removeAllItems:function(){return"Usuń wszystkie przedmioty"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/ps.js b/plugins/select2/js/i18n/ps.js
index 9d2cd8ca9..9b008e4c1 100644
--- a/plugins/select2/js/i18n/ps.js
+++ b/plugins/select2/js/i18n/ps.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ps",[],function(){return{errorLoading:function(){return"پايلي نه سي ترلاسه کېدای"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="د مهربانۍ لمخي "+e+" توری ړنګ کړئ";return 1!=e&&(r=r.replace("توری","توري")),r},inputTooShort:function(n){return"لږ تر لږه "+(n.minimum-n.input.length)+" يا ډېر توري وليکئ"},loadingMore:function(){return"نوري پايلي ترلاسه کيږي..."},maximumSelected:function(n){var e="تاسو يوازي "+n.maximum+" قلم په نښه کولای سی";return 1!=n.maximum&&(e=e.replace("قلم","قلمونه")),e},noResults:function(){return"پايلي و نه موندل سوې"},searching:function(){return"لټول کيږي..."},removeAllItems:function(){return"ټول توکي لرې کړئ"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/pt-BR.js b/plugins/select2/js/i18n/pt-BR.js
index f26c8133f..c991e2550 100644
--- a/plugins/select2/js/i18n/pt-BR.js
+++ b/plugins/select2/js/i18n/pt-BR.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Apague "+n+" caracter";return 1!=n&&(r+="es"),r},inputTooShort:function(e){return"Digite "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var n="Você só pode selecionar "+e.maximum+" ite";return 1==e.maximum?n+="m":n+="ns",n},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/pt.js b/plugins/select2/js/i18n/pt.js
index 2068a7c28..b5da1a6b4 100644
--- a/plugins/select2/js/i18n/pt.js
+++ b/plugins/select2/js/i18n/pt.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var r=e.input.length-e.maximum,n="Por favor apague "+r+" ";return n+=1!=r?"caracteres":"caractere"},inputTooShort:function(e){return"Introduza "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var r="Apenas pode seleccionar "+e.maximum+" ";return r+=1!=e.maximum?"itens":"item"},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/ro.js b/plugins/select2/js/i18n/ro.js
index 4bff1c64b..1ba7b40be 100644
--- a/plugins/select2/js/i18n/ro.js
+++ b/plugins/select2/js/i18n/ro.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return 1!==t&&(n+="e"),n},inputTooShort:function(e){return"Vă rugăm să introduceți "+(e.minimum-e.input.length)+" sau mai multe caractere"},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",1!==e.maximum&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"},removeAllItems:function(){return"Eliminați toate elementele"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/ru.js b/plugins/select2/js/i18n/ru.js
index 267b995ff..63a7d66c3 100644
--- a/plugins/select2/js/i18n/ru.js
+++ b/plugins/select2/js/i18n/ru.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ru",[],function(){function n(n,e,r,u){return n%10<5&&n%10>0&&n%100<5||n%100>20?n%10>1?r:e:u}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Пожалуйста, введите на "+r+" символ";return u+=n(r,"","a","ов"),u+=" меньше"},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Пожалуйста, введите ещё хотя бы "+r+" символ";return u+=n(r,"","a","ов")},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(e){var r="Вы можете выбрать не более "+e.maximum+" элемент";return r+=n(e.maximum,"","a","ов")},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"},removeAllItems:function(){return"Удалить все элементы"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/sk.js b/plugins/select2/js/i18n/sk.js
index 64346a7a3..5049528ad 100644
--- a/plugins/select2/js/i18n/sk.js
+++ b/plugins/select2/js/i18n/sk.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{errorLoading:function(){return"Výsledky sa nepodarilo načítať."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadajte o jeden znak menej":t>=2&&t<=4?"Prosím, zadajte o "+e[t](!0)+" znaky menej":"Prosím, zadajte o "+t+" znakov menej"},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadajte ešte jeden znak":t<=4?"Prosím, zadajte ešte ďalšie "+e[t](!0)+" znaky":"Prosím, zadajte ešte ďalších "+t+" znakov"},loadingMore:function(){return"Načítanie ďalších výsledkov…"},maximumSelected:function(n){return 1==n.maximum?"Môžete zvoliť len jednu položku":n.maximum>=2&&n.maximum<=4?"Môžete zvoliť najviac "+e[n.maximum](!1)+" položky":"Môžete zvoliť najviac "+n.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"},removeAllItems:function(){return"Odstráňte všetky položky"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/sl.js b/plugins/select2/js/i18n/sl.js
index 9b26c39ad..4d0b7d3e3 100644
--- a/plugins/select2/js/i18n/sl.js
+++ b/plugins/select2/js/i18n/sl.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sl",[],function(){return{errorLoading:function(){return"Zadetkov iskanja ni bilo mogoče naložiti."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Prosim zbrišite "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Prosim vpišite še "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},loadingMore:function(){return"Nalagam več zadetkov…"},maximumSelected:function(e){var n="Označite lahko največ "+e.maximum+" predmet";return 2==e.maximum?n+="a":1!=e.maximum&&(n+="e"),n},noResults:function(){return"Ni zadetkov."},searching:function(){return"Iščem…"},removeAllItems:function(){return"Odstranite vse elemente"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/sq.js b/plugins/select2/js/i18n/sq.js
index 4999d21f8..59162024e 100644
--- a/plugins/select2/js/i18n/sq.js
+++ b/plugins/select2/js/i18n/sq.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sq",[],function(){return{errorLoading:function(){return"Rezultatet nuk mund të ngarkoheshin."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Të lutem fshi "+n+" karakter";return 1!=n&&(t+="e"),t},inputTooShort:function(e){return"Të lutem shkruaj "+(e.minimum-e.input.length)+" ose më shumë karaktere"},loadingMore:function(){return"Duke ngarkuar më shumë rezultate…"},maximumSelected:function(e){var n="Mund të zgjedhësh vetëm "+e.maximum+" element";return 1!=e.maximum&&(n+="e"),n},noResults:function(){return"Nuk u gjet asnjë rezultat"},searching:function(){return"Duke kërkuar…"},removeAllItems:function(){return"Hiq të gjitha sendet"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/sr-Cyrl.js b/plugins/select2/js/i18n/sr-Cyrl.js
index 34fb00599..ce13ce8f9 100644
--- a/plugins/select2/js/i18n/sr-Cyrl.js
+++ b/plugins/select2/js/i18n/sr-Cyrl.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr-Cyrl",[],function(){function n(n,e,r,u){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:u}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Обришите "+r+" симбол";return u+=n(r,"","а","а")},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Укуцајте бар још "+r+" симбол";return u+=n(r,"","а","а")},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(e){var r="Можете изабрати само "+e.maximum+" ставк";return r+=n(e.maximum,"у","е","и")},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/sr.js b/plugins/select2/js/i18n/sr.js
index 2293b5875..dd407a06d 100644
--- a/plugins/select2/js/i18n/sr.js
+++ b/plugins/select2/js/i18n/sr.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr",[],function(){function n(n,e,r,t){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(e){var r=e.input.length-e.maximum,t="Obrišite "+r+" simbol";return t+=n(r,"","a","a")},inputTooShort:function(e){var r=e.minimum-e.input.length,t="Ukucajte bar još "+r+" simbol";return t+=n(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(e){var r="Možete izabrati samo "+e.maximum+" stavk";return r+=n(e.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/sv.js b/plugins/select2/js/i18n/sv.js
index ab5cd50c3..1bc8724a7 100644
--- a/plugins/select2/js/i18n/sv.js
+++ b/plugins/select2/js/i18n/sv.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(n){return"Vänligen sudda ut "+(n.input.length-n.maximum)+" tecken"},inputTooShort:function(n){return"Vänligen skriv in "+(n.minimum-n.input.length)+" eller fler tecken"},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(n){return"Du kan max välja "+n.maximum+" element"},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"},removeAllItems:function(){return"Ta bort alla objekt"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/th.js b/plugins/select2/js/i18n/th.js
index 5458cc09d..63eab7114 100644
--- a/plugins/select2/js/i18n/th.js
+++ b/plugins/select2/js/i18n/th.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/th",[],function(){return{errorLoading:function(){return"ไม่สามารถค้นข้อมูลได้"},inputTooLong:function(n){return"โปรดลบออก "+(n.input.length-n.maximum)+" ตัวอักษร"},inputTooShort:function(n){return"โปรดพิมพ์เพิ่มอีก "+(n.minimum-n.input.length)+" ตัวอักษร"},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(n){return"คุณสามารถเลือกได้ไม่เกิน "+n.maximum+" รายการ"},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"},removeAllItems:function(){return"ลบรายการทั้งหมด"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/tk.js b/plugins/select2/js/i18n/tk.js
index 2c8274d00..30255ff37 100644
--- a/plugins/select2/js/i18n/tk.js
+++ b/plugins/select2/js/i18n/tk.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/tk",[],function(){return{errorLoading:function(){return"Netije ýüklenmedi."},inputTooLong:function(e){return e.input.length-e.maximum+" harp bozuň."},inputTooShort:function(e){return"Ýene-de iň az "+(e.minimum-e.input.length)+" harp ýazyň."},loadingMore:function(){return"Köpräk netije görkezilýär…"},maximumSelected:function(e){return"Diňe "+e.maximum+" sanysyny saýlaň."},noResults:function(){return"Netije tapylmady."},searching:function(){return"Gözlenýär…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/tr.js b/plugins/select2/js/i18n/tr.js
index 5ab03b9be..fc4c0bf05 100644
--- a/plugins/select2/js/i18n/tr.js
+++ b/plugins/select2/js/i18n/tr.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/tr",[],function(){return{errorLoading:function(){return"Sonuç yüklenemedi"},inputTooLong:function(n){return n.input.length-n.maximum+" karakter daha girmelisiniz"},inputTooShort:function(n){return"En az "+(n.minimum-n.input.length)+" karakter daha girmelisiniz"},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(n){return"Sadece "+n.maximum+" seçim yapabilirsiniz"},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"},removeAllItems:function(){return"Tüm öğeleri kaldır"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/uk.js b/plugins/select2/js/i18n/uk.js
index cf3febb2b..63697e388 100644
--- a/plugins/select2/js/i18n/uk.js
+++ b/plugins/select2/js/i18n/uk.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/uk",[],function(){function n(n,e,u,r){return n%100>10&&n%100<15?r:n%10==1?e:n%10>1&&n%10<5?u:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(e){return"Будь ласка, видаліть "+(e.input.length-e.maximum)+" "+n(e.maximum,"літеру","літери","літер")},inputTooShort:function(n){return"Будь ласка, введіть "+(n.minimum-n.input.length)+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(e){return"Ви можете вибрати лише "+e.maximum+" "+n(e.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"},removeAllItems:function(){return"Видалити всі елементи"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/vi.js b/plugins/select2/js/i18n/vi.js
index 90848f324..24f3bc2d6 100644
--- a/plugins/select2/js/i18n/vi.js
+++ b/plugins/select2/js/i18n/vi.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/vi",[],function(){return{inputTooLong:function(n){return"Vui lòng xóa bớt "+(n.input.length-n.maximum)+" ký tự"},inputTooShort:function(n){return"Vui lòng nhập thêm từ "+(n.minimum-n.input.length)+" ký tự trở lên"},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(n){return"Chỉ có thể chọn được "+n.maximum+" lựa chọn"},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"},removeAllItems:function(){return"Xóa tất cả các mục"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/zh-CN.js b/plugins/select2/js/i18n/zh-CN.js
index 4b98e42e9..2c5649d31 100644
--- a/plugins/select2/js/i18n/zh-CN.js
+++ b/plugins/select2/js/i18n/zh-CN.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(n){return"请删除"+(n.input.length-n.maximum)+"个字符"},inputTooShort:function(n){return"请再输入至少"+(n.minimum-n.input.length)+"个字符"},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(n){return"最多只能选择"+n.maximum+"个项目"},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"},removeAllItems:function(){return"删除所有项目"}}}),n.define,n.require}();
\ No newline at end of file
diff --git a/plugins/select2/js/i18n/zh-TW.js b/plugins/select2/js/i18n/zh-TW.js
index 39b1a4e85..570a56693 100644
--- a/plugins/select2/js/i18n/zh-TW.js
+++ b/plugins/select2/js/i18n/zh-TW.js
@@ -1,3 +1,3 @@
-/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */
+/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(n){return"請刪掉"+(n.input.length-n.maximum)+"個字元"},inputTooShort:function(n){return"請再輸入"+(n.minimum-n.input.length)+"個字元"},loadingMore:function(){return"載入中…"},maximumSelected:function(n){return"你只能選擇最多"+n.maximum+"項"},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"},removeAllItems:function(){return"刪除所有項目"}}}),n.define,n.require}();
\ No newline at end of file