LaravelTest
6661 строка · 354.2 Кб
1/*!
2* OverlayScrollbars
3* https://github.com/KingSora/OverlayScrollbars
4*
5* Version: 1.13.0
6*
7* Copyright KingSora | Rene Haas.
8* https://github.com/KingSora
9*
10* Released under the MIT license.
11* Date: 02.08.2020
12*/
13
14(function (global, factory) {15if (typeof define === 'function' && define.amd)16define(function () { return factory(global, global.document, undefined); });17else if (typeof module === 'object' && typeof module.exports === 'object')18module.exports = factory(global, global.document, undefined);19else20factory(global, global.document, undefined);21}(typeof window !== 'undefined' ? window : this,22function (window, document, undefined) {23'use strict';24var PLUGINNAME = 'OverlayScrollbars';25var TYPES = {26o: 'object',27f: 'function',28a: 'array',29s: 'string',30b: 'boolean',31n: 'number',32u: 'undefined',33z: 'null'34//d : 'date',35//e : 'error',36//r : 'regexp',37//y : 'symbol'38};39var LEXICON = {40c: 'class',41s: 'style',42i: 'id',43l: 'length',44p: 'prototype',45ti: 'tabindex',46oH: 'offsetHeight',47cH: 'clientHeight',48sH: 'scrollHeight',49oW: 'offsetWidth',50cW: 'clientWidth',51sW: 'scrollWidth',52hOP: 'hasOwnProperty',53bCR: 'getBoundingClientRect'54};55var VENDORS = (function () {56//https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix57var jsCache = {};58var cssCache = {};59var cssPrefixes = ['-webkit-', '-moz-', '-o-', '-ms-'];60var jsPrefixes = ['WebKit', 'Moz', 'O', 'MS'];61function firstLetterToUpper(str) {62return str.charAt(0).toUpperCase() + str.slice(1);63}64
65return {66_cssPrefixes: cssPrefixes,67_jsPrefixes: jsPrefixes,68_cssProperty: function (name) {69var result = cssCache[name];70
71if (cssCache[LEXICON.hOP](name))72return result;73
74var uppercasedName = firstLetterToUpper(name);75var elmStyle = document.createElement('div')[LEXICON.s];76var resultPossibilities;77var i = 0;78var v;79var currVendorWithoutDashes;80
81for (; i < cssPrefixes.length; i++) {82currVendorWithoutDashes = cssPrefixes[i].replace(/-/g, '');83resultPossibilities = [84name, //transition85cssPrefixes[i] + name, //-webkit-transition86currVendorWithoutDashes + uppercasedName, //webkitTransition87firstLetterToUpper(currVendorWithoutDashes) + uppercasedName //WebkitTransition88];89for (v = 0; v < resultPossibilities[LEXICON.l]; v++) {90if (elmStyle[resultPossibilities[v]] !== undefined) {91result = resultPossibilities[v];92break;93}94}95}96
97cssCache[name] = result;98return result;99},100_cssPropertyValue: function (property, values, suffix) {101var name = property + ' ' + values;102var result = cssCache[name];103
104if (cssCache[LEXICON.hOP](name))105return result;106
107var dummyStyle = document.createElement('div')[LEXICON.s];108var possbleValues = values.split(' ');109var preparedSuffix = suffix || '';110var i = 0;111var v = -1;112var prop;113
114for (; i < possbleValues[LEXICON.l]; i++) {115for (; v < VENDORS._cssPrefixes[LEXICON.l]; v++) {116prop = v < 0 ? possbleValues[i] : VENDORS._cssPrefixes[v] + possbleValues[i];117dummyStyle.cssText = property + ':' + prop + preparedSuffix;118if (dummyStyle[LEXICON.l]) {119result = prop;120break;121}122}123}124
125cssCache[name] = result;126return result;127},128_jsAPI: function (name, isInterface, fallback) {129var i = 0;130var result = jsCache[name];131
132if (!jsCache[LEXICON.hOP](name)) {133result = window[name];134for (; i < jsPrefixes[LEXICON.l]; i++)135result = result || window[(isInterface ? jsPrefixes[i] : jsPrefixes[i].toLowerCase()) + firstLetterToUpper(name)];136jsCache[name] = result;137}138return result || fallback;139}140}141})();142var COMPATIBILITY = (function () {143function windowSize(x) {144return x ? window.innerWidth || document.documentElement[LEXICON.cW] || document.body[LEXICON.cW] : window.innerHeight || document.documentElement[LEXICON.cH] || document.body[LEXICON.cH];145}146function bind(func, thisObj) {147if (typeof func != TYPES.f) {148throw "Can't bind function!";149// closest thing possible to the ECMAScript 5150// internal IsCallable function151//throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');152}153var proto = LEXICON.p;154var aArgs = Array[proto].slice.call(arguments, 2);155var fNOP = function () { };156var fBound = function () { return func.apply(this instanceof fNOP ? this : thisObj, aArgs.concat(Array[proto].slice.call(arguments))); };157
158if (func[proto])159fNOP[proto] = func[proto]; // Function.prototype doesn't have a prototype property160fBound[proto] = new fNOP();161
162return fBound;163}164
165return {166/**167* Gets the current window width.
168* @returns {Number|number} The current window width in pixel.
169*/
170wW: bind(windowSize, 0, true),171
172/**173* Gets the current window height.
174* @returns {Number|number} The current window height in pixel.
175*/
176wH: bind(windowSize, 0),177
178/**179* Gets the MutationObserver Object or undefined if not supported.
180* @returns {MutationObserver|*|undefined} The MutationsObserver Object or undefined.
181*/
182mO: bind(VENDORS._jsAPI, 0, 'MutationObserver', true),183
184/**185* Gets the ResizeObserver Object or undefined if not supported.
186* @returns {MutationObserver|*|undefined} The ResizeObserver Object or undefined.
187*/
188rO: bind(VENDORS._jsAPI, 0, 'ResizeObserver', true),189
190/**191* Gets the RequestAnimationFrame method or it's corresponding polyfill.
192* @returns {*|Function} The RequestAnimationFrame method or it's corresponding polyfill.
193*/
194rAF: bind(VENDORS._jsAPI, 0, 'requestAnimationFrame', false, function (func) { return window.setTimeout(func, 1000 / 60); }),195
196/**197* Gets the CancelAnimationFrame method or it's corresponding polyfill.
198* @returns {*|Function} The CancelAnimationFrame method or it's corresponding polyfill.
199*/
200cAF: bind(VENDORS._jsAPI, 0, 'cancelAnimationFrame', false, function (id) { return window.clearTimeout(id); }),201
202/**203* Gets the current time.
204* @returns {number} The current time.
205*/
206now: function () {207return Date.now && Date.now() || new Date().getTime();208},209
210/**211* Stops the propagation of the given event.
212* @param event The event of which the propagation shall be stoped.
213*/
214stpP: function (event) {215if (event.stopPropagation)216event.stopPropagation();217else218event.cancelBubble = true;219},220
221/**222* Prevents the default action of the given event.
223* @param event The event of which the default action shall be prevented.
224*/
225prvD: function (event) {226if (event.preventDefault && event.cancelable)227event.preventDefault();228else229event.returnValue = false;230},231
232/**233* Gets the pageX and pageY values of the given mouse event.
234* @param event The mouse event of which the pageX and pageX shall be got.
235* @returns {{x: number, y: number}} x = pageX value, y = pageY value.
236*/
237page: function (event) {238event = event.originalEvent || event;239
240var strPage = 'page';241var strClient = 'client';242var strX = 'X';243var strY = 'Y';244var target = event.target || event.srcElement || document;245var eventDoc = target.ownerDocument || document;246var doc = eventDoc.documentElement;247var body = eventDoc.body;248
249//if touch event return return pageX/Y of it250if (event.touches !== undefined) {251var touch = event.touches[0];252return {253x: touch[strPage + strX],254y: touch[strPage + strY]255}256}257
258// Calculate pageX/Y if not native supported259if (!event[strPage + strX] && event[strClient + strX] && event[strClient + strX] != null) {260
261return {262x: event[strClient + strX] +263(doc && doc.scrollLeft || body && body.scrollLeft || 0) -264(doc && doc.clientLeft || body && body.clientLeft || 0),265y: event[strClient + strY] +266(doc && doc.scrollTop || body && body.scrollTop || 0) -267(doc && doc.clientTop || body && body.clientTop || 0)268}269}270return {271x: event[strPage + strX],272y: event[strPage + strY]273};274},275
276/**277* Gets the clicked mouse button of the given mouse event.
278* @param event The mouse event of which the clicked button shal be got.
279* @returns {number} The number of the clicked mouse button. (0 : none | 1 : leftButton | 2 : middleButton | 3 : rightButton)
280*/
281mBtn: function (event) {282var button = event.button;283if (!event.which && button !== undefined)284return (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));285else286return event.which;287},288
289/**290* Checks whether a item is in the given array and returns its index.
291* @param item The item of which the position in the array shall be determined.
292* @param arr The array.
293* @returns {number} The zero based index of the item or -1 if the item isn't in the array.
294*/
295inA: function (item, arr) {296for (var i = 0; i < arr[LEXICON.l]; i++)297//Sometiems in IE a "SCRIPT70" Permission denied error occurs if HTML elements in a iFrame are compared298try {299if (arr[i] === item)300return i;301}302catch (e) { }303return -1;304},305
306/**307* Returns true if the given value is a array.
308* @param arr The potential array.
309* @returns {boolean} True if the given value is a array, false otherwise.
310*/
311isA: function (arr) {312var def = Array.isArray;313return def ? def(arr) : this.type(arr) == TYPES.a;314},315
316/**317* Determine the internal JavaScript [[Class]] of the given object.
318* @param obj The object of which the type shall be determined.
319* @returns {string} The type of the given object.
320*/
321type: function (obj) {322if (obj === undefined)323return obj + '';324if (obj === null)325return obj + '';326return Object[LEXICON.p].toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();327},328
329
330bind: bind331
332/**333* Gets the vendor-prefixed CSS property by the given name.
334* For example the given name is "transform" and you're using a old Firefox browser then the returned value would be "-moz-transform".
335* If the browser doesn't need a vendor-prefix, then the returned string is the given name.
336* If the browser doesn't support the given property name at all (not even with a vendor-prefix) the returned value is null.
337* @param propName The unprefixed CSS property name.
338* @returns {string|null} The vendor-prefixed CSS property or null if the browser doesn't support the given CSS property.
339
340cssProp: function(propName) {
341return VENDORS._cssProperty(propName);
342}
343*/
344}345})();346
347
348var MATH = Math;349var JQUERY = window.jQuery;350var EASING = (function () {351var _easingsMath = {352p: MATH.PI,353c: MATH.cos,354s: MATH.sin,355w: MATH.pow,356t: MATH.sqrt,357n: MATH.asin,358a: MATH.abs,359o: 1.70158360};361
362/*363x : current percent (0 - 1),
364t : current time (duration * percent),
365b : start value (from),
366c : end value (to),
367d : duration
368
369easingName : function(x, t, b, c, d) { return easedValue; }
370*/
371
372return {373swing: function (x, t, b, c, d) {374return 0.5 - _easingsMath.c(x * _easingsMath.p) / 2;375},376linear: function (x, t, b, c, d) {377return x;378},379easeInQuad: function (x, t, b, c, d) {380return c * (t /= d) * t + b;381},382easeOutQuad: function (x, t, b, c, d) {383return -c * (t /= d) * (t - 2) + b;384},385easeInOutQuad: function (x, t, b, c, d) {386return ((t /= d / 2) < 1) ? c / 2 * t * t + b : -c / 2 * ((--t) * (t - 2) - 1) + b;387},388easeInCubic: function (x, t, b, c, d) {389return c * (t /= d) * t * t + b;390},391easeOutCubic: function (x, t, b, c, d) {392return c * ((t = t / d - 1) * t * t + 1) + b;393},394easeInOutCubic: function (x, t, b, c, d) {395return ((t /= d / 2) < 1) ? c / 2 * t * t * t + b : c / 2 * ((t -= 2) * t * t + 2) + b;396},397easeInQuart: function (x, t, b, c, d) {398return c * (t /= d) * t * t * t + b;399},400easeOutQuart: function (x, t, b, c, d) {401return -c * ((t = t / d - 1) * t * t * t - 1) + b;402},403easeInOutQuart: function (x, t, b, c, d) {404return ((t /= d / 2) < 1) ? c / 2 * t * t * t * t + b : -c / 2 * ((t -= 2) * t * t * t - 2) + b;405},406easeInQuint: function (x, t, b, c, d) {407return c * (t /= d) * t * t * t * t + b;408},409easeOutQuint: function (x, t, b, c, d) {410return c * ((t = t / d - 1) * t * t * t * t + 1) + b;411},412easeInOutQuint: function (x, t, b, c, d) {413return ((t /= d / 2) < 1) ? c / 2 * t * t * t * t * t + b : c / 2 * ((t -= 2) * t * t * t * t + 2) + b;414},415easeInSine: function (x, t, b, c, d) {416return -c * _easingsMath.c(t / d * (_easingsMath.p / 2)) + c + b;417},418easeOutSine: function (x, t, b, c, d) {419return c * _easingsMath.s(t / d * (_easingsMath.p / 2)) + b;420},421easeInOutSine: function (x, t, b, c, d) {422return -c / 2 * (_easingsMath.c(_easingsMath.p * t / d) - 1) + b;423},424easeInExpo: function (x, t, b, c, d) {425return (t == 0) ? b : c * _easingsMath.w(2, 10 * (t / d - 1)) + b;426},427easeOutExpo: function (x, t, b, c, d) {428return (t == d) ? b + c : c * (-_easingsMath.w(2, -10 * t / d) + 1) + b;429},430easeInOutExpo: function (x, t, b, c, d) {431if (t == 0) return b;432if (t == d) return b + c;433if ((t /= d / 2) < 1) return c / 2 * _easingsMath.w(2, 10 * (t - 1)) + b;434return c / 2 * (-_easingsMath.w(2, -10 * --t) + 2) + b;435},436easeInCirc: function (x, t, b, c, d) {437return -c * (_easingsMath.t(1 - (t /= d) * t) - 1) + b;438},439easeOutCirc: function (x, t, b, c, d) {440return c * _easingsMath.t(1 - (t = t / d - 1) * t) + b;441},442easeInOutCirc: function (x, t, b, c, d) {443return ((t /= d / 2) < 1) ? -c / 2 * (_easingsMath.t(1 - t * t) - 1) + b : c / 2 * (_easingsMath.t(1 - (t -= 2) * t) + 1) + b;444},445easeInElastic: function (x, t, b, c, d) {446var s = _easingsMath.o; var p = 0; var a = c;447if (t == 0) return b; if ((t /= d) == 1) return b + c; if (!p) p = d * .3;448if (a < _easingsMath.a(c)) { a = c; s = p / 4; }449else s = p / (2 * _easingsMath.p) * _easingsMath.n(c / a);450return -(a * _easingsMath.w(2, 10 * (t -= 1)) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p)) + b;451},452easeOutElastic: function (x, t, b, c, d) {453var s = _easingsMath.o; var p = 0; var a = c;454if (t == 0) return b;455if ((t /= d) == 1) return b + c;456if (!p) p = d * .3;457if (a < _easingsMath.a(c)) { a = c; s = p / 4; }458else s = p / (2 * _easingsMath.p) * _easingsMath.n(c / a);459return a * _easingsMath.w(2, -10 * t) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p) + c + b;460},461easeInOutElastic: function (x, t, b, c, d) {462var s = _easingsMath.o; var p = 0; var a = c;463if (t == 0) return b;464if ((t /= d / 2) == 2) return b + c;465if (!p) p = d * (.3 * 1.5);466if (a < _easingsMath.a(c)) { a = c; s = p / 4; }467else s = p / (2 * _easingsMath.p) * _easingsMath.n(c / a);468if (t < 1) return -.5 * (a * _easingsMath.w(2, 10 * (t -= 1)) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p)) + b;469return a * _easingsMath.w(2, -10 * (t -= 1)) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p) * .5 + c + b;470},471easeInBack: function (x, t, b, c, d, s) {472s = s || _easingsMath.o;473return c * (t /= d) * t * ((s + 1) * t - s) + b;474},475easeOutBack: function (x, t, b, c, d, s) {476s = s || _easingsMath.o;477return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;478},479easeInOutBack: function (x, t, b, c, d, s) {480s = s || _easingsMath.o;481return ((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;482},483easeInBounce: function (x, t, b, c, d) {484return c - this.easeOutBounce(x, d - t, 0, c, d) + b;485},486easeOutBounce: function (x, t, b, c, d) {487var o = 7.5625;488if ((t /= d) < (1 / 2.75)) {489return c * (o * t * t) + b;490} else if (t < (2 / 2.75)) {491return c * (o * (t -= (1.5 / 2.75)) * t + .75) + b;492} else if (t < (2.5 / 2.75)) {493return c * (o * (t -= (2.25 / 2.75)) * t + .9375) + b;494} else {495return c * (o * (t -= (2.625 / 2.75)) * t + .984375) + b;496}497},498easeInOutBounce: function (x, t, b, c, d) {499return (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;500}501};502/*503*
504* TERMS OF USE - EASING EQUATIONS
505*
506* Open source under the BSD License.
507*
508* Copyright © 2001 Robert Penner
509* All rights reserved.
510*
511* Redistribution and use in source and binary forms, with or without modification,
512* are permitted provided that the following conditions are met:
513*
514* Redistributions of source code must retain the above copyright notice, this list of
515* conditions and the following disclaimer.
516* Redistributions in binary form must reproduce the above copyright notice, this list
517* of conditions and the following disclaimer in the documentation and/or other materials
518* provided with the distribution.
519*
520* Neither the name of the author nor the names of contributors may be used to endorse
521* or promote products derived from this software without specific prior written permission.
522*
523* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
524* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
525* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
526* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
527* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
528* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
529* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
530* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
531* OF THE POSSIBILITY OF SUCH DAMAGE.
532*
533*/
534})();535var FRAMEWORK = (function () {536var _rnothtmlwhite = (/[^\x20\t\r\n\f]+/g);537var _strSpace = ' ';538var _strEmpty = '';539var _strScrollLeft = 'scrollLeft';540var _strScrollTop = 'scrollTop';541var _animations = [];542var _type = COMPATIBILITY.type;543var _cssNumber = {544animationIterationCount: true,545columnCount: true,546fillOpacity: true,547flexGrow: true,548flexShrink: true,549fontWeight: true,550lineHeight: true,551opacity: true,552order: true,553orphans: true,554widows: true,555zIndex: true,556zoom: true557};558
559function extend() {560var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {},561i = 1,562length = arguments[LEXICON.l],563deep = false;564
565// Handle a deep copy situation566if (_type(target) == TYPES.b) {567deep = target;568target = arguments[1] || {};569// skip the boolean and the target570i = 2;571}572
573// Handle case when target is a string or something (possible in deep copy)574if (_type(target) != TYPES.o && !_type(target) == TYPES.f) {575target = {};576}577
578// extend jQuery itself if only one argument is passed579if (length === i) {580target = FakejQuery;581--i;582}583
584for (; i < length; i++) {585// Only deal with non-null/undefined values586if ((options = arguments[i]) != null) {587// Extend the base object588for (name in options) {589src = target[name];590copy = options[name];591
592// Prevent never-ending loop593if (target === copy) {594continue;595}596
597// Recurse if we're merging plain objects or arrays598if (deep && copy && (isPlainObject(copy) || (copyIsArray = COMPATIBILITY.isA(copy)))) {599if (copyIsArray) {600copyIsArray = false;601clone = src && COMPATIBILITY.isA(src) ? src : [];602
603} else {604clone = src && isPlainObject(src) ? src : {};605}606
607// Never move original objects, clone them608target[name] = extend(deep, clone, copy);609
610// Don't bring in undefined values611} else if (copy !== undefined) {612target[name] = copy;613}614}615}616}617
618// Return the modified object619return target;620};621
622function inArray(item, arr, fromIndex) {623for (var i = fromIndex || 0; i < arr[LEXICON.l]; i++)624if (arr[i] === item)625return i;626return -1;627}628
629function isFunction(obj) {630return _type(obj) == TYPES.f;631};632
633function isEmptyObject(obj) {634for (var name in obj)635return false;636return true;637};638
639function isPlainObject(obj) {640if (!obj || _type(obj) != TYPES.o)641return false;642
643var key;644var proto = LEXICON.p;645var hasOwnProperty = Object[proto].hasOwnProperty;646var hasOwnConstructor = hasOwnProperty.call(obj, 'constructor');647var hasIsPrototypeOf = obj.constructor && obj.constructor[proto] && hasOwnProperty.call(obj.constructor[proto], 'isPrototypeOf');648
649if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {650return false;651}652
653
654for (key in obj) { /**/ }655
656return _type(key) == TYPES.u || hasOwnProperty.call(obj, key);657};658
659function each(obj, callback) {660var i = 0;661
662if (isArrayLike(obj)) {663for (; i < obj[LEXICON.l]; i++) {664if (callback.call(obj[i], i, obj[i]) === false)665break;666}667}668else {669for (i in obj) {670if (callback.call(obj[i], i, obj[i]) === false)671break;672}673}674
675return obj;676};677
678function isArrayLike(obj) {679var length = !!obj && [LEXICON.l] in obj && obj[LEXICON.l];680var t = _type(obj);681return isFunction(t) ? false : (t == TYPES.a || length === 0 || _type(length) == TYPES.n && length > 0 && (length - 1) in obj);682}683
684function stripAndCollapse(value) {685var tokens = value.match(_rnothtmlwhite) || [];686return tokens.join(_strSpace);687}688
689function matches(elem, selector) {690var nodeList = (elem.parentNode || document).querySelectorAll(selector) || [];691var i = nodeList[LEXICON.l];692
693while (i--)694if (nodeList[i] == elem)695return true;696
697return false;698}699
700function insertAdjacentElement(el, strategy, child) {701if (COMPATIBILITY.isA(child)) {702for (var i = 0; i < child[LEXICON.l]; i++)703insertAdjacentElement(el, strategy, child[i]);704}705else if (_type(child) == TYPES.s)706el.insertAdjacentHTML(strategy, child);707else708el.insertAdjacentElement(strategy, child.nodeType ? child : child[0]);709}710
711function setCSSVal(el, prop, val) {712try {713if (el[LEXICON.s][prop] !== undefined)714el[LEXICON.s][prop] = parseCSSVal(prop, val);715} catch (e) { }716}717
718function parseCSSVal(prop, val) {719if (!_cssNumber[prop.toLowerCase()] && _type(val) == TYPES.n)720val += 'px';721return val;722}723
724function startNextAnimationInQ(animObj, removeFromQ) {725var index;726var nextAnim;727if (removeFromQ !== false)728animObj.q.splice(0, 1);729if (animObj.q[LEXICON.l] > 0) {730nextAnim = animObj.q[0];731animate(animObj.el, nextAnim.props, nextAnim.duration, nextAnim.easing, nextAnim.complete, true);732}733else {734index = inArray(animObj, _animations);735if (index > -1)736_animations.splice(index, 1);737}738}739
740function setAnimationValue(el, prop, value) {741if (prop === _strScrollLeft || prop === _strScrollTop)742el[prop] = value;743else744setCSSVal(el, prop, value);745}746
747function animate(el, props, options, easing, complete, guaranteedNext) {748var hasOptions = isPlainObject(options);749var from = {};750var to = {};751var i = 0;752var key;753var animObj;754var start;755var progress;756var step;757var specialEasing;758var duration;759if (hasOptions) {760easing = options.easing;761start = options.start;762progress = options.progress;763step = options.step;764specialEasing = options.specialEasing;765complete = options.complete;766duration = options.duration;767}768else769duration = options;770specialEasing = specialEasing || {};771duration = duration || 400;772easing = easing || 'swing';773guaranteedNext = guaranteedNext || false;774
775for (; i < _animations[LEXICON.l]; i++) {776if (_animations[i].el === el) {777animObj = _animations[i];778break;779}780}781
782if (!animObj) {783animObj = {784el: el,785q: []786};787_animations.push(animObj);788}789
790for (key in props) {791if (key === _strScrollLeft || key === _strScrollTop)792from[key] = el[key];793else794from[key] = FakejQuery(el).css(key);795}796
797for (key in from) {798if (from[key] !== props[key] && props[key] !== undefined)799to[key] = props[key];800}801
802if (!isEmptyObject(to)) {803var timeNow;804var end;805var percent;806var fromVal;807var toVal;808var easedVal;809var timeStart;810var frame;811var elapsed;812var qPos = guaranteedNext ? 0 : inArray(qObj, animObj.q);813var qObj = {814props: to,815duration: hasOptions ? options : duration,816easing: easing,817complete: complete818};819if (qPos === -1) {820qPos = animObj.q[LEXICON.l];821animObj.q.push(qObj);822}823
824if (qPos === 0) {825if (duration > 0) {826timeStart = COMPATIBILITY.now();827frame = function () {828timeNow = COMPATIBILITY.now();829elapsed = (timeNow - timeStart);830end = qObj.stop || elapsed >= duration;831percent = 1 - ((MATH.max(0, timeStart + duration - timeNow) / duration) || 0);832
833for (key in to) {834fromVal = parseFloat(from[key]);835toVal = parseFloat(to[key]);836easedVal = (toVal - fromVal) * EASING[specialEasing[key] || easing](percent, percent * duration, 0, 1, duration) + fromVal;837setAnimationValue(el, key, easedVal);838if (isFunction(step)) {839step(easedVal, {840elem: el,841prop: key,842start: fromVal,843now: easedVal,844end: toVal,845pos: percent,846options: {847easing: easing,848speacialEasing: specialEasing,849duration: duration,850complete: complete,851step: step852},853startTime: timeStart854});855}856}857
858if (isFunction(progress))859progress({}, percent, MATH.max(0, duration - elapsed));860
861if (end) {862startNextAnimationInQ(animObj);863if (isFunction(complete))864complete();865}866else867qObj.frame = COMPATIBILITY.rAF()(frame);868};869qObj.frame = COMPATIBILITY.rAF()(frame);870}871else {872for (key in to)873setAnimationValue(el, key, to[key]);874startNextAnimationInQ(animObj);875}876}877}878else if (guaranteedNext)879startNextAnimationInQ(animObj);880}881
882function stop(el, clearQ, jumpToEnd) {883var animObj;884var qObj;885var key;886var i = 0;887for (; i < _animations[LEXICON.l]; i++) {888animObj = _animations[i];889if (animObj.el === el) {890if (animObj.q[LEXICON.l] > 0) {891qObj = animObj.q[0];892qObj.stop = true;893COMPATIBILITY.cAF()(qObj.frame);894animObj.q.splice(0, 1);895
896if (jumpToEnd)897for (key in qObj.props)898setAnimationValue(el, key, qObj.props[key]);899
900if (clearQ)901animObj.q = [];902else903startNextAnimationInQ(animObj, false);904}905break;906}907}908}909
910function elementIsVisible(el) {911return !!(el[LEXICON.oW] || el[LEXICON.oH] || el.getClientRects()[LEXICON.l]);912}913
914function FakejQuery(selector) {915if (arguments[LEXICON.l] === 0)916return this;917
918var base = new FakejQuery();919var elements = selector;920var i = 0;921var elms;922var el;923
924if (_type(selector) == TYPES.s) {925elements = [];926if (selector.charAt(0) === '<') {927el = document.createElement('div');928el.innerHTML = selector;929elms = el.children;930}931else {932elms = document.querySelectorAll(selector);933}934
935for (; i < elms[LEXICON.l]; i++)936elements.push(elms[i]);937}938
939if (elements) {940if (_type(elements) != TYPES.s && (!isArrayLike(elements) || elements === window || elements === elements.self))941elements = [elements];942
943for (i = 0; i < elements[LEXICON.l]; i++)944base[i] = elements[i];945
946base[LEXICON.l] = elements[LEXICON.l];947}948
949return base;950};951
952FakejQuery[LEXICON.p] = {953
954//EVENTS:955
956on: function (eventName, handler) {957eventName = (eventName || _strEmpty).match(_rnothtmlwhite) || [_strEmpty];958
959var eventNameLength = eventName[LEXICON.l];960var i = 0;961var el;962return this.each(function () {963el = this;964try {965if (el.addEventListener) {966for (; i < eventNameLength; i++)967el.addEventListener(eventName[i], handler);968}969else if (el.detachEvent) {970for (; i < eventNameLength; i++)971el.attachEvent('on' + eventName[i], handler);972}973} catch (e) { }974});975},976
977off: function (eventName, handler) {978eventName = (eventName || _strEmpty).match(_rnothtmlwhite) || [_strEmpty];979
980var eventNameLength = eventName[LEXICON.l];981var i = 0;982var el;983return this.each(function () {984el = this;985try {986if (el.removeEventListener) {987for (; i < eventNameLength; i++)988el.removeEventListener(eventName[i], handler);989}990else if (el.detachEvent) {991for (; i < eventNameLength; i++)992el.detachEvent('on' + eventName[i], handler);993}994} catch (e) { }995});996},997
998one: function (eventName, handler) {999eventName = (eventName || _strEmpty).match(_rnothtmlwhite) || [_strEmpty];1000return this.each(function () {1001var el = FakejQuery(this);1002FakejQuery.each(eventName, function (i, oneEventName) {1003var oneHandler = function (e) {1004handler.call(this, e);1005el.off(oneEventName, oneHandler);1006};1007el.on(oneEventName, oneHandler);1008});1009});1010},1011
1012trigger: function (eventName) {1013var el;1014var event;1015return this.each(function () {1016el = this;1017if (document.createEvent) {1018event = document.createEvent('HTMLEvents');1019event.initEvent(eventName, true, false);1020el.dispatchEvent(event);1021}1022else {1023el.fireEvent('on' + eventName);1024}1025});1026},1027
1028//DOM NODE INSERTING / REMOVING:1029
1030append: function (child) {1031return this.each(function () { insertAdjacentElement(this, 'beforeend', child); });1032},1033
1034prepend: function (child) {1035return this.each(function () { insertAdjacentElement(this, 'afterbegin', child); });1036},1037
1038before: function (child) {1039return this.each(function () { insertAdjacentElement(this, 'beforebegin', child); });1040},1041
1042after: function (child) {1043return this.each(function () { insertAdjacentElement(this, 'afterend', child); });1044},1045
1046remove: function () {1047return this.each(function () {1048var el = this;1049var parentNode = el.parentNode;1050if (parentNode != null)1051parentNode.removeChild(el);1052});1053},1054
1055unwrap: function () {1056var parents = [];1057var i;1058var el;1059var parent;1060
1061this.each(function () {1062parent = this.parentNode;1063if (inArray(parent, parents) === - 1)1064parents.push(parent);1065});1066
1067for (i = 0; i < parents[LEXICON.l]; i++) {1068el = parents[i];1069parent = el.parentNode;1070while (el.firstChild)1071parent.insertBefore(el.firstChild, el);1072parent.removeChild(el);1073}1074
1075return this;1076},1077
1078wrapAll: function (wrapperHTML) {1079var i;1080var nodes = this;1081var wrapper = FakejQuery(wrapperHTML)[0];1082var deepest = wrapper;1083var parent = nodes[0].parentNode;1084var previousSibling = nodes[0].previousSibling;1085while (deepest.childNodes[LEXICON.l] > 0)1086deepest = deepest.childNodes[0];1087
1088for (i = 0; nodes[LEXICON.l] - i; deepest.firstChild === nodes[0] && i++)1089deepest.appendChild(nodes[i]);1090
1091var nextSibling = previousSibling ? previousSibling.nextSibling : parent.firstChild;1092parent.insertBefore(wrapper, nextSibling);1093
1094return this;1095},1096
1097wrapInner: function (wrapperHTML) {1098return this.each(function () {1099var el = FakejQuery(this);1100var contents = el.contents();1101
1102if (contents[LEXICON.l])1103contents.wrapAll(wrapperHTML);1104else1105el.append(wrapperHTML);1106});1107},1108
1109wrap: function (wrapperHTML) {1110return this.each(function () { FakejQuery(this).wrapAll(wrapperHTML); });1111},1112
1113
1114//DOM NODE MANIPULATION / INFORMATION:1115
1116css: function (styles, val) {1117var el;1118var key;1119var cptStyle;1120var getCptStyle = window.getComputedStyle;1121if (_type(styles) == TYPES.s) {1122if (val === undefined) {1123el = this[0];1124cptStyle = getCptStyle ? getCptStyle(el, null) : el.currentStyle[styles];1125
1126//https://bugzilla.mozilla.org/show_bug.cgi?id=548397 can be null sometimes if iframe with display: none (firefox only!)1127return getCptStyle ? cptStyle != null ? cptStyle.getPropertyValue(styles) : el[LEXICON.s][styles] : cptStyle;1128}1129else {1130return this.each(function () {1131setCSSVal(this, styles, val);1132});1133}1134}1135else {1136return this.each(function () {1137for (key in styles)1138setCSSVal(this, key, styles[key]);1139});1140}1141},1142
1143hasClass: function (className) {1144var elem, i = 0;1145var classNamePrepared = _strSpace + className + _strSpace;1146var classList;1147
1148while ((elem = this[i++])) {1149classList = elem.classList;1150if (classList && classList.contains(className))1151return true;1152else if (elem.nodeType === 1 && (_strSpace + stripAndCollapse(elem.className + _strEmpty) + _strSpace).indexOf(classNamePrepared) > -1)1153return true;1154}1155
1156return false;1157},1158
1159addClass: function (className) {1160var classes;1161var elem;1162var cur;1163var curValue;1164var clazz;1165var finalValue;1166var supportClassList;1167var elmClassList;1168var i = 0;1169var v = 0;1170
1171if (className) {1172classes = className.match(_rnothtmlwhite) || [];1173
1174while ((elem = this[i++])) {1175elmClassList = elem.classList;1176if (supportClassList === undefined)1177supportClassList = elmClassList !== undefined;1178
1179if (supportClassList) {1180while ((clazz = classes[v++]))1181elmClassList.add(clazz);1182}1183else {1184curValue = elem.className + _strEmpty;1185cur = elem.nodeType === 1 && (_strSpace + stripAndCollapse(curValue) + _strSpace);1186
1187if (cur) {1188while ((clazz = classes[v++]))1189if (cur.indexOf(_strSpace + clazz + _strSpace) < 0)1190cur += clazz + _strSpace;1191
1192finalValue = stripAndCollapse(cur);1193if (curValue !== finalValue)1194elem.className = finalValue;1195}1196}1197}1198}1199
1200return this;1201},1202
1203removeClass: function (className) {1204var classes;1205var elem;1206var cur;1207var curValue;1208var clazz;1209var finalValue;1210var supportClassList;1211var elmClassList;1212var i = 0;1213var v = 0;1214
1215if (className) {1216classes = className.match(_rnothtmlwhite) || [];1217
1218while ((elem = this[i++])) {1219elmClassList = elem.classList;1220if (supportClassList === undefined)1221supportClassList = elmClassList !== undefined;1222
1223if (supportClassList) {1224while ((clazz = classes[v++]))1225elmClassList.remove(clazz);1226}1227else {1228curValue = elem.className + _strEmpty;1229cur = elem.nodeType === 1 && (_strSpace + stripAndCollapse(curValue) + _strSpace);1230
1231if (cur) {1232while ((clazz = classes[v++]))1233while (cur.indexOf(_strSpace + clazz + _strSpace) > -1)1234cur = cur.replace(_strSpace + clazz + _strSpace, _strSpace);1235
1236finalValue = stripAndCollapse(cur);1237if (curValue !== finalValue)1238elem.className = finalValue;1239}1240}1241}1242}1243
1244return this;1245},1246
1247hide: function () {1248return this.each(function () { this[LEXICON.s].display = 'none'; });1249},1250
1251show: function () {1252return this.each(function () { this[LEXICON.s].display = 'block'; });1253},1254
1255attr: function (attrName, value) {1256var i = 0;1257var el;1258while (el = this[i++]) {1259if (value === undefined)1260return el.getAttribute(attrName);1261el.setAttribute(attrName, value);1262}1263return this;1264},1265
1266removeAttr: function (attrName) {1267return this.each(function () { this.removeAttribute(attrName); });1268},1269
1270offset: function () {1271var el = this[0];1272var rect = el[LEXICON.bCR]();1273var scrollLeft = window.pageXOffset || document.documentElement[_strScrollLeft];1274var scrollTop = window.pageYOffset || document.documentElement[_strScrollTop];1275return {1276top: rect.top + scrollTop,1277left: rect.left + scrollLeft1278};1279},1280
1281position: function () {1282var el = this[0];1283return {1284top: el.offsetTop,1285left: el.offsetLeft1286};1287},1288
1289scrollLeft: function (value) {1290var i = 0;1291var el;1292while (el = this[i++]) {1293if (value === undefined)1294return el[_strScrollLeft];1295el[_strScrollLeft] = value;1296}1297return this;1298},1299
1300scrollTop: function (value) {1301var i = 0;1302var el;1303while (el = this[i++]) {1304if (value === undefined)1305return el[_strScrollTop];1306el[_strScrollTop] = value;1307}1308return this;1309},1310
1311val: function (value) {1312var el = this[0];1313if (!value)1314return el.value;1315el.value = value;1316return this;1317},1318
1319
1320//DOM TRAVERSAL / FILTERING:1321
1322first: function () {1323return this.eq(0);1324},1325
1326last: function () {1327return this.eq(-1);1328},1329
1330eq: function (index) {1331return FakejQuery(this[index >= 0 ? index : this[LEXICON.l] + index]);1332},1333
1334find: function (selector) {1335var children = [];1336var i;1337this.each(function () {1338var el = this;1339var ch = el.querySelectorAll(selector);1340for (i = 0; i < ch[LEXICON.l]; i++)1341children.push(ch[i]);1342});1343return FakejQuery(children);1344},1345
1346children: function (selector) {1347var children = [];1348var el;1349var ch;1350var i;1351
1352this.each(function () {1353ch = this.children;1354for (i = 0; i < ch[LEXICON.l]; i++) {1355el = ch[i];1356if (selector) {1357if ((el.matches && el.matches(selector)) || matches(el, selector))1358children.push(el);1359}1360else1361children.push(el);1362}1363});1364return FakejQuery(children);1365},1366
1367parent: function (selector) {1368var parents = [];1369var parent;1370this.each(function () {1371parent = this.parentNode;1372if (selector ? FakejQuery(parent).is(selector) : true)1373parents.push(parent);1374});1375return FakejQuery(parents);1376},1377
1378is: function (selector) {1379
1380var el;1381var i;1382for (i = 0; i < this[LEXICON.l]; i++) {1383el = this[i];1384if (selector === ':visible')1385return elementIsVisible(el);1386if (selector === ':hidden')1387return !elementIsVisible(el);1388if ((el.matches && el.matches(selector)) || matches(el, selector))1389return true;1390}1391return false;1392},1393
1394contents: function () {1395var contents = [];1396var childs;1397var i;1398
1399this.each(function () {1400childs = this.childNodes;1401for (i = 0; i < childs[LEXICON.l]; i++)1402contents.push(childs[i]);1403});1404
1405return FakejQuery(contents);1406},1407
1408each: function (callback) {1409return each(this, callback);1410},1411
1412
1413//ANIMATION:1414
1415animate: function (props, duration, easing, complete) {1416return this.each(function () { animate(this, props, duration, easing, complete); });1417},1418
1419stop: function (clearQ, jump) {1420return this.each(function () { stop(this, clearQ, jump); });1421}1422};1423
1424extend(FakejQuery, {1425extend: extend,1426inArray: inArray,1427isEmptyObject: isEmptyObject,1428isPlainObject: isPlainObject,1429each: each1430});1431
1432return FakejQuery;1433})();1434var INSTANCES = (function () {1435var _targets = [];1436var _instancePropertyString = '__overlayScrollbars__';1437
1438/**1439* Register, unregister or get a certain (or all) instances.
1440* Register: Pass the target and the instance.
1441* Unregister: Pass the target and null.
1442* Get Instance: Pass the target from which the instance shall be got.
1443* Get Targets: Pass no arguments.
1444* @param target The target to which the instance shall be registered / from which the instance shall be unregistered / the instance shall be got
1445* @param instance The instance.
1446* @returns {*|void} Returns the instance from the given target.
1447*/
1448return function (target, instance) {1449var argLen = arguments[LEXICON.l];1450if (argLen < 1) {1451//return all targets1452return _targets;1453}1454else {1455if (instance) {1456//register instance1457target[_instancePropertyString] = instance;1458_targets.push(target);1459}1460else {1461var index = COMPATIBILITY.inA(target, _targets);1462if (index > -1) {1463if (argLen > 1) {1464//unregister instance1465delete target[_instancePropertyString];1466_targets.splice(index, 1);1467}1468else {1469//get instance from target1470return _targets[index][_instancePropertyString];1471}1472}1473}1474}1475}1476})();1477var PLUGIN = (function () {1478var _plugin;1479var _pluginsGlobals;1480var _pluginsAutoUpdateLoop;1481var _pluginsExtensions = [];1482var _pluginsOptions = (function () {1483var type = COMPATIBILITY.type;1484var possibleTemplateTypes = [1485TYPES.b, //boolean1486TYPES.n, //number1487TYPES.s, //string1488TYPES.a, //array1489TYPES.o, //object1490TYPES.f, //function1491TYPES.z //null1492];1493var restrictedStringsSplit = ' ';1494var restrictedStringsPossibilitiesSplit = ':';1495var classNameAllowedValues = [TYPES.z, TYPES.s];1496var numberAllowedValues = TYPES.n;1497var booleanNullAllowedValues = [TYPES.z, TYPES.b];1498var booleanTrueTemplate = [true, TYPES.b];1499var booleanFalseTemplate = [false, TYPES.b];1500var callbackTemplate = [null, [TYPES.z, TYPES.f]];1501var updateOnLoadTemplate = [['img'], [TYPES.s, TYPES.a, TYPES.z]];1502var inheritedAttrsTemplate = [['style', 'class'], [TYPES.s, TYPES.a, TYPES.z]];1503var resizeAllowedValues = 'n:none b:both h:horizontal v:vertical';1504var overflowBehaviorAllowedValues = 'v-h:visible-hidden v-s:visible-scroll s:scroll h:hidden';1505var scrollbarsVisibilityAllowedValues = 'v:visible h:hidden a:auto';1506var scrollbarsAutoHideAllowedValues = 'n:never s:scroll l:leave m:move';1507var optionsDefaultsAndTemplate = {1508className: ['os-theme-dark', classNameAllowedValues], //null || string1509resize: ['none', resizeAllowedValues], //none || both || horizontal || vertical || n || b || h || v1510sizeAutoCapable: booleanTrueTemplate, //true || false1511clipAlways: booleanTrueTemplate, //true || false1512normalizeRTL: booleanTrueTemplate, //true || false1513paddingAbsolute: booleanFalseTemplate, //true || false1514autoUpdate: [null, booleanNullAllowedValues], //true || false || null1515autoUpdateInterval: [33, numberAllowedValues], //number1516updateOnLoad: updateOnLoadTemplate, //string || array || null1517nativeScrollbarsOverlaid: {1518showNativeScrollbars: booleanFalseTemplate, //true || false1519initialize: booleanTrueTemplate //true || false1520},1521overflowBehavior: {1522x: ['scroll', overflowBehaviorAllowedValues], //visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s1523y: ['scroll', overflowBehaviorAllowedValues] //visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s1524},1525scrollbars: {1526visibility: ['auto', scrollbarsVisibilityAllowedValues], //visible || hidden || auto || v || h || a1527autoHide: ['never', scrollbarsAutoHideAllowedValues], //never || scroll || leave || move || n || s || l || m1528autoHideDelay: [800, numberAllowedValues], //number1529dragScrolling: booleanTrueTemplate, //true || false1530clickScrolling: booleanFalseTemplate, //true || false1531touchSupport: booleanTrueTemplate, //true || false1532snapHandle: booleanFalseTemplate //true || false1533},1534textarea: {1535dynWidth: booleanFalseTemplate, //true || false1536dynHeight: booleanFalseTemplate, //true || false1537inheritedAttrs: inheritedAttrsTemplate //string || array || null1538},1539callbacks: {1540onInitialized: callbackTemplate, //null || function1541onInitializationWithdrawn: callbackTemplate, //null || function1542onDestroyed: callbackTemplate, //null || function1543onScrollStart: callbackTemplate, //null || function1544onScroll: callbackTemplate, //null || function1545onScrollStop: callbackTemplate, //null || function1546onOverflowChanged: callbackTemplate, //null || function1547onOverflowAmountChanged: callbackTemplate, //null || function1548onDirectionChanged: callbackTemplate, //null || function1549onContentSizeChanged: callbackTemplate, //null || function1550onHostSizeChanged: callbackTemplate, //null || function1551onUpdated: callbackTemplate //null || function1552}1553};1554var convert = function (template) {1555var recursive = function (obj) {1556var key;1557var val;1558var valType;1559for (key in obj) {1560if (!obj[LEXICON.hOP](key))1561continue;1562val = obj[key];1563valType = type(val);1564if (valType == TYPES.a)1565obj[key] = val[template ? 1 : 0];1566else if (valType == TYPES.o)1567obj[key] = recursive(val);1568}1569return obj;1570};1571return recursive(FRAMEWORK.extend(true, {}, optionsDefaultsAndTemplate));1572};1573
1574return {1575_defaults: convert(),1576
1577_template: convert(true),1578
1579/**1580* Validates the passed object by the passed template.
1581* @param obj The object which shall be validated.
1582* @param template The template which defines the allowed values and types.
1583* @param writeErrors True if errors shall be logged to the console.
1584* @param diffObj If a object is passed then only valid differences to this object will be returned.
1585* @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.
1586*/
1587_validate: function (obj, template, writeErrors, diffObj) {1588var validatedOptions = {};1589var validatedOptionsPrepared = {};1590var objectCopy = FRAMEWORK.extend(true, {}, obj);1591var inArray = FRAMEWORK.inArray;1592var isEmptyObj = FRAMEWORK.isEmptyObject;1593var checkObjectProps = function (data, template, diffData, validatedOptions, validatedOptionsPrepared, prevPropName) {1594for (var prop in template) {1595if (template[LEXICON.hOP](prop) && data[LEXICON.hOP](prop)) {1596var isValid = false;1597var isDiff = false;1598var templateValue = template[prop];1599var templateValueType = type(templateValue);1600var templateIsComplex = templateValueType == TYPES.o;1601var templateTypes = !COMPATIBILITY.isA(templateValue) ? [templateValue] : templateValue;1602var dataDiffValue = diffData[prop];1603var dataValue = data[prop];1604var dataValueType = type(dataValue);1605var propPrefix = prevPropName ? prevPropName + '.' : '';1606var error = "The option \"" + propPrefix + prop + "\" wasn't set, because";1607var errorPossibleTypes = [];1608var errorRestrictedStrings = [];1609var restrictedStringValuesSplit;1610var restrictedStringValuesPossibilitiesSplit;1611var isRestrictedValue;1612var mainPossibility;1613var currType;1614var i;1615var v;1616var j;1617
1618dataDiffValue = dataDiffValue === undefined ? {} : dataDiffValue;1619
1620//if the template has a object as value, it means that the options are complex (verschachtelt)1621if (templateIsComplex && dataValueType == TYPES.o) {1622validatedOptions[prop] = {};1623validatedOptionsPrepared[prop] = {};1624checkObjectProps(dataValue, templateValue, dataDiffValue, validatedOptions[prop], validatedOptionsPrepared[prop], propPrefix + prop);1625FRAMEWORK.each([data, validatedOptions, validatedOptionsPrepared], function (index, value) {1626if (isEmptyObj(value[prop])) {1627delete value[prop];1628}1629});1630}1631else if (!templateIsComplex) {1632for (i = 0; i < templateTypes[LEXICON.l]; i++) {1633currType = templateTypes[i];1634templateValueType = type(currType);1635//if currtype is string and starts with restrictedStringPrefix and end with restrictedStringSuffix1636isRestrictedValue = templateValueType == TYPES.s && inArray(currType, possibleTemplateTypes) === -1;1637if (isRestrictedValue) {1638errorPossibleTypes.push(TYPES.s);1639
1640//split it into a array which contains all possible values for example: ["y:yes", "n:no", "m:maybe"]1641restrictedStringValuesSplit = currType.split(restrictedStringsSplit);1642errorRestrictedStrings = errorRestrictedStrings.concat(restrictedStringValuesSplit);1643for (v = 0; v < restrictedStringValuesSplit[LEXICON.l]; v++) {1644//split the possible values into their possibiliteis for example: ["y", "yes"] -> the first is always the mainPossibility1645restrictedStringValuesPossibilitiesSplit = restrictedStringValuesSplit[v].split(restrictedStringsPossibilitiesSplit);1646mainPossibility = restrictedStringValuesPossibilitiesSplit[0];1647for (j = 0; j < restrictedStringValuesPossibilitiesSplit[LEXICON.l]; j++) {1648//if any possibility matches with the dataValue, its valid1649if (dataValue === restrictedStringValuesPossibilitiesSplit[j]) {1650isValid = true;1651break;1652}1653}1654if (isValid)1655break;1656}1657}1658else {1659errorPossibleTypes.push(currType);1660
1661if (dataValueType === currType) {1662isValid = true;1663break;1664}1665}1666}1667
1668if (isValid) {1669isDiff = dataValue !== dataDiffValue;1670
1671if (isDiff)1672validatedOptions[prop] = dataValue;1673
1674if (isRestrictedValue ? inArray(dataDiffValue, restrictedStringValuesPossibilitiesSplit) < 0 : isDiff)1675validatedOptionsPrepared[prop] = isRestrictedValue ? mainPossibility : dataValue;1676}1677else if (writeErrors) {1678console.warn(error + " it doesn't accept the type [ " + dataValueType.toUpperCase() + " ] with the value of \"" + dataValue + "\".\r\n" +1679"Accepted types are: [ " + errorPossibleTypes.join(', ').toUpperCase() + " ]." +1680(errorRestrictedStrings[length] > 0 ? "\r\nValid strings are: [ " + errorRestrictedStrings.join(', ').split(restrictedStringsPossibilitiesSplit).join(', ') + " ]." : ''));1681}1682delete data[prop];1683}1684}1685}1686};1687checkObjectProps(objectCopy, template, diffObj || {}, validatedOptions, validatedOptionsPrepared);1688
1689//add values which aren't specified in the template to the finished validated object to prevent them from being discarded1690/*1691if(keepForeignProps) {
1692FRAMEWORK.extend(true, validatedOptions, objectCopy);
1693FRAMEWORK.extend(true, validatedOptionsPrepared, objectCopy);
1694}
1695*/
1696
1697if (!isEmptyObj(objectCopy) && writeErrors)1698console.warn('The following options are discarded due to invalidity:\r\n' + window.JSON.stringify(objectCopy, null, 2));1699
1700return {1701_default: validatedOptions,1702_prepared: validatedOptionsPrepared1703};1704}1705}1706}());1707
1708/**1709* Initializes the object which contains global information about the plugin and each instance of it.
1710*/
1711function initOverlayScrollbarsStatics() {1712if (!_pluginsGlobals)1713_pluginsGlobals = new OverlayScrollbarsGlobals(_pluginsOptions._defaults);1714if (!_pluginsAutoUpdateLoop)1715_pluginsAutoUpdateLoop = new OverlayScrollbarsAutoUpdateLoop(_pluginsGlobals);1716}1717
1718/**1719* 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.
1720* @param defaultOptions
1721* @constructor
1722*/
1723function OverlayScrollbarsGlobals(defaultOptions) {1724var _base = this;1725var strOverflow = 'overflow';1726var strHidden = 'hidden';1727var strScroll = 'scroll';1728var bodyElement = FRAMEWORK('body');1729var scrollbarDummyElement = FRAMEWORK('<div id="os-dummy-scrollbar-size"><div></div></div>');1730var scrollbarDummyElement0 = scrollbarDummyElement[0];1731var dummyContainerChild = FRAMEWORK(scrollbarDummyElement.children('div').eq(0));1732
1733bodyElement.append(scrollbarDummyElement);1734scrollbarDummyElement.hide().show(); //fix IE8 bug (incorrect measuring)1735
1736var nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement0);1737var nativeScrollbarIsOverlaid = {1738x: nativeScrollbarSize.x === 0,1739y: nativeScrollbarSize.y === 01740};1741var msie = (function () {1742var ua = window.navigator.userAgent;1743var strIndexOf = 'indexOf';1744var strSubString = 'substring';1745var msie = ua[strIndexOf]('MSIE ');1746var trident = ua[strIndexOf]('Trident/');1747var edge = ua[strIndexOf]('Edge/');1748var rv = ua[strIndexOf]('rv:');1749var result;1750var parseIntFunc = parseInt;1751
1752// IE 10 or older => return version number1753if (msie > 0)1754result = parseIntFunc(ua[strSubString](msie + 5, ua[strIndexOf]('.', msie)), 10);1755
1756// IE 11 => return version number1757else if (trident > 0)1758result = parseIntFunc(ua[strSubString](rv + 3, ua[strIndexOf]('.', rv)), 10);1759
1760// Edge (IE 12+) => return version number1761else if (edge > 0)1762result = parseIntFunc(ua[strSubString](edge + 5, ua[strIndexOf]('.', edge)), 10);1763
1764// other browser1765return result;1766})();1767
1768FRAMEWORK.extend(_base, {1769defaultOptions: defaultOptions,1770msie: msie,1771autoUpdateLoop: false,1772autoUpdateRecommended: !COMPATIBILITY.mO(),1773nativeScrollbarSize: nativeScrollbarSize,1774nativeScrollbarIsOverlaid: nativeScrollbarIsOverlaid,1775nativeScrollbarStyling: (function () {1776var result = false;1777scrollbarDummyElement.addClass('os-viewport-native-scrollbars-invisible');1778try {1779result = (scrollbarDummyElement.css('scrollbar-width') === 'none' && (msie > 9 || !msie)) || window.getComputedStyle(scrollbarDummyElement0, '::-webkit-scrollbar').getPropertyValue('display') === 'none';1780} catch (ex) { }1781
1782//fix opera bug: scrollbar styles will only appear if overflow value is scroll or auto during the activation of the style.1783//and set overflow to scroll1784//scrollbarDummyElement.css(strOverflow, strHidden).hide().css(strOverflow, strScroll).show();1785//return (scrollbarDummyElement0[LEXICON.oH] - scrollbarDummyElement0[LEXICON.cH]) === 0 && (scrollbarDummyElement0[LEXICON.oW] - scrollbarDummyElement0[LEXICON.cW]) === 0;1786
1787return result;1788})(),1789overlayScrollbarDummySize: { x: 30, y: 30 },1790cssCalc: VENDORS._cssPropertyValue('width', 'calc', '(1px)') || null,1791restrictedMeasuring: (function () {1792//https://bugzilla.mozilla.org/show_bug.cgi?id=14393051793//since 1.11.0 always false -> fixed via CSS (hopefully)1794scrollbarDummyElement.css(strOverflow, strHidden);1795var scrollSize = {1796w: scrollbarDummyElement0[LEXICON.sW],1797h: scrollbarDummyElement0[LEXICON.sH]1798};1799scrollbarDummyElement.css(strOverflow, 'visible');1800var scrollSize2 = {1801w: scrollbarDummyElement0[LEXICON.sW],1802h: scrollbarDummyElement0[LEXICON.sH]1803};1804return (scrollSize.w - scrollSize2.w) !== 0 || (scrollSize.h - scrollSize2.h) !== 0;1805})(),1806rtlScrollBehavior: (function () {1807scrollbarDummyElement.css({ 'overflow-y': strHidden, 'overflow-x': strScroll, 'direction': 'rtl' }).scrollLeft(0);1808var dummyContainerOffset = scrollbarDummyElement.offset();1809var dummyContainerChildOffset = dummyContainerChild.offset();1810//https://github.com/KingSora/OverlayScrollbars/issues/1871811scrollbarDummyElement.scrollLeft(-999);1812var dummyContainerChildOffsetAfterScroll = dummyContainerChild.offset();1813return {1814//origin direction = determines if the zero scroll position is on the left or right side1815//'i' means 'invert' (i === true means that the axis must be inverted to be correct)1816//true = on the left side1817//false = on the right side1818i: dummyContainerOffset.left === dummyContainerChildOffset.left,1819//negative = determines if the maximum scroll is positive or negative1820//'n' means 'negate' (n === true means that the axis must be negated to be correct)1821//true = negative1822//false = positive1823n: dummyContainerChildOffset.left !== dummyContainerChildOffsetAfterScroll.left1824};1825})(),1826supportTransform: !!VENDORS._cssProperty('transform'),1827supportTransition: !!VENDORS._cssProperty('transition'),1828supportPassiveEvents: (function () {1829var supportsPassive = false;1830try {1831window.addEventListener('test', null, Object.defineProperty({}, 'passive', {1832get: function () {1833supportsPassive = true;1834}1835}));1836} catch (e) { }1837return supportsPassive;1838})(),1839supportResizeObserver: !!COMPATIBILITY.rO(),1840supportMutationObserver: !!COMPATIBILITY.mO()1841});1842
1843scrollbarDummyElement.removeAttr(LEXICON.s).remove();1844
1845//Catch zoom event:1846(function () {1847if (nativeScrollbarIsOverlaid.x && nativeScrollbarIsOverlaid.y)1848return;1849
1850var abs = MATH.abs;1851var windowWidth = COMPATIBILITY.wW();1852var windowHeight = COMPATIBILITY.wH();1853var windowDpr = getWindowDPR();1854var onResize = function () {1855if (INSTANCES().length > 0) {1856var newW = COMPATIBILITY.wW();1857var newH = COMPATIBILITY.wH();1858var deltaW = newW - windowWidth;1859var deltaH = newH - windowHeight;1860
1861if (deltaW === 0 && deltaH === 0)1862return;1863
1864var deltaWRatio = MATH.round(newW / (windowWidth / 100.0));1865var deltaHRatio = MATH.round(newH / (windowHeight / 100.0));1866var absDeltaW = abs(deltaW);1867var absDeltaH = abs(deltaH);1868var absDeltaWRatio = abs(deltaWRatio);1869var absDeltaHRatio = abs(deltaHRatio);1870var newDPR = getWindowDPR();1871
1872var deltaIsBigger = absDeltaW > 2 && absDeltaH > 2;1873var difference = !differenceIsBiggerThanOne(absDeltaWRatio, absDeltaHRatio);1874var dprChanged = newDPR !== windowDpr && windowDpr > 0;1875var isZoom = deltaIsBigger && difference && dprChanged;1876var oldScrollbarSize = _base.nativeScrollbarSize;1877var newScrollbarSize;1878
1879if (isZoom) {1880bodyElement.append(scrollbarDummyElement);1881newScrollbarSize = _base.nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement[0]);1882scrollbarDummyElement.remove();1883if (oldScrollbarSize.x !== newScrollbarSize.x || oldScrollbarSize.y !== newScrollbarSize.y) {1884FRAMEWORK.each(INSTANCES(), function () {1885if (INSTANCES(this))1886INSTANCES(this).update('zoom');1887});1888}1889}1890
1891windowWidth = newW;1892windowHeight = newH;1893windowDpr = newDPR;1894}1895};1896
1897function differenceIsBiggerThanOne(valOne, valTwo) {1898var absValOne = abs(valOne);1899var absValTwo = abs(valTwo);1900return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);1901}1902
1903function getWindowDPR() {1904var dDPI = window.screen.deviceXDPI || 0;1905var sDPI = window.screen.logicalXDPI || 1;1906return window.devicePixelRatio || (dDPI / sDPI);1907}1908
1909FRAMEWORK(window).on('resize', onResize);1910})();1911
1912function calcNativeScrollbarSize(measureElement) {1913return {1914x: measureElement[LEXICON.oH] - measureElement[LEXICON.cH],1915y: measureElement[LEXICON.oW] - measureElement[LEXICON.cW]1916};1917}1918}1919
1920/**1921* 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.
1922* @constructor
1923*/
1924function OverlayScrollbarsAutoUpdateLoop(globals) {1925var _base = this;1926var _inArray = FRAMEWORK.inArray;1927var _getNow = COMPATIBILITY.now;1928var _strAutoUpdate = 'autoUpdate';1929var _strAutoUpdateInterval = _strAutoUpdate + 'Interval';1930var _strLength = LEXICON.l;1931var _loopingInstances = [];1932var _loopingInstancesIntervalCache = [];1933var _loopIsActive = false;1934var _loopIntervalDefault = 33;1935var _loopInterval = _loopIntervalDefault;1936var _loopTimeOld = _getNow();1937var _loopID;1938
1939
1940/**1941* The auto update loop which will run every 50 milliseconds or less if the update interval of a instance is lower than 50 milliseconds.
1942*/
1943var loop = function () {1944if (_loopingInstances[_strLength] > 0 && _loopIsActive) {1945_loopID = COMPATIBILITY.rAF()(function () {1946loop();1947});1948var timeNew = _getNow();1949var timeDelta = timeNew - _loopTimeOld;1950var lowestInterval;1951var instance;1952var instanceOptions;1953var instanceAutoUpdateAllowed;1954var instanceAutoUpdateInterval;1955var now;1956
1957if (timeDelta > _loopInterval) {1958_loopTimeOld = timeNew - (timeDelta % _loopInterval);1959lowestInterval = _loopIntervalDefault;1960for (var i = 0; i < _loopingInstances[_strLength]; i++) {1961instance = _loopingInstances[i];1962if (instance !== undefined) {1963instanceOptions = instance.options();1964instanceAutoUpdateAllowed = instanceOptions[_strAutoUpdate];1965instanceAutoUpdateInterval = MATH.max(1, instanceOptions[_strAutoUpdateInterval]);1966now = _getNow();1967
1968if ((instanceAutoUpdateAllowed === true || instanceAutoUpdateAllowed === null) && (now - _loopingInstancesIntervalCache[i]) > instanceAutoUpdateInterval) {1969instance.update('auto');1970_loopingInstancesIntervalCache[i] = new Date(now += instanceAutoUpdateInterval);1971}1972
1973lowestInterval = MATH.max(1, MATH.min(lowestInterval, instanceAutoUpdateInterval));1974}1975}1976_loopInterval = lowestInterval;1977}1978} else {1979_loopInterval = _loopIntervalDefault;1980}1981};1982
1983/**1984* Add OverlayScrollbars instance to the auto update loop. Only successful if the instance isn't already added.
1985* @param instance The instance which shall be updated in a loop automatically.
1986*/
1987_base.add = function (instance) {1988if (_inArray(instance, _loopingInstances) === -1) {1989_loopingInstances.push(instance);1990_loopingInstancesIntervalCache.push(_getNow());1991if (_loopingInstances[_strLength] > 0 && !_loopIsActive) {1992_loopIsActive = true;1993globals.autoUpdateLoop = _loopIsActive;1994loop();1995}1996}1997};1998
1999/**2000* Remove OverlayScrollbars instance from the auto update loop. Only successful if the instance was added before.
2001* @param instance The instance which shall be updated in a loop automatically.
2002*/
2003_base.remove = function (instance) {2004var index = _inArray(instance, _loopingInstances);2005if (index > -1) {2006//remove from loopingInstances list2007_loopingInstancesIntervalCache.splice(index, 1);2008_loopingInstances.splice(index, 1);2009
2010//correct update loop behavior2011if (_loopingInstances[_strLength] === 0 && _loopIsActive) {2012_loopIsActive = false;2013globals.autoUpdateLoop = _loopIsActive;2014if (_loopID !== undefined) {2015COMPATIBILITY.cAF()(_loopID);2016_loopID = -1;2017}2018}2019}2020};2021}2022
2023/**2024* A object which manages the scrollbars visibility of the target element.
2025* @param pluginTargetElement The element from which the scrollbars shall be hidden.
2026* @param options The custom options.
2027* @param extensions The custom extensions.
2028* @param globals
2029* @param autoUpdateLoop
2030* @returns {*}
2031* @constructor
2032*/
2033function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) {2034//shortcuts2035var type = COMPATIBILITY.type;2036var inArray = FRAMEWORK.inArray;2037var each = FRAMEWORK.each;2038
2039//make correct instanceof2040var _base = new _plugin();2041var _frameworkProto = FRAMEWORK[LEXICON.p];2042
2043//if passed element is no HTML element: skip and return2044if (!isHTMLElement(pluginTargetElement))2045return;2046
2047//if passed element is already initialized: set passed options if there are any and return its instance2048if (INSTANCES(pluginTargetElement)) {2049var inst = INSTANCES(pluginTargetElement);2050inst.options(options);2051return inst;2052}2053
2054//globals:2055var _nativeScrollbarIsOverlaid;2056var _overlayScrollbarDummySize;2057var _rtlScrollBehavior;2058var _autoUpdateRecommended;2059var _msieVersion;2060var _nativeScrollbarStyling;2061var _cssCalc;2062var _nativeScrollbarSize;2063var _supportTransition;2064var _supportTransform;2065var _supportPassiveEvents;2066var _supportResizeObserver;2067var _supportMutationObserver;2068var _restrictedMeasuring;2069
2070//general readonly:2071var _initialized;2072var _destroyed;2073var _isTextarea;2074var _isBody;2075var _documentMixed;2076var _domExists;2077
2078//general:2079var _isBorderBox;2080var _sizeAutoObserverAdded;2081var _paddingX;2082var _paddingY;2083var _borderX;2084var _borderY;2085var _marginX;2086var _marginY;2087var _isRTL;2088var _sleeping;2089var _contentBorderSize = {};2090var _scrollHorizontalInfo = {};2091var _scrollVerticalInfo = {};2092var _viewportSize = {};2093var _nativeScrollbarMinSize = {};2094
2095//naming:2096var _strMinusHidden = '-hidden';2097var _strMarginMinus = 'margin-';2098var _strPaddingMinus = 'padding-';2099var _strBorderMinus = 'border-';2100var _strTop = 'top';2101var _strRight = 'right';2102var _strBottom = 'bottom';2103var _strLeft = 'left';2104var _strMinMinus = 'min-';2105var _strMaxMinus = 'max-';2106var _strWidth = 'width';2107var _strHeight = 'height';2108var _strFloat = 'float';2109var _strEmpty = '';2110var _strAuto = 'auto';2111var _strSync = 'sync';2112var _strScroll = 'scroll';2113var _strHundredPercent = '100%';2114var _strX = 'x';2115var _strY = 'y';2116var _strDot = '.';2117var _strSpace = ' ';2118var _strScrollbar = 'scrollbar';2119var _strMinusHorizontal = '-horizontal';2120var _strMinusVertical = '-vertical';2121var _strScrollLeft = _strScroll + 'Left';2122var _strScrollTop = _strScroll + 'Top';2123var _strMouseTouchDownEvent = 'mousedown touchstart';2124var _strMouseTouchUpEvent = 'mouseup touchend touchcancel';2125var _strMouseTouchMoveEvent = 'mousemove touchmove';2126var _strMouseEnter = 'mouseenter';2127var _strMouseLeave = 'mouseleave';2128var _strKeyDownEvent = 'keydown';2129var _strKeyUpEvent = 'keyup';2130var _strSelectStartEvent = 'selectstart';2131var _strTransitionEndEvent = 'transitionend webkitTransitionEnd oTransitionEnd';2132var _strResizeObserverProperty = '__overlayScrollbarsRO__';2133
2134//class names:2135var _cassNamesPrefix = 'os-';2136var _classNameHTMLElement = _cassNamesPrefix + 'html';2137var _classNameHostElement = _cassNamesPrefix + 'host';2138var _classNameHostElementForeign = _classNameHostElement + '-foreign';2139var _classNameHostTextareaElement = _classNameHostElement + '-textarea';2140var _classNameHostScrollbarHorizontalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusHorizontal + _strMinusHidden;2141var _classNameHostScrollbarVerticalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusVertical + _strMinusHidden;2142var _classNameHostTransition = _classNameHostElement + '-transition';2143var _classNameHostRTL = _classNameHostElement + '-rtl';2144var _classNameHostResizeDisabled = _classNameHostElement + '-resize-disabled';2145var _classNameHostScrolling = _classNameHostElement + '-scrolling';2146var _classNameHostOverflow = _classNameHostElement + '-overflow';2147var _classNameHostOverflow = _classNameHostElement + '-overflow';2148var _classNameHostOverflowX = _classNameHostOverflow + '-x';2149var _classNameHostOverflowY = _classNameHostOverflow + '-y';2150var _classNameTextareaElement = _cassNamesPrefix + 'textarea';2151var _classNameTextareaCoverElement = _classNameTextareaElement + '-cover';2152var _classNamePaddingElement = _cassNamesPrefix + 'padding';2153var _classNameViewportElement = _cassNamesPrefix + 'viewport';2154var _classNameViewportNativeScrollbarsInvisible = _classNameViewportElement + '-native-scrollbars-invisible';2155var _classNameViewportNativeScrollbarsOverlaid = _classNameViewportElement + '-native-scrollbars-overlaid';2156var _classNameContentElement = _cassNamesPrefix + 'content';2157var _classNameContentArrangeElement = _cassNamesPrefix + 'content-arrange';2158var _classNameContentGlueElement = _cassNamesPrefix + 'content-glue';2159var _classNameSizeAutoObserverElement = _cassNamesPrefix + 'size-auto-observer';2160var _classNameResizeObserverElement = _cassNamesPrefix + 'resize-observer';2161var _classNameResizeObserverItemElement = _cassNamesPrefix + 'resize-observer-item';2162var _classNameResizeObserverItemFinalElement = _classNameResizeObserverItemElement + '-final';2163var _classNameTextInherit = _cassNamesPrefix + 'text-inherit';2164var _classNameScrollbar = _cassNamesPrefix + _strScrollbar;2165var _classNameScrollbarTrack = _classNameScrollbar + '-track';2166var _classNameScrollbarTrackOff = _classNameScrollbarTrack + '-off';2167var _classNameScrollbarHandle = _classNameScrollbar + '-handle';2168var _classNameScrollbarHandleOff = _classNameScrollbarHandle + '-off';2169var _classNameScrollbarUnusable = _classNameScrollbar + '-unusable';2170var _classNameScrollbarAutoHidden = _classNameScrollbar + '-' + _strAuto + _strMinusHidden;2171var _classNameScrollbarCorner = _classNameScrollbar + '-corner';2172var _classNameScrollbarCornerResize = _classNameScrollbarCorner + '-resize';2173var _classNameScrollbarCornerResizeB = _classNameScrollbarCornerResize + '-both';2174var _classNameScrollbarCornerResizeH = _classNameScrollbarCornerResize + _strMinusHorizontal;2175var _classNameScrollbarCornerResizeV = _classNameScrollbarCornerResize + _strMinusVertical;2176var _classNameScrollbarHorizontal = _classNameScrollbar + _strMinusHorizontal;2177var _classNameScrollbarVertical = _classNameScrollbar + _strMinusVertical;2178var _classNameDragging = _cassNamesPrefix + 'dragging';2179var _classNameThemeNone = _cassNamesPrefix + 'theme-none';2180var _classNamesDynamicDestroy = [2181_classNameViewportNativeScrollbarsInvisible,2182_classNameViewportNativeScrollbarsOverlaid,2183_classNameScrollbarTrackOff,2184_classNameScrollbarHandleOff,2185_classNameScrollbarUnusable,2186_classNameScrollbarAutoHidden,2187_classNameScrollbarCornerResize,2188_classNameScrollbarCornerResizeB,2189_classNameScrollbarCornerResizeH,2190_classNameScrollbarCornerResizeV,2191_classNameDragging].join(_strSpace);2192
2193//callbacks:2194var _callbacksInitQeueue = [];2195
2196//attrs viewport shall inherit from target2197var _viewportAttrsFromTarget = [LEXICON.ti];2198
2199//options:2200var _defaultOptions;2201var _currentOptions;2202var _currentPreparedOptions;2203
2204//extensions:2205var _extensions = {};2206var _extensionsPrivateMethods = 'added removed on contract';2207
2208//update2209var _lastUpdateTime;2210var _swallowedUpdateHints = {};2211var _swallowedUpdateTimeout;2212var _swallowUpdateLag = 42;2213var _updateOnLoadEventName = 'load';2214var _updateOnLoadElms = [];2215
2216//DOM elements:2217var _windowElement;2218var _documentElement;2219var _htmlElement;2220var _bodyElement;2221var _targetElement; //the target element of this OverlayScrollbars object2222var _hostElement; //the host element of this OverlayScrollbars object -> may be the same as targetElement2223var _sizeAutoObserverElement; //observes size auto changes2224var _sizeObserverElement; //observes size and padding changes2225var _paddingElement; //manages the padding2226var _viewportElement; //is the viewport of our scrollbar model2227var _contentElement; //the element which holds the content2228var _contentArrangeElement; //is needed for correct sizing of the content element (only if native scrollbars are overlays)2229var _contentGlueElement; //has always the size of the content element2230var _textareaCoverElement; //only applied if target is a textarea element. Used for correct size calculation and for prevention of uncontrolled scrolling2231var _scrollbarCornerElement;2232var _scrollbarHorizontalElement;2233var _scrollbarHorizontalTrackElement;2234var _scrollbarHorizontalHandleElement;2235var _scrollbarVerticalElement;2236var _scrollbarVerticalTrackElement;2237var _scrollbarVerticalHandleElement;2238var _windowElementNative;2239var _documentElementNative;2240var _targetElementNative;2241var _hostElementNative;2242var _sizeAutoObserverElementNative;2243var _sizeObserverElementNative;2244var _paddingElementNative;2245var _viewportElementNative;2246var _contentElementNative;2247
2248//Cache:2249var _hostSizeCache;2250var _contentScrollSizeCache;2251var _arrangeContentSizeCache;2252var _hasOverflowCache;2253var _hideOverflowCache;2254var _widthAutoCache;2255var _heightAutoCache;2256var _cssBoxSizingCache;2257var _cssPaddingCache;2258var _cssBorderCache;2259var _cssMarginCache;2260var _cssDirectionCache;2261var _cssDirectionDetectedCache;2262var _paddingAbsoluteCache;2263var _clipAlwaysCache;2264var _contentGlueSizeCache;2265var _overflowBehaviorCache;2266var _overflowAmountCache;2267var _ignoreOverlayScrollbarHidingCache;2268var _autoUpdateCache;2269var _sizeAutoCapableCache;2270var _contentElementScrollSizeChangeDetectedCache;2271var _hostElementSizeChangeDetectedCache;2272var _scrollbarsVisibilityCache;2273var _scrollbarsAutoHideCache;2274var _scrollbarsClickScrollingCache;2275var _scrollbarsDragScrollingCache;2276var _resizeCache;2277var _normalizeRTLCache;2278var _classNameCache;2279var _oldClassName;2280var _textareaAutoWrappingCache;2281var _textareaInfoCache;2282var _textareaSizeCache;2283var _textareaDynHeightCache;2284var _textareaDynWidthCache;2285var _bodyMinSizeCache;2286var _updateAutoCache = {};2287
2288//MutationObserver:2289var _mutationObserverHost;2290var _mutationObserverContent;2291var _mutationObserverHostCallback;2292var _mutationObserverContentCallback;2293var _mutationObserversConnected;2294var _mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows'];2295var _mutationObserverAttrsHost = [LEXICON.i, LEXICON.c, LEXICON.s, 'open'].concat(_viewportAttrsFromTarget);2296
2297//events:2298var _destroyEvents = [];2299
2300//textarea:2301var _textareaHasFocus;2302
2303//scrollbars:2304var _scrollbarsAutoHideTimeoutId;2305var _scrollbarsAutoHideMoveTimeoutId;2306var _scrollbarsAutoHideDelay;2307var _scrollbarsAutoHideNever;2308var _scrollbarsAutoHideScroll;2309var _scrollbarsAutoHideMove;2310var _scrollbarsAutoHideLeave;2311var _scrollbarsHandleHovered;2312var _scrollbarsHandlesDefineScrollPos;2313
2314//resize2315var _resizeNone;2316var _resizeBoth;2317var _resizeHorizontal;2318var _resizeVertical;2319
2320
2321//==== Event Listener ====//2322
2323/**2324* Adds or removes a event listener from the given element.
2325* @param element The element to which the event listener shall be applied or removed.
2326* @param eventNames The name(s) of the events.
2327* @param listener The method which shall be called.
2328* @param remove True if the handler shall be removed, false or undefined if the handler shall be added.
2329* @param passiveOrOptions The options for the event.
2330*/
2331function setupResponsiveEventListener(element, eventNames, listener, remove, passiveOrOptions) {2332var collected = COMPATIBILITY.isA(eventNames) && COMPATIBILITY.isA(listener);2333var method = remove ? 'removeEventListener' : 'addEventListener';2334var onOff = remove ? 'off' : 'on';2335var events = collected ? false : eventNames.split(_strSpace)2336var i = 0;2337
2338var passiveOrOptionsIsObj = FRAMEWORK.isPlainObject(passiveOrOptions);2339var passive = (_supportPassiveEvents && (passiveOrOptionsIsObj ? (passiveOrOptions._passive) : passiveOrOptions)) || false;2340var capture = passiveOrOptionsIsObj && (passiveOrOptions._capture || false);2341var nativeParam = _supportPassiveEvents ? {2342passive: passive,2343capture: capture,2344} : capture;2345
2346if (collected) {2347for (; i < eventNames[LEXICON.l]; i++)2348setupResponsiveEventListener(element, eventNames[i], listener[i], remove, passiveOrOptions);2349}2350else {2351for (; i < events[LEXICON.l]; i++) {2352if(_supportPassiveEvents) {2353element[0][method](events[i], listener, nativeParam);2354}2355else {2356element[onOff](events[i], listener);2357}2358}2359}2360}2361
2362
2363function addDestroyEventListener(element, eventNames, listener, passive) {2364setupResponsiveEventListener(element, eventNames, listener, false, passive);2365_destroyEvents.push(COMPATIBILITY.bind(setupResponsiveEventListener, 0, element, eventNames, listener, true, passive));2366}2367
2368//==== Resize Observer ====//2369
2370/**2371* Adds or removes a resize observer from the given element.
2372* @param targetElement The element to which the resize observer shall be added or removed.
2373* @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.
2374*/
2375function setupResizeObserver(targetElement, onElementResizedCallback) {2376if (targetElement) {2377var resizeObserver = COMPATIBILITY.rO();2378var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart';2379var strChildNodes = 'childNodes';2380var constScroll = 3333333;2381var callback = function () {2382targetElement[_strScrollTop](constScroll)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll : constScroll);2383onElementResizedCallback();2384};2385//add resize observer:2386if (onElementResizedCallback) {2387if (_supportResizeObserver) {2388var element = targetElement.addClass('observed').append(generateDiv(_classNameResizeObserverElement)).contents()[0];2389var observer = element[_strResizeObserverProperty] = new resizeObserver(callback);2390observer.observe(element);2391}2392else {2393if (_msieVersion > 9 || !_autoUpdateRecommended) {2394targetElement.prepend(2395generateDiv(_classNameResizeObserverElement,2396generateDiv({ c: _classNameResizeObserverItemElement, dir: 'ltr' },2397generateDiv(_classNameResizeObserverItemElement,2398generateDiv(_classNameResizeObserverItemFinalElement)2399) +2400generateDiv(_classNameResizeObserverItemElement,2401generateDiv({ c: _classNameResizeObserverItemFinalElement, style: 'width: 200%; height: 200%' })2402)2403)2404)2405);2406
2407var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0];2408var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]);2409var expandElement = FRAMEWORK(observerElement[strChildNodes][0]);2410var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]);2411var widthCache = observerElement[LEXICON.oW];2412var heightCache = observerElement[LEXICON.oH];2413var isDirty;2414var rAFId;2415var currWidth;2416var currHeight;2417var factor = 2;2418var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!!2419var reset = function () {2420/*2421var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
2422var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
2423var expandChildCSS = {};
2424expandChildCSS[_strWidth] = sizeResetWidth;
2425expandChildCSS[_strHeight] = sizeResetHeight;
2426expandElementChild.css(expandChildCSS);
2427
2428
2429expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
2430shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
2431*/
2432expandElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);2433shrinkElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);2434};2435var onResized = function () {2436rAFId = 0;2437if (!isDirty)2438return;2439
2440widthCache = currWidth;2441heightCache = currHeight;2442callback();2443};2444var onScroll = function (event) {2445currWidth = observerElement[LEXICON.oW];2446currHeight = observerElement[LEXICON.oH];2447isDirty = currWidth != widthCache || currHeight != heightCache;2448
2449if (event && isDirty && !rAFId) {2450COMPATIBILITY.cAF()(rAFId);2451rAFId = COMPATIBILITY.rAF()(onResized);2452}2453else if (!event)2454onResized();2455
2456reset();2457if (event) {2458COMPATIBILITY.prvD(event);2459COMPATIBILITY.stpP(event);2460}2461return false;2462};2463var expandChildCSS = {};2464var observerElementCSS = {};2465
2466setTopRightBottomLeft(observerElementCSS, _strEmpty, [2467-((nativeScrollbarSize.y + 1) * factor),2468nativeScrollbarSize.x * -factor,2469nativeScrollbarSize.y * -factor,2470-((nativeScrollbarSize.x + 1) * factor)2471]);2472
2473FRAMEWORK(observerElement).css(observerElementCSS);2474expandElement.on(_strScroll, onScroll);2475shrinkElement.on(_strScroll, onScroll);2476targetElement.on(strAnimationStartEvent, function () {2477onScroll(false);2478});2479//lets assume that the divs will never be that large and a constant value is enough2480expandChildCSS[_strWidth] = constScroll;2481expandChildCSS[_strHeight] = constScroll;2482expandElementChild.css(expandChildCSS);2483
2484reset();2485}2486else {2487var attachEvent = _documentElementNative.attachEvent;2488var isIE = _msieVersion !== undefined;2489if (attachEvent) {2490targetElement.prepend(generateDiv(_classNameResizeObserverElement));2491findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback);2492}2493else {2494var obj = _documentElementNative.createElement(TYPES.o);2495obj.setAttribute(LEXICON.ti, '-1');2496obj.setAttribute(LEXICON.c, _classNameResizeObserverElement);2497obj.onload = function () {2498var wnd = this.contentDocument.defaultView;2499wnd.addEventListener('resize', callback);2500wnd.document.documentElement.style.display = 'none';2501};2502obj.type = 'text/html';2503if (isIE)2504targetElement.prepend(obj);2505obj.data = 'about:blank';2506if (!isIE)2507targetElement.prepend(obj);2508targetElement.on(strAnimationStartEvent, callback);2509}2510}2511}2512
2513if (targetElement[0] === _sizeObserverElementNative) {2514var directionChanged = function () {2515var dir = _hostElement.css('direction');2516var css = {};2517var scrollLeftValue = 0;2518var result = false;2519if (dir !== _cssDirectionDetectedCache) {2520if (dir === 'ltr') {2521css[_strLeft] = 0;2522css[_strRight] = _strAuto;2523scrollLeftValue = constScroll;2524}2525else {2526css[_strLeft] = _strAuto;2527css[_strRight] = 0;2528scrollLeftValue = _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll;2529}2530//execution order is important for IE!!!2531_sizeObserverElement.children().eq(0).css(css);2532_sizeObserverElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constScroll);2533_cssDirectionDetectedCache = dir;2534result = true;2535}2536return result;2537};2538directionChanged();2539addDestroyEventListener(targetElement, _strScroll, function (event) {2540if (directionChanged())2541update();2542COMPATIBILITY.prvD(event);2543COMPATIBILITY.stpP(event);2544return false;2545});2546}2547}2548//remove resize observer:2549else {2550if (_supportResizeObserver) {2551var element = targetElement.contents()[0];2552var resizeObserverObj = element[_strResizeObserverProperty];2553if (resizeObserverObj) {2554resizeObserverObj.disconnect();2555delete element[_strResizeObserverProperty];2556}2557}2558else {2559remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0));2560}2561}2562}2563}2564
2565/**2566* Freezes or unfreezes the given resize observer.
2567* @param targetElement The element to which the target resize observer is applied.
2568* @param freeze True if the resize observer shall be frozen, false otherwise.
2569
2570function freezeResizeObserver(targetElement, freeze) {
2571if (targetElement !== undefined) {
2572if(freeze) {
2573if (_supportResizeObserver) {
2574var element = targetElement.contents()[0];
2575element[_strResizeObserverProperty].unobserve(element);
2576}
2577else {
2578targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0);
2579var w = targetElement.css(_strWidth);
2580var h = targetElement.css(_strHeight);
2581var css = {};
2582css[_strWidth] = w;
2583css[_strHeight] = h;
2584targetElement.css(css);
2585}
2586}
2587else {
2588if (_supportResizeObserver) {
2589var element = targetElement.contents()[0];
2590element[_strResizeObserverProperty].observe(element);
2591}
2592else {
2593var css = { };
2594css[_strHeight] = _strEmpty;
2595css[_strWidth] = _strEmpty;
2596targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css);
2597}
2598}
2599}
2600}
2601*/
2602
2603
2604//==== Mutation Observers ====//2605
2606/**2607* Creates MutationObservers for the host and content Element if they are supported.
2608*/
2609function createMutationObservers() {2610if (_supportMutationObserver) {2611var mutationObserverContentLag = 11;2612var mutationObserver = COMPATIBILITY.mO();2613var contentLastUpdate = COMPATIBILITY.now();2614var mutationTarget;2615var mutationAttrName;2616var mutationIsClass;2617var oldMutationVal;2618var newClassVal;2619var hostClassNameRegex;2620var contentTimeout;2621var now;2622var sizeAuto;2623var action;2624
2625_mutationObserverHostCallback = function (mutations) {2626
2627var doUpdate = false;2628var doUpdateForce = false;2629var mutation;2630var mutatedAttrs = [];2631
2632if (_initialized && !_sleeping) {2633each(mutations, function () {2634mutation = this;2635mutationTarget = mutation.target;2636mutationAttrName = mutation.attributeName;2637mutationIsClass = mutationAttrName === LEXICON.c;2638oldMutationVal = mutation.oldValue;2639newClassVal = mutationTarget.className;2640
2641if (_domExists && mutationIsClass && !doUpdateForce) {2642// if old class value contains _classNameHostElementForeign and new class value doesn't2643if (oldMutationVal.indexOf(_classNameHostElementForeign) > -1 && newClassVal.indexOf(_classNameHostElementForeign) < 0) {2644hostClassNameRegex = createHostClassNameRegExp(true);2645_hostElementNative.className = newClassVal.split(_strSpace).concat(oldMutationVal.split(_strSpace).filter(function (name) {2646return name.match(hostClassNameRegex);2647})).join(_strSpace);2648doUpdate = doUpdateForce = true;2649}2650}2651
2652if (!doUpdate) {2653doUpdate = mutationIsClass2654? hostClassNamesChanged(oldMutationVal, newClassVal)2655: mutationAttrName === LEXICON.s2656? oldMutationVal !== mutationTarget[LEXICON.s].cssText2657: true;2658}2659
2660mutatedAttrs.push(mutationAttrName);2661});2662
2663updateViewportAttrsFromTarget(mutatedAttrs);2664
2665if (doUpdate)2666_base.update(doUpdateForce || _strAuto);2667}2668return doUpdate;2669};2670_mutationObserverContentCallback = function (mutations) {2671var doUpdate = false;2672var mutation;2673
2674if (_initialized && !_sleeping) {2675each(mutations, function () {2676mutation = this;2677doUpdate = isUnknownMutation(mutation);2678return !doUpdate;2679});2680
2681if (doUpdate) {2682now = COMPATIBILITY.now();2683sizeAuto = (_heightAutoCache || _widthAutoCache);2684action = function () {2685if (!_destroyed) {2686contentLastUpdate = now;2687
2688//if cols, rows or wrap attr was changed2689if (_isTextarea)2690textareaUpdate();2691
2692if (sizeAuto)2693update();2694else2695_base.update(_strAuto);2696}2697};2698clearTimeout(contentTimeout);2699if (mutationObserverContentLag <= 0 || now - contentLastUpdate > mutationObserverContentLag || !sizeAuto)2700action();2701else2702contentTimeout = setTimeout(action, mutationObserverContentLag);2703}2704}2705return doUpdate;2706}2707
2708_mutationObserverHost = new mutationObserver(_mutationObserverHostCallback);2709_mutationObserverContent = new mutationObserver(_mutationObserverContentCallback);2710}2711}2712
2713/**2714* Connects the MutationObservers if they are supported.
2715*/
2716function connectMutationObservers() {2717if (_supportMutationObserver && !_mutationObserversConnected) {2718_mutationObserverHost.observe(_hostElementNative, {2719attributes: true,2720attributeOldValue: true,2721attributeFilter: _mutationObserverAttrsHost2722});2723
2724_mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, {2725attributes: true,2726attributeOldValue: true,2727subtree: !_isTextarea,2728childList: !_isTextarea,2729characterData: !_isTextarea,2730attributeFilter: _isTextarea ? _mutationObserverAttrsTextarea : _mutationObserverAttrsHost2731});2732
2733_mutationObserversConnected = true;2734}2735}2736
2737/**2738* Disconnects the MutationObservers if they are supported.
2739*/
2740function disconnectMutationObservers() {2741if (_supportMutationObserver && _mutationObserversConnected) {2742_mutationObserverHost.disconnect();2743_mutationObserverContent.disconnect();2744
2745_mutationObserversConnected = false;2746}2747}2748
2749
2750//==== Events of elements ====//2751
2752/**2753* This method gets called every time the host element gets resized. IMPORTANT: Padding changes are detected too!!
2754* It refreshes the hostResizedEventArgs and the hostSizeResizeCache.
2755* If there are any size changes, the update method gets called.
2756*/
2757function hostOnResized() {2758if (!_sleeping) {2759var changed;2760var hostSize = {2761w: _sizeObserverElementNative[LEXICON.sW],2762h: _sizeObserverElementNative[LEXICON.sH]2763};2764
2765changed = checkCache(hostSize, _hostElementSizeChangeDetectedCache);2766_hostElementSizeChangeDetectedCache = hostSize;2767if (changed)2768update({ _hostSizeChanged: true });2769}2770}2771
2772/**2773* The mouse enter event of the host element. This event is only needed for the autoHide feature.
2774*/
2775function hostOnMouseEnter() {2776if (_scrollbarsAutoHideLeave)2777refreshScrollbarsAutoHide(true);2778}2779
2780/**2781* The mouse leave event of the host element. This event is only needed for the autoHide feature.
2782*/
2783function hostOnMouseLeave() {2784if (_scrollbarsAutoHideLeave && !_bodyElement.hasClass(_classNameDragging))2785refreshScrollbarsAutoHide(false);2786}2787
2788/**2789* The mouse move event of the host element. This event is only needed for the autoHide "move" feature.
2790*/
2791function hostOnMouseMove() {2792if (_scrollbarsAutoHideMove) {2793refreshScrollbarsAutoHide(true);2794clearTimeout(_scrollbarsAutoHideMoveTimeoutId);2795_scrollbarsAutoHideMoveTimeoutId = setTimeout(function () {2796if (_scrollbarsAutoHideMove && !_destroyed)2797refreshScrollbarsAutoHide(false);2798}, 100);2799}2800}2801
2802/**2803* Prevents text from deselection if attached to the document element on the mousedown event of a DOM element.
2804* @param event The select start event.
2805*/
2806function documentOnSelectStart(event) {2807COMPATIBILITY.prvD(event);2808return false;2809}2810
2811/**2812* A callback which will be called after a element has loaded.
2813*/
2814function updateOnLoadCallback(event) {2815var elm = FRAMEWORK(event.target);2816
2817eachUpdateOnLoad(function (i, updateOnLoadSelector) {2818if (elm.is(updateOnLoadSelector)) {2819update({ _contentSizeChanged: true });2820}2821});2822}2823
2824/**2825* Adds or removes mouse & touch events of the host element. (for handling auto-hiding of the scrollbars)
2826* @param destroy Indicates whether the events shall be added or removed.
2827*/
2828function setupHostMouseTouchEvents(destroy) {2829if (!destroy)2830setupHostMouseTouchEvents(true);2831
2832setupResponsiveEventListener(_hostElement,2833_strMouseTouchMoveEvent.split(_strSpace)[0],2834hostOnMouseMove,2835(!_scrollbarsAutoHideMove || destroy), true);2836setupResponsiveEventListener(_hostElement,2837[_strMouseEnter, _strMouseLeave],2838[hostOnMouseEnter, hostOnMouseLeave],2839(!_scrollbarsAutoHideLeave || destroy), true);2840
2841//if the plugin is initialized and the mouse is over the host element, make the scrollbars visible2842if (!_initialized && !destroy)2843_hostElement.one('mouseover', hostOnMouseEnter);2844}2845
2846
2847//==== Update Detection ====//2848
2849/**2850* Measures the min width and min height of the body element and refreshes the related cache.
2851* @returns {boolean} True if the min width or min height has changed, false otherwise.
2852*/
2853function bodyMinSizeChanged() {2854var bodyMinSize = {};2855if (_isBody && _contentArrangeElement) {2856bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth));2857bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight));2858bodyMinSize.c = checkCache(bodyMinSize, _bodyMinSizeCache);2859bodyMinSize.f = true; //flag for "measured at least once"2860}2861_bodyMinSizeCache = bodyMinSize;2862return !!bodyMinSize.c;2863}2864
2865/**2866* Returns true if the class names really changed (new class without plugin host prefix)
2867* @param oldClassNames The old ClassName string or array.
2868* @param newClassNames The new ClassName string or array.
2869* @returns {boolean} True if the class names has really changed, false otherwise.
2870*/
2871function hostClassNamesChanged(oldClassNames, newClassNames) {2872var currClasses = typeof newClassNames == TYPES.s ? newClassNames.split(_strSpace) : [];2873var oldClasses = typeof oldClassNames == TYPES.s ? oldClassNames.split(_strSpace) : [];2874var diff = getArrayDifferences(oldClasses, currClasses);2875
2876// remove none theme from diff list to prevent update2877var idx = inArray(_classNameThemeNone, diff);2878var i;2879var regex;2880
2881if (idx > -1)2882diff.splice(idx, 1);2883
2884if (diff[LEXICON.l] > 0) {2885regex = createHostClassNameRegExp(true, true);2886for (i = 0; i < diff.length; i++) {2887if (!diff[i].match(regex)) {2888return true;2889}2890}2891}2892return false;2893}2894
2895/**2896* 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.
2897* @param mutation The mutation which shall be checked.
2898* @returns {boolean} True if the mutation is from a unknown element, false otherwise.
2899*/
2900function isUnknownMutation(mutation) {2901var attributeName = mutation.attributeName;2902var mutationTarget = mutation.target;2903var mutationType = mutation.type;2904var strClosest = 'closest';2905
2906if (mutationTarget === _contentElementNative)2907return attributeName === null;2908if (mutationType === 'attributes' && (attributeName === LEXICON.c || attributeName === LEXICON.s) && !_isTextarea) {2909//ignore className changes by the plugin2910if (attributeName === LEXICON.c && FRAMEWORK(mutationTarget).hasClass(_classNameHostElement))2911return hostClassNamesChanged(mutation.oldValue, mutationTarget.className);2912
2913//only do it of browser support it natively2914if (typeof mutationTarget[strClosest] != TYPES.f)2915return true;2916if (mutationTarget[strClosest](_strDot + _classNameResizeObserverElement) !== null ||2917mutationTarget[strClosest](_strDot + _classNameScrollbar) !== null ||2918mutationTarget[strClosest](_strDot + _classNameScrollbarCorner) !== null)2919return false;2920}2921return true;2922}2923
2924/**2925* Returns true if the content size was changed since the last time this method was called.
2926* @returns {boolean} True if the content size was changed, false otherwise.
2927*/
2928function updateAutoContentSizeChanged() {2929if (_sleeping)2930return false;2931
2932var contentMeasureElement = getContentMeasureElement();2933var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0;2934var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea;2935var css = {};2936var float;2937var bodyMinSizeC;2938var changed;2939var contentElementScrollSize;2940
2941if (setCSS) {2942float = _contentElement.css(_strFloat);2943css[_strFloat] = _isRTL ? _strRight : _strLeft;2944css[_strWidth] = _strAuto;2945_contentElement.css(css);2946}2947contentElementScrollSize = {2948w: contentMeasureElement[LEXICON.sW] + textareaValueLength,2949h: contentMeasureElement[LEXICON.sH] + textareaValueLength2950};2951if (setCSS) {2952css[_strFloat] = float;2953css[_strWidth] = _strHundredPercent;2954_contentElement.css(css);2955}2956
2957bodyMinSizeC = bodyMinSizeChanged();2958changed = checkCache(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache);2959
2960_contentElementScrollSizeChangeDetectedCache = contentElementScrollSize;2961
2962return changed || bodyMinSizeC;2963}2964
2965/**2966* Returns true when a attribute which the MutationObserver would observe has changed.
2967* @returns {boolean} True if one of the attributes which a MutationObserver would observe has changed, false or undefined otherwise.
2968*/
2969function meaningfulAttrsChanged() {2970if (_sleeping || _mutationObserversConnected)2971return;2972
2973var elem;2974var curr;2975var cache;2976var changedAttrs = [];2977var checks = [2978{2979_elem: _hostElement,2980_attrs: _mutationObserverAttrsHost.concat(':visible')2981},2982{2983_elem: _isTextarea ? _targetElement : undefined,2984_attrs: _mutationObserverAttrsTextarea2985}2986];2987
2988each(checks, function (index, check) {2989elem = check._elem;2990if (elem) {2991each(check._attrs, function (index, attr) {2992curr = attr.charAt(0) === ':' ? elem.is(attr) : elem.attr(attr);2993cache = _updateAutoCache[attr];2994
2995if (checkCache(curr, cache)) {2996changedAttrs.push(attr);2997}2998
2999_updateAutoCache[attr] = curr;3000});3001}3002});3003
3004updateViewportAttrsFromTarget(changedAttrs);3005
3006return changedAttrs[LEXICON.l] > 0;3007}3008
3009/**3010* Checks is a CSS Property of a child element is affecting the scroll size of the content.
3011* @param propertyName The CSS property name.
3012* @returns {boolean} True if the property is affecting the content scroll size, false otherwise.
3013*/
3014function isSizeAffectingCSSProperty(propertyName) {3015if (!_initialized)3016return true;3017var flexGrow = 'flex-grow';3018var flexShrink = 'flex-shrink';3019var flexBasis = 'flex-basis';3020var affectingPropsX = [3021_strWidth,3022_strMinMinus + _strWidth,3023_strMaxMinus + _strWidth,3024_strMarginMinus + _strLeft,3025_strMarginMinus + _strRight,3026_strLeft,3027_strRight,3028'font-weight',3029'word-spacing',3030flexGrow,3031flexShrink,3032flexBasis
3033];3034var affectingPropsXContentBox = [3035_strPaddingMinus + _strLeft,3036_strPaddingMinus + _strRight,3037_strBorderMinus + _strLeft + _strWidth,3038_strBorderMinus + _strRight + _strWidth3039];3040var affectingPropsY = [3041_strHeight,3042_strMinMinus + _strHeight,3043_strMaxMinus + _strHeight,3044_strMarginMinus + _strTop,3045_strMarginMinus + _strBottom,3046_strTop,3047_strBottom,3048'line-height',3049flexGrow,3050flexShrink,3051flexBasis
3052];3053var affectingPropsYContentBox = [3054_strPaddingMinus + _strTop,3055_strPaddingMinus + _strBottom,3056_strBorderMinus + _strTop + _strWidth,3057_strBorderMinus + _strBottom + _strWidth3058];3059var _strS = 's';3060var _strVS = 'v-s';3061var checkX = _overflowBehaviorCache.x === _strS || _overflowBehaviorCache.x === _strVS;3062var checkY = _overflowBehaviorCache.y === _strS || _overflowBehaviorCache.y === _strVS;3063var sizeIsAffected = false;3064var checkPropertyName = function (arr, name) {3065for (var i = 0; i < arr[LEXICON.l]; i++) {3066if (arr[i] === name)3067return true;3068}3069return false;3070};3071
3072if (checkY) {3073sizeIsAffected = checkPropertyName(affectingPropsY, propertyName);3074if (!sizeIsAffected && !_isBorderBox)3075sizeIsAffected = checkPropertyName(affectingPropsYContentBox, propertyName);3076}3077if (checkX && !sizeIsAffected) {3078sizeIsAffected = checkPropertyName(affectingPropsX, propertyName);3079if (!sizeIsAffected && !_isBorderBox)3080sizeIsAffected = checkPropertyName(affectingPropsXContentBox, propertyName);3081}3082return sizeIsAffected;3083}3084
3085
3086//==== Update ====//3087
3088/**3089* Sets the attribute values of the viewport element to the values from the target element.
3090* The value of a attribute is only set if the attribute is whitelisted.
3091* @attrs attrs The array of attributes which shall be set or undefined if all whitelisted shall be set.
3092*/
3093function updateViewportAttrsFromTarget(attrs) {3094attrs = attrs || _viewportAttrsFromTarget;3095each(attrs, function (index, attr) {3096if (COMPATIBILITY.inA(attr, _viewportAttrsFromTarget) > -1) {3097var targetAttr = _targetElement.attr(attr);3098if (type(targetAttr) == TYPES.s) {3099_viewportElement.attr(attr, targetAttr);3100}3101else {3102_viewportElement.removeAttr(attr);3103}3104}3105});3106}3107
3108/**3109* Updates the variables and size of the textarea element, and manages the scroll on new line or new character.
3110*/
3111function textareaUpdate() {3112if (!_sleeping) {3113var wrapAttrOff = !_textareaAutoWrappingCache;3114var minWidth = _viewportSize.w;3115var minHeight = _viewportSize.h;3116var css = {};3117var doMeasure = _widthAutoCache || wrapAttrOff;3118var origWidth;3119var width;3120var origHeight;3121var height;3122
3123//reset min size3124css[_strMinMinus + _strWidth] = _strEmpty;3125css[_strMinMinus + _strHeight] = _strEmpty;3126
3127//set width auto3128css[_strWidth] = _strAuto;3129_targetElement.css(css);3130
3131//measure width3132origWidth = _targetElementNative[LEXICON.oW];3133width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1;3134/*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/3135
3136//set measured width3137css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent;3138css[_strMinMinus + _strWidth] = _strHundredPercent;3139
3140//set height auto3141css[_strHeight] = _strAuto;3142_targetElement.css(css);3143
3144//measure height3145origHeight = _targetElementNative[LEXICON.oH];3146height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1);3147
3148//append correct size values3149css[_strWidth] = width;3150css[_strHeight] = height;3151_textareaCoverElement.css(css);3152
3153//apply min width / min height to prevent textarea collapsing3154css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/;3155css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/;3156_targetElement.css(css);3157
3158return {3159_originalWidth: origWidth,3160_originalHeight: origHeight,3161_dynamicWidth: width,3162_dynamicHeight: height3163};3164}3165}3166
3167/**3168* Updates the plugin and DOM to the current options.
3169* This method should only be called if a update is 100% required.
3170* @param updateHints A objects which contains hints for this update:
3171* {
3172* _hostSizeChanged : boolean,
3173* _contentSizeChanged : boolean,
3174* _force : boolean, == preventSwallowing
3175* _changedOptions : { }, == preventSwallowing && preventSleep
3176* }
3177*/
3178function update(updateHints) {3179clearTimeout(_swallowedUpdateTimeout);3180updateHints = updateHints || {};3181_swallowedUpdateHints._hostSizeChanged |= updateHints._hostSizeChanged;3182_swallowedUpdateHints._contentSizeChanged |= updateHints._contentSizeChanged;3183_swallowedUpdateHints._force |= updateHints._force;3184
3185var now = COMPATIBILITY.now();3186var hostSizeChanged = !!_swallowedUpdateHints._hostSizeChanged;3187var contentSizeChanged = !!_swallowedUpdateHints._contentSizeChanged;3188var force = !!_swallowedUpdateHints._force;3189var changedOptions = updateHints._changedOptions;3190var swallow = _swallowUpdateLag > 0 && _initialized && !_destroyed && !force && !changedOptions && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache);3191var displayIsHidden;3192
3193if (swallow)3194_swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag);3195
3196//abort update due to:3197//destroyed3198//swallowing3199//sleeping3200//host is hidden or has false display3201if (_destroyed || swallow || (_sleeping && !changedOptions) || (_initialized && !force && (displayIsHidden = _hostElement.is(':hidden'))) || _hostElement.css('display') === 'inline')3202return;3203
3204_lastUpdateTime = now;3205_swallowedUpdateHints = {};3206
3207//if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely.3208if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {3209//native scrollbars are hidden, so change the values to zero3210_nativeScrollbarSize.x = 0;3211_nativeScrollbarSize.y = 0;3212}3213else {3214//refresh native scrollbar size (in case of zoom)3215_nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);3216}3217
3218// Scrollbar padding is needed for firefox, because firefox hides scrollbar automatically if the size of the div is too small.3219// The calculation: [scrollbar size +3 *3]3220// (+3 because of possible decoration e.g. borders, margins etc., but only if native scrollbar is NOT a overlaid scrollbar)3221// (*3 because (1)increase / (2)decrease -button and (3)resize handle)3222_nativeScrollbarMinSize = {3223x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3,3224y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 33225};3226
3227changedOptions = changedOptions || {};3228//freezeResizeObserver(_sizeObserverElement, true);3229//freezeResizeObserver(_sizeAutoObserverElement, true);3230
3231var checkCacheAutoForce = function () {3232return checkCache.apply(this, [].slice.call(arguments).concat([force]));3233};3234
3235//save current scroll offset3236var currScroll = {3237x: _viewportElement[_strScrollLeft](),3238y: _viewportElement[_strScrollTop]()3239};3240
3241var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars;3242var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea;3243
3244//scrollbars visibility:3245var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility;3246var scrollbarsVisibilityChanged = checkCacheAutoForce(scrollbarsVisibility, _scrollbarsVisibilityCache);3247
3248//scrollbars autoHide:3249var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide;3250var scrollbarsAutoHideChanged = checkCacheAutoForce(scrollbarsAutoHide, _scrollbarsAutoHideCache);3251
3252//scrollbars click scrolling3253var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling;3254var scrollbarsClickScrollingChanged = checkCacheAutoForce(scrollbarsClickScrolling, _scrollbarsClickScrollingCache);3255
3256//scrollbars drag scrolling3257var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling;3258var scrollbarsDragScrollingChanged = checkCacheAutoForce(scrollbarsDragScrolling, _scrollbarsDragScrollingCache);3259
3260//className3261var className = _currentPreparedOptions.className;3262var classNameChanged = checkCacheAutoForce(className, _classNameCache);3263
3264//resize3265var resize = _currentPreparedOptions.resize;3266var resizeChanged = checkCacheAutoForce(resize, _resizeCache) && !_isBody; //body can't be resized since the window itself acts as resize possibility.3267
3268//paddingAbsolute3269var paddingAbsolute = _currentPreparedOptions.paddingAbsolute;3270var paddingAbsoluteChanged = checkCacheAutoForce(paddingAbsolute, _paddingAbsoluteCache);3271
3272//clipAlways3273var clipAlways = _currentPreparedOptions.clipAlways;3274var clipAlwaysChanged = checkCacheAutoForce(clipAlways, _clipAlwaysCache);3275
3276//sizeAutoCapable3277var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport.3278var sizeAutoCapableChanged = checkCacheAutoForce(sizeAutoCapable, _sizeAutoCapableCache);3279
3280//showNativeScrollbars3281var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars;3282var ignoreOverlayScrollbarHidingChanged = checkCacheAutoForce(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache);3283
3284//autoUpdate3285var autoUpdate = _currentPreparedOptions.autoUpdate;3286var autoUpdateChanged = checkCacheAutoForce(autoUpdate, _autoUpdateCache);3287
3288//overflowBehavior3289var overflowBehavior = _currentPreparedOptions.overflowBehavior;3290var overflowBehaviorChanged = checkCacheAutoForce(overflowBehavior, _overflowBehaviorCache, force);3291
3292//dynWidth:3293var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth;3294var textareaDynWidthChanged = checkCacheAutoForce(_textareaDynWidthCache, textareaDynWidth);3295
3296//dynHeight:3297var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight;3298var textareaDynHeightChanged = checkCacheAutoForce(_textareaDynHeightCache, textareaDynHeight);3299
3300//scrollbars visibility3301_scrollbarsAutoHideNever = scrollbarsAutoHide === 'n';3302_scrollbarsAutoHideScroll = scrollbarsAutoHide === 's';3303_scrollbarsAutoHideMove = scrollbarsAutoHide === 'm';3304_scrollbarsAutoHideLeave = scrollbarsAutoHide === 'l';3305
3306//scrollbars autoHideDelay3307_scrollbarsAutoHideDelay = currentPreparedOptionsScrollbars.autoHideDelay;3308
3309//old className3310_oldClassName = _classNameCache;3311
3312//resize3313_resizeNone = resize === 'n';3314_resizeBoth = resize === 'b';3315_resizeHorizontal = resize === 'h';3316_resizeVertical = resize === 'v';3317
3318//normalizeRTL3319_normalizeRTLCache = _currentPreparedOptions.normalizeRTL;3320
3321//ignore overlay scrollbar hiding3322ignoreOverlayScrollbarHiding = ignoreOverlayScrollbarHiding && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y);3323
3324//refresh options cache3325_scrollbarsVisibilityCache = scrollbarsVisibility;3326_scrollbarsAutoHideCache = scrollbarsAutoHide;3327_scrollbarsClickScrollingCache = scrollbarsClickScrolling;3328_scrollbarsDragScrollingCache = scrollbarsDragScrolling;3329_classNameCache = className;3330_resizeCache = resize;3331_paddingAbsoluteCache = paddingAbsolute;3332_clipAlwaysCache = clipAlways;3333_sizeAutoCapableCache = sizeAutoCapable;3334_ignoreOverlayScrollbarHidingCache = ignoreOverlayScrollbarHiding;3335_autoUpdateCache = autoUpdate;3336_overflowBehaviorCache = extendDeep({}, overflowBehavior);3337_textareaDynWidthCache = textareaDynWidth;3338_textareaDynHeightCache = textareaDynHeight;3339_hasOverflowCache = _hasOverflowCache || { x: false, y: false };3340
3341//set correct class name to the host element3342if (classNameChanged) {3343removeClass(_hostElement, _oldClassName + _strSpace + _classNameThemeNone);3344addClass(_hostElement, className !== undefined && className !== null && className.length > 0 ? className : _classNameThemeNone);3345}3346
3347//set correct auto Update3348if (autoUpdateChanged) {3349if (autoUpdate === true || (autoUpdate === null && _autoUpdateRecommended)) {3350disconnectMutationObservers();3351autoUpdateLoop.add(_base);3352}3353else {3354autoUpdateLoop.remove(_base);3355connectMutationObservers();3356}3357}3358
3359//activate or deactivate size auto capability3360if (sizeAutoCapableChanged) {3361if (sizeAutoCapable) {3362if (_contentGlueElement) {3363_contentGlueElement.show();3364}3365else {3366_contentGlueElement = FRAMEWORK(generateDiv(_classNameContentGlueElement));3367_paddingElement.before(_contentGlueElement);3368}3369if (_sizeAutoObserverAdded) {3370_sizeAutoObserverElement.show();3371}3372else {3373_sizeAutoObserverElement = FRAMEWORK(generateDiv(_classNameSizeAutoObserverElement));3374_sizeAutoObserverElementNative = _sizeAutoObserverElement[0];3375
3376_contentGlueElement.before(_sizeAutoObserverElement);3377var oldSize = { w: -1, h: -1 };3378setupResizeObserver(_sizeAutoObserverElement, function () {3379var newSize = {3380w: _sizeAutoObserverElementNative[LEXICON.oW],3381h: _sizeAutoObserverElementNative[LEXICON.oH]3382};3383if (checkCache(newSize, oldSize)) {3384if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) {3385update();3386}3387else if (_initialized && (!_heightAutoCache && newSize.h === 0) || (!_widthAutoCache && newSize.w === 0)) {3388update();3389}3390}3391oldSize = newSize;3392});3393_sizeAutoObserverAdded = true;3394//fix heightAuto detector bug if height is fixed but contentHeight is 0.3395//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.3396if (_cssCalc !== null)3397_sizeAutoObserverElement.css(_strHeight, _cssCalc + '(100% + 1px)');3398}3399}3400else {3401if (_sizeAutoObserverAdded)3402_sizeAutoObserverElement.hide();3403if (_contentGlueElement)3404_contentGlueElement.hide();3405}3406}3407
3408//if force, update all resizeObservers too3409if (force) {3410_sizeObserverElement.find('*').trigger(_strScroll);3411if (_sizeAutoObserverAdded)3412_sizeAutoObserverElement.find('*').trigger(_strScroll);3413}3414
3415//display hidden:3416displayIsHidden = displayIsHidden === undefined ? _hostElement.is(':hidden') : displayIsHidden;3417
3418//textarea AutoWrapping:3419var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false;3420var textareaAutoWrappingChanged = checkCacheAutoForce(textareaAutoWrapping, _textareaAutoWrappingCache);3421
3422//detect direction:3423var cssDirection = _hostElement.css('direction');3424var cssDirectionChanged = checkCacheAutoForce(cssDirection, _cssDirectionCache);3425
3426//detect box-sizing:3427var boxSizing = _hostElement.css('box-sizing');3428var boxSizingChanged = checkCacheAutoForce(boxSizing, _cssBoxSizingCache);3429
3430//detect padding:3431var padding = getTopRightBottomLeftHost(_strPaddingMinus);3432
3433//width + height auto detecting var:3434var sizeAutoObserverElementBCRect;3435//exception occurs in IE8 sometimes (unknown exception)3436try {3437sizeAutoObserverElementBCRect = _sizeAutoObserverAdded ? _sizeAutoObserverElementNative[LEXICON.bCR]() : null;3438} catch (ex) {3439return;3440}3441
3442_isRTL = cssDirection === 'rtl';3443_isBorderBox = (boxSizing === 'border-box');3444var isRTLLeft = _isRTL ? _strLeft : _strRight;3445var isRTLRight = _isRTL ? _strRight : _strLeft;3446
3447//detect width auto:3448var widthAutoResizeDetection = false;3449var widthAutoObserverDetection = (_sizeAutoObserverAdded && (_hostElement.css(_strFloat) !== 'none' /*|| _isTextarea */)) ? (MATH.round(sizeAutoObserverElementBCRect.right - sizeAutoObserverElementBCRect.left) === 0) && (!paddingAbsolute ? (_hostElementNative[LEXICON.cW] - _paddingX) > 0 : true) : false;3450if (sizeAutoCapable && !widthAutoObserverDetection) {3451var tmpCurrHostWidth = _hostElementNative[LEXICON.oW];3452var tmpCurrContentGlueWidth = _contentGlueElement.css(_strWidth);3453_contentGlueElement.css(_strWidth, _strAuto);3454
3455var tmpNewHostWidth = _hostElementNative[LEXICON.oW];3456_contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);3457widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;3458if (!widthAutoResizeDetection) {3459_contentGlueElement.css(_strWidth, tmpCurrHostWidth + 1);3460tmpNewHostWidth = _hostElementNative[LEXICON.oW];3461_contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);3462widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;3463}3464}3465var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden;3466var widthAutoChanged = checkCacheAutoForce(widthAuto, _widthAutoCache);3467var wasWidthAuto = !widthAuto && _widthAutoCache;3468
3469//detect height auto:3470var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false;3471var heightAutoChanged = checkCacheAutoForce(heightAuto, _heightAutoCache);3472var wasHeightAuto = !heightAuto && _heightAutoCache;3473
3474//detect border:3475//we need the border only if border box and auto size3476var updateBorderX = (widthAuto && _isBorderBox) || !_isBorderBox;3477var updateBorderY = (heightAuto && _isBorderBox) || !_isBorderBox;3478var border = getTopRightBottomLeftHost(_strBorderMinus, '-' + _strWidth, !updateBorderX, !updateBorderY)3479
3480//detect margin:3481var margin = getTopRightBottomLeftHost(_strMarginMinus);3482
3483//vars to apply correct css3484var contentElementCSS = {};3485var contentGlueElementCSS = {};3486
3487//funcs3488var getHostSize = function () {3489//has to be clientSize because offsetSize respect borders3490return {3491w: _hostElementNative[LEXICON.cW],3492h: _hostElementNative[LEXICON.cH]3493};3494};3495var getViewportSize = function () {3496//viewport size is padding container because it never has padding, margin and a border3497//determine zoom rounding error -> sometimes scrollWidth/Height is smaller than clientWidth/Height3498//if this happens add the difference to the viewportSize to compensate the rounding error3499return {3500w: _paddingElementNative[LEXICON.oW] + MATH.max(0, _contentElementNative[LEXICON.cW] - _contentElementNative[LEXICON.sW]),3501h: _paddingElementNative[LEXICON.oH] + MATH.max(0, _contentElementNative[LEXICON.cH] - _contentElementNative[LEXICON.sH])3502};3503};3504
3505//set info for padding3506var paddingAbsoluteX = _paddingX = padding.l + padding.r;3507var paddingAbsoluteY = _paddingY = padding.t + padding.b;3508paddingAbsoluteX *= paddingAbsolute ? 1 : 0;3509paddingAbsoluteY *= paddingAbsolute ? 1 : 0;3510padding.c = checkCacheAutoForce(padding, _cssPaddingCache);3511
3512//set info for border3513_borderX = border.l + border.r;3514_borderY = border.t + border.b;3515border.c = checkCacheAutoForce(border, _cssBorderCache);3516
3517//set info for margin3518_marginX = margin.l + margin.r;3519_marginY = margin.t + margin.b;3520margin.c = checkCacheAutoForce(margin, _cssMarginCache);3521
3522//refresh cache3523_textareaAutoWrappingCache = textareaAutoWrapping;3524_cssDirectionCache = cssDirection;3525_cssBoxSizingCache = boxSizing;3526_widthAutoCache = widthAuto;3527_heightAutoCache = heightAuto;3528_cssPaddingCache = padding;3529_cssBorderCache = border;3530_cssMarginCache = margin;3531
3532//IEFix direction changed3533if (cssDirectionChanged && _sizeAutoObserverAdded)3534_sizeAutoObserverElement.css(_strFloat, isRTLRight);3535
3536//apply padding:3537if (padding.c || cssDirectionChanged || paddingAbsoluteChanged || widthAutoChanged || heightAutoChanged || boxSizingChanged || sizeAutoCapableChanged) {3538var paddingElementCSS = {};3539var textareaCSS = {};3540var paddingValues = [padding.t, padding.r, padding.b, padding.l];3541
3542setTopRightBottomLeft(contentGlueElementCSS, _strMarginMinus, [-padding.t, -padding.r, -padding.b, -padding.l]);3543if (paddingAbsolute) {3544setTopRightBottomLeft(paddingElementCSS, _strEmpty, paddingValues);3545setTopRightBottomLeft(_isTextarea ? textareaCSS : contentElementCSS, _strPaddingMinus);3546}3547else {3548setTopRightBottomLeft(paddingElementCSS, _strEmpty);3549setTopRightBottomLeft(_isTextarea ? textareaCSS : contentElementCSS, _strPaddingMinus, paddingValues);3550}3551
3552_paddingElement.css(paddingElementCSS);3553_targetElement.css(textareaCSS);3554}3555
3556//viewport size is padding container because it never has padding, margin and a border.3557_viewportSize = getViewportSize();3558
3559//update Textarea3560var textareaSize = _isTextarea ? textareaUpdate() : false;3561var textareaSizeChanged = _isTextarea && checkCacheAutoForce(textareaSize, _textareaSizeCache);3562var textareaDynOrigSize = _isTextarea && textareaSize ? {3563w: textareaDynWidth ? textareaSize._dynamicWidth : textareaSize._originalWidth,3564h: textareaDynHeight ? textareaSize._dynamicHeight : textareaSize._originalHeight3565} : {};3566_textareaSizeCache = textareaSize;3567
3568//fix height auto / width auto in cooperation with current padding & boxSizing behavior:3569if (heightAuto && (heightAutoChanged || paddingAbsoluteChanged || boxSizingChanged || padding.c || border.c)) {3570contentElementCSS[_strHeight] = _strAuto;3571}3572else if (heightAutoChanged || paddingAbsoluteChanged) {3573contentElementCSS[_strHeight] = _strHundredPercent;3574}3575if (widthAuto && (widthAutoChanged || paddingAbsoluteChanged || boxSizingChanged || padding.c || border.c || cssDirectionChanged)) {3576contentElementCSS[_strWidth] = _strAuto;3577contentGlueElementCSS[_strMaxMinus + _strWidth] = _strHundredPercent; //IE Fix3578}3579else if (widthAutoChanged || paddingAbsoluteChanged) {3580contentElementCSS[_strWidth] = _strHundredPercent;3581contentElementCSS[_strFloat] = _strEmpty;3582contentGlueElementCSS[_strMaxMinus + _strWidth] = _strEmpty; //IE Fix3583}3584if (widthAuto) {3585//textareaDynOrigSize.w || _strAuto :: doesnt works because applied margin will shift width3586contentGlueElementCSS[_strWidth] = _strAuto;3587
3588contentElementCSS[_strWidth] = VENDORS._cssPropertyValue(_strWidth, 'max-content intrinsic') || _strAuto;3589contentElementCSS[_strFloat] = isRTLRight;3590}3591else {3592contentGlueElementCSS[_strWidth] = _strEmpty;3593}3594if (heightAuto) {3595//textareaDynOrigSize.h || _contentElementNative[LEXICON.cH] :: use for anti scroll jumping3596contentGlueElementCSS[_strHeight] = textareaDynOrigSize.h || _contentElementNative[LEXICON.cH];3597}3598else {3599contentGlueElementCSS[_strHeight] = _strEmpty;3600}3601if (sizeAutoCapable)3602_contentGlueElement.css(contentGlueElementCSS);3603_contentElement.css(contentElementCSS);3604
3605//CHECKPOINT HERE ~3606contentElementCSS = {};3607contentGlueElementCSS = {};3608
3609//if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true3610if (hostSizeChanged || contentSizeChanged || textareaSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged) {3611var strOverflow = 'overflow';3612var strOverflowX = strOverflow + '-x';3613var strOverflowY = strOverflow + '-y';3614var strHidden = 'hidden';3615var strVisible = 'visible';3616
3617//Reset the viewport (very important for natively overlaid scrollbars and zoom change3618//don't change the overflow prop as it is very expensive and affects performance !A LOT!3619if (!_nativeScrollbarStyling) {3620var viewportElementResetCSS = {};3621var resetXTmp = _hasOverflowCache.y && _hideOverflowCache.ys && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.y ? _viewportElement.css(isRTLLeft) : -_nativeScrollbarSize.y) : 0;3622var resetBottomTmp = _hasOverflowCache.x && _hideOverflowCache.xs && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.x ? _viewportElement.css(_strBottom) : -_nativeScrollbarSize.x) : 0;3623setTopRightBottomLeft(viewportElementResetCSS, _strEmpty);3624_viewportElement.css(viewportElementResetCSS);3625}3626
3627//measure several sizes:3628var contentMeasureElement = getContentMeasureElement();3629//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 overlaid3630var contentSize = {3631//use clientSize because natively overlaidScrollbars add borders3632w: textareaDynOrigSize.w || contentMeasureElement[LEXICON.cW],3633h: textareaDynOrigSize.h || contentMeasureElement[LEXICON.cH]3634};3635var scrollSize = {3636w: contentMeasureElement[LEXICON.sW],3637h: contentMeasureElement[LEXICON.sH]3638};3639
3640//apply the correct viewport style and measure viewport size3641if (!_nativeScrollbarStyling) {3642viewportElementResetCSS[_strBottom] = wasHeightAuto ? _strEmpty : resetBottomTmp;3643viewportElementResetCSS[isRTLLeft] = wasWidthAuto ? _strEmpty : resetXTmp;3644_viewportElement.css(viewportElementResetCSS);3645}3646_viewportSize = getViewportSize();3647
3648//measure and correct several sizes3649var hostSize = getHostSize();3650var hostAbsoluteRectSize = {3651w: hostSize.w - _marginX - _borderX - (_isBorderBox ? 0 : _paddingX),3652h: hostSize.h - _marginY - _borderY - (_isBorderBox ? 0 : _paddingY)3653};3654var contentGlueSize = {3655//client/scrollSize + AbsolutePadding -> because padding is only applied to the paddingElement if its absolute, so you have to add it manually3656//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 padding3657w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostAbsoluteRectSize.w),3658h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostAbsoluteRectSize.h)3659};3660contentGlueSize.c = checkCacheAutoForce(contentGlueSize, _contentGlueSizeCache);3661_contentGlueSizeCache = contentGlueSize;3662
3663//apply correct contentGlue size3664if (sizeAutoCapable) {3665//size contentGlue correctly to make sure the element has correct size if the sizing switches to auto3666if (contentGlueSize.c || (heightAuto || widthAuto)) {3667contentGlueElementCSS[_strWidth] = contentGlueSize.w;3668contentGlueElementCSS[_strHeight] = contentGlueSize.h;3669
3670//textarea-sizes are already calculated correctly at this point3671if (!_isTextarea) {3672contentSize = {3673//use clientSize because natively overlaidScrollbars add borders3674w: contentMeasureElement[LEXICON.cW],3675h: contentMeasureElement[LEXICON.cH]3676};3677}3678}3679var textareaCoverCSS = {};3680var setContentGlueElementCSSfunction = function (horizontal) {3681var scrollbarVars = getScrollbarVars(horizontal);3682var wh = scrollbarVars._w_h;3683var strWH = scrollbarVars._width_height;3684var autoSize = horizontal ? widthAuto : heightAuto;3685var borderSize = horizontal ? _borderX : _borderY;3686var paddingSize = horizontal ? _paddingX : _paddingY;3687var marginSize = horizontal ? _marginX : _marginY;3688var viewportSize = _viewportSize[wh] - borderSize - marginSize - (_isBorderBox ? 0 : paddingSize);3689
3690//make contentGlue size -1 if element is not auto sized, to make sure that a resize event happens when the element shrinks3691if (!autoSize || (!autoSize && border.c))3692contentGlueElementCSS[strWH] = hostAbsoluteRectSize[wh] - 1;3693
3694//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)3695if (autoSize && (contentSize[wh] < viewportSize) && (horizontal && _isTextarea ? !textareaAutoWrapping : true)) {3696if (_isTextarea)3697textareaCoverCSS[strWH] = parseToZeroOrNumber(_textareaCoverElement.css(strWH)) - 1;3698contentGlueElementCSS[strWH] -= 1;3699}3700
3701//make sure content glue size is at least 13702if (contentSize[wh] > 0)3703contentGlueElementCSS[strWH] = MATH.max(1, contentGlueElementCSS[strWH]);3704};3705setContentGlueElementCSSfunction(true);3706setContentGlueElementCSSfunction(false);3707
3708if (_isTextarea)3709_textareaCoverElement.css(textareaCoverCSS);3710_contentGlueElement.css(contentGlueElementCSS);3711}3712if (widthAuto)3713contentElementCSS[_strWidth] = _strHundredPercent;3714if (widthAuto && !_isBorderBox && !_mutationObserversConnected)3715contentElementCSS[_strFloat] = 'none';3716
3717//apply and reset content style3718_contentElement.css(contentElementCSS);3719contentElementCSS = {};3720
3721//measure again, but this time all correct sizes:3722var contentScrollSize = {3723w: contentMeasureElement[LEXICON.sW],3724h: contentMeasureElement[LEXICON.sH],3725};3726contentScrollSize.c = contentSizeChanged = checkCacheAutoForce(contentScrollSize, _contentScrollSizeCache);3727_contentScrollSizeCache = contentScrollSize;3728
3729//refresh viewport size after correct measuring3730_viewportSize = getViewportSize();3731
3732hostSize = getHostSize();3733hostSizeChanged = checkCacheAutoForce(hostSize, _hostSizeCache);3734_hostSizeCache = hostSize;3735
3736var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0);3737var previousOverflowAmount = _overflowAmountCache;3738var overflowBehaviorIsVS = {};3739var overflowBehaviorIsVH = {};3740var overflowBehaviorIsS = {};3741var overflowAmount = {};3742var hasOverflow = {};3743var hideOverflow = {};3744var canScroll = {};3745var viewportRect = _paddingElementNative[LEXICON.bCR]();3746var setOverflowVariables = function (horizontal) {3747var scrollbarVars = getScrollbarVars(horizontal);3748var scrollbarVarsInverted = getScrollbarVars(!horizontal);3749var xyI = scrollbarVarsInverted._x_y;3750var xy = scrollbarVars._x_y;3751var wh = scrollbarVars._w_h;3752var widthHeight = scrollbarVars._width_height;3753var scrollMax = _strScroll + scrollbarVars._Left_Top + 'Max';3754var fractionalOverflowAmount = viewportRect[widthHeight] ? MATH.abs(viewportRect[widthHeight] - _viewportSize[wh]) : 0;3755var checkFractionalOverflowAmount = previousOverflowAmount && previousOverflowAmount[xy] > 0 && _viewportElementNative[scrollMax] === 0;3756overflowBehaviorIsVS[xy] = overflowBehavior[xy] === 'v-s';3757overflowBehaviorIsVH[xy] = overflowBehavior[xy] === 'v-h';3758overflowBehaviorIsS[xy] = overflowBehavior[xy] === 's';3759overflowAmount[xy] = MATH.max(0, MATH.round((contentScrollSize[wh] - _viewportSize[wh]) * 100) / 100);3760overflowAmount[xy] *= (hideOverflowForceTextarea || (checkFractionalOverflowAmount && fractionalOverflowAmount > 0 && fractionalOverflowAmount < 1)) ? 0 : 1;3761hasOverflow[xy] = overflowAmount[xy] > 0;3762
3763//hideOverflow:3764//x || y : true === overflow is hidden by "overflow: scroll" OR "overflow: hidden"3765//xs || ys : true === overflow is hidden by "overflow: scroll"3766hideOverflow[xy] = overflowBehaviorIsVS[xy] || overflowBehaviorIsVH[xy] ? (hasOverflow[xyI] && !overflowBehaviorIsVS[xyI] && !overflowBehaviorIsVH[xyI]) : hasOverflow[xy];3767hideOverflow[xy + 's'] = hideOverflow[xy] ? (overflowBehaviorIsS[xy] || overflowBehaviorIsVS[xy]) : false;3768
3769canScroll[xy] = hasOverflow[xy] && hideOverflow[xy + 's'];3770};3771setOverflowVariables(true);3772setOverflowVariables(false);3773
3774overflowAmount.c = checkCacheAutoForce(overflowAmount, _overflowAmountCache);3775_overflowAmountCache = overflowAmount;3776hasOverflow.c = checkCacheAutoForce(hasOverflow, _hasOverflowCache);3777_hasOverflowCache = hasOverflow;3778hideOverflow.c = checkCacheAutoForce(hideOverflow, _hideOverflowCache);3779_hideOverflowCache = hideOverflow;3780
3781//if native scrollbar is overlay at x OR y axis, prepare DOM3782if (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) {3783var borderDesign = 'px solid transparent';3784var contentArrangeElementCSS = {};3785var arrangeContent = {};3786var arrangeChanged = force;3787var setContentElementCSS;3788
3789if (hasOverflow.x || hasOverflow.y) {3790arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty;3791arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty;3792arrangeChanged = checkCacheAutoForce(arrangeContent, _arrangeContentSizeCache);3793_arrangeContentSizeCache = arrangeContent;3794}3795
3796if (hasOverflow.c || hideOverflow.c || contentScrollSize.c || cssDirectionChanged || widthAutoChanged || heightAutoChanged || widthAuto || heightAuto || ignoreOverlayScrollbarHidingChanged) {3797contentElementCSS[_strMarginMinus + isRTLRight] = contentElementCSS[_strBorderMinus + isRTLRight] = _strEmpty;3798setContentElementCSS = function (horizontal) {3799var scrollbarVars = getScrollbarVars(horizontal);3800var scrollbarVarsInverted = getScrollbarVars(!horizontal);3801var xy = scrollbarVars._x_y;3802var strDirection = horizontal ? _strBottom : isRTLLeft;3803var invertedAutoSize = horizontal ? heightAuto : widthAuto;3804
3805if (_nativeScrollbarIsOverlaid[xy] && hasOverflow[xy] && hideOverflow[xy + 's']) {3806contentElementCSS[_strMarginMinus + strDirection] = invertedAutoSize ? (ignoreOverlayScrollbarHiding ? _strEmpty : _overlayScrollbarDummySize[xy]) : _strEmpty;3807contentElementCSS[_strBorderMinus + strDirection] = ((horizontal ? !invertedAutoSize : true) && !ignoreOverlayScrollbarHiding) ? (_overlayScrollbarDummySize[xy] + borderDesign) : _strEmpty;3808}3809else {3810arrangeContent[scrollbarVarsInverted._w_h] =3811contentElementCSS[_strMarginMinus + strDirection] =3812contentElementCSS[_strBorderMinus + strDirection] = _strEmpty;3813arrangeChanged = true;3814}3815};3816
3817if (_nativeScrollbarStyling) {3818addRemoveClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible, !ignoreOverlayScrollbarHiding)3819}3820else {3821setContentElementCSS(true);3822setContentElementCSS(false);3823}3824}3825if (ignoreOverlayScrollbarHiding) {3826arrangeContent.w = arrangeContent.h = _strEmpty;3827arrangeChanged = true;3828}3829if (arrangeChanged && !_nativeScrollbarStyling) {3830contentArrangeElementCSS[_strWidth] = hideOverflow.y ? arrangeContent.w : _strEmpty;3831contentArrangeElementCSS[_strHeight] = hideOverflow.x ? arrangeContent.h : _strEmpty;3832
3833if (!_contentArrangeElement) {3834_contentArrangeElement = FRAMEWORK(generateDiv(_classNameContentArrangeElement));3835_viewportElement.prepend(_contentArrangeElement);3836}3837_contentArrangeElement.css(contentArrangeElementCSS);3838}3839_contentElement.css(contentElementCSS);3840}3841
3842var viewportElementCSS = {};3843var paddingElementCSS = {};3844var setViewportCSS;3845if (hostSizeChanged || hasOverflow.c || hideOverflow.c || contentScrollSize.c || overflowBehaviorChanged || boxSizingChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged || clipAlwaysChanged || heightAutoChanged) {3846viewportElementCSS[isRTLRight] = _strEmpty;3847setViewportCSS = function (horizontal) {3848var scrollbarVars = getScrollbarVars(horizontal);3849var scrollbarVarsInverted = getScrollbarVars(!horizontal);3850var xy = scrollbarVars._x_y;3851var XY = scrollbarVars._X_Y;3852var strDirection = horizontal ? _strBottom : isRTLLeft;3853
3854var reset = function () {3855viewportElementCSS[strDirection] = _strEmpty;3856_contentBorderSize[scrollbarVarsInverted._w_h] = 0;3857};3858if (hasOverflow[xy] && hideOverflow[xy + 's']) {3859viewportElementCSS[strOverflow + XY] = _strScroll;3860if (ignoreOverlayScrollbarHiding || _nativeScrollbarStyling) {3861reset();3862}3863else {3864viewportElementCSS[strDirection] = -(_nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[xy] : _nativeScrollbarSize[xy]);3865_contentBorderSize[scrollbarVarsInverted._w_h] = _nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[scrollbarVarsInverted._x_y] : 0;3866}3867} else {3868viewportElementCSS[strOverflow + XY] = _strEmpty;3869reset();3870}3871};3872setViewportCSS(true);3873setViewportCSS(false);3874
3875// if the scroll container is too small and if there is any overflow with no overlay scrollbar (and scrollbar styling isn't possible),3876// make viewport element greater in size (Firefox hide Scrollbars fix)3877// because firefox starts hiding scrollbars on too small elements3878// with this behavior the overflow calculation may be incorrect or the scrollbars would appear suddenly3879// https://bugzilla.mozilla.org/show_bug.cgi?id=2922843880if (!_nativeScrollbarStyling3881&& (_viewportSize.h < _nativeScrollbarMinSize.x || _viewportSize.w < _nativeScrollbarMinSize.y)3882&& ((hasOverflow.x && hideOverflow.x && !_nativeScrollbarIsOverlaid.x) || (hasOverflow.y && hideOverflow.y && !_nativeScrollbarIsOverlaid.y))) {3883viewportElementCSS[_strPaddingMinus + _strTop] = _nativeScrollbarMinSize.x;3884viewportElementCSS[_strMarginMinus + _strTop] = -_nativeScrollbarMinSize.x;3885
3886viewportElementCSS[_strPaddingMinus + isRTLRight] = _nativeScrollbarMinSize.y;3887viewportElementCSS[_strMarginMinus + isRTLRight] = -_nativeScrollbarMinSize.y;3888}3889else {3890viewportElementCSS[_strPaddingMinus + _strTop] =3891viewportElementCSS[_strMarginMinus + _strTop] =3892viewportElementCSS[_strPaddingMinus + isRTLRight] =3893viewportElementCSS[_strMarginMinus + isRTLRight] = _strEmpty;3894}3895viewportElementCSS[_strPaddingMinus + isRTLLeft] =3896viewportElementCSS[_strMarginMinus + isRTLLeft] = _strEmpty;3897
3898//if there is any overflow (x OR y axis) and this overflow shall be hidden, make overflow hidden, else overflow visible3899if ((hasOverflow.x && hideOverflow.x) || (hasOverflow.y && hideOverflow.y) || hideOverflowForceTextarea) {3900//only hide if is Textarea3901if (_isTextarea && hideOverflowForceTextarea) {3902paddingElementCSS[strOverflowX] =3903paddingElementCSS[strOverflowY] = strHidden;3904}3905}3906else {3907if (!clipAlways || (overflowBehaviorIsVH.x || overflowBehaviorIsVS.x || overflowBehaviorIsVH.y || overflowBehaviorIsVS.y)) {3908//only un-hide if Textarea3909if (_isTextarea) {3910paddingElementCSS[strOverflowX] =3911paddingElementCSS[strOverflowY] = _strEmpty;3912}3913viewportElementCSS[strOverflowX] =3914viewportElementCSS[strOverflowY] = strVisible;3915}3916}3917
3918_paddingElement.css(paddingElementCSS);3919_viewportElement.css(viewportElementCSS);3920viewportElementCSS = {};3921
3922//force soft redraw in webkit because without the scrollbars will may appear because DOM wont be redrawn under special conditions3923if ((hasOverflow.c || boxSizingChanged || widthAutoChanged || heightAutoChanged) && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {3924var elementStyle = _contentElementNative[LEXICON.s];3925var dump;3926elementStyle.webkitTransform = 'scale(1)';3927elementStyle.display = 'run-in';3928dump = _contentElementNative[LEXICON.oH];3929elementStyle.display = _strEmpty; //|| dump; //use dump to prevent it from deletion if minify3930elementStyle.webkitTransform = _strEmpty;3931}3932/*3933//force hard redraw in webkit if native overlaid scrollbars shall appear
3934if (ignoreOverlayScrollbarHidingChanged && ignoreOverlayScrollbarHiding) {
3935_hostElement.hide();
3936var dump = _hostElementNative[LEXICON.oH];
3937_hostElement.show();
3938}
3939*/
3940}3941
3942//change to direction RTL and width auto Bugfix in Webkit3943//without this fix, the DOM still thinks the scrollbar is LTR and thus the content is shifted to the left3944contentElementCSS = {};3945if (cssDirectionChanged || widthAutoChanged || heightAutoChanged) {3946if (_isRTL && widthAuto) {3947var floatTmp = _contentElement.css(_strFloat);3948var posLeftWithoutFloat = MATH.round(_contentElement.css(_strFloat, _strEmpty).css(_strLeft, _strEmpty).position().left);3949_contentElement.css(_strFloat, floatTmp);3950var posLeftWithFloat = MATH.round(_contentElement.position().left);3951
3952if (posLeftWithoutFloat !== posLeftWithFloat)3953contentElementCSS[_strLeft] = posLeftWithoutFloat;3954}3955else {3956contentElementCSS[_strLeft] = _strEmpty;3957}3958}3959_contentElement.css(contentElementCSS);3960
3961//handle scroll position3962if (_isTextarea && contentSizeChanged) {3963var textareaInfo = getTextareaInfo();3964if (textareaInfo) {3965var textareaRowsChanged = _textareaInfoCache === undefined ? true : textareaInfo._rows !== _textareaInfoCache._rows;3966var cursorRow = textareaInfo._cursorRow;3967var cursorCol = textareaInfo._cursorColumn;3968var widestRow = textareaInfo._widestRow;3969var lastRow = textareaInfo._rows;3970var lastCol = textareaInfo._columns;3971var cursorPos = textareaInfo._cursorPosition;3972var cursorMax = textareaInfo._cursorMax;3973var cursorIsLastPosition = (cursorPos >= cursorMax && _textareaHasFocus);3974var textareaScrollAmount = {3975x: (!textareaAutoWrapping && (cursorCol === lastCol && cursorRow === widestRow)) ? _overflowAmountCache.x : -1,3976y: (textareaAutoWrapping ? cursorIsLastPosition || textareaRowsChanged && (previousOverflowAmount ? (currScroll.y === previousOverflowAmount.y) : false) : (cursorIsLastPosition || textareaRowsChanged) && cursorRow === lastRow) ? _overflowAmountCache.y : -13977};3978currScroll.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.3979currScroll.y = textareaScrollAmount.y > -1 ? textareaScrollAmount.y : currScroll.y;3980}3981_textareaInfoCache = textareaInfo;3982}3983if (_isRTL && _rtlScrollBehavior.i && _nativeScrollbarIsOverlaid.y && hasOverflow.x && _normalizeRTLCache)3984currScroll.x += _contentBorderSize.w || 0;3985if (widthAuto)3986_hostElement[_strScrollLeft](0);3987if (heightAuto)3988_hostElement[_strScrollTop](0);3989_viewportElement[_strScrollLeft](currScroll.x)[_strScrollTop](currScroll.y);3990
3991//scrollbars management:3992var scrollbarsVisibilityVisible = scrollbarsVisibility === 'v';3993var scrollbarsVisibilityHidden = scrollbarsVisibility === 'h';3994var scrollbarsVisibilityAuto = scrollbarsVisibility === 'a';3995var refreshScrollbarsVisibility = function (showX, showY) {3996showY = showY === undefined ? showX : showY;3997refreshScrollbarAppearance(true, showX, canScroll.x)3998refreshScrollbarAppearance(false, showY, canScroll.y)3999};4000
4001//manage class name which indicates scrollable overflow4002addRemoveClass(_hostElement, _classNameHostOverflow, hideOverflow.x || hideOverflow.y);4003addRemoveClass(_hostElement, _classNameHostOverflowX, hideOverflow.x);4004addRemoveClass(_hostElement, _classNameHostOverflowY, hideOverflow.y);4005
4006//add or remove rtl class name for styling purposes except when its body, then the scrollbar stays4007if (cssDirectionChanged && !_isBody) {4008addRemoveClass(_hostElement, _classNameHostRTL, _isRTL);4009}4010
4011//manage the resize feature (CSS3 resize "polyfill" for this plugin)4012if (_isBody)4013addClass(_hostElement, _classNameHostResizeDisabled);4014if (resizeChanged) {4015addRemoveClass(_hostElement, _classNameHostResizeDisabled, _resizeNone);4016addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResize, !_resizeNone);4017addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeB, _resizeBoth);4018addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeH, _resizeHorizontal);4019addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV, _resizeVertical);4020}4021
4022//manage the scrollbars general visibility + the scrollbar interactivity (unusable class name)4023if (scrollbarsVisibilityChanged || overflowBehaviorChanged || hideOverflow.c || hasOverflow.c || ignoreOverlayScrollbarHidingChanged) {4024if (ignoreOverlayScrollbarHiding) {4025if (ignoreOverlayScrollbarHidingChanged) {4026removeClass(_hostElement, _classNameHostScrolling);4027if (ignoreOverlayScrollbarHiding) {4028refreshScrollbarsVisibility(false);4029}4030}4031}4032else if (scrollbarsVisibilityAuto) {4033refreshScrollbarsVisibility(canScroll.x, canScroll.y);4034}4035else if (scrollbarsVisibilityVisible) {4036refreshScrollbarsVisibility(true);4037}4038else if (scrollbarsVisibilityHidden) {4039refreshScrollbarsVisibility(false);4040}4041}4042
4043//manage the scrollbars auto hide feature (auto hide them after specific actions)4044if (scrollbarsAutoHideChanged || ignoreOverlayScrollbarHidingChanged) {4045setupHostMouseTouchEvents(!_scrollbarsAutoHideLeave && !_scrollbarsAutoHideMove);4046refreshScrollbarsAutoHide(_scrollbarsAutoHideNever, !_scrollbarsAutoHideNever);4047}4048
4049//manage scrollbars handle length & offset - don't remove!4050if (hostSizeChanged || overflowAmount.c || heightAutoChanged || widthAutoChanged || resizeChanged || boxSizingChanged || paddingAbsoluteChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged) {4051refreshScrollbarHandleLength(true);4052refreshScrollbarHandleOffset(true);4053refreshScrollbarHandleLength(false);4054refreshScrollbarHandleOffset(false);4055}4056
4057//manage interactivity4058if (scrollbarsClickScrollingChanged)4059refreshScrollbarsInteractive(true, scrollbarsClickScrolling);4060if (scrollbarsDragScrollingChanged)4061refreshScrollbarsInteractive(false, scrollbarsDragScrolling);4062
4063//callbacks:4064dispatchCallback('onDirectionChanged', {4065isRTL: _isRTL,4066dir: cssDirection4067}, cssDirectionChanged);4068dispatchCallback('onHostSizeChanged', {4069width: _hostSizeCache.w,4070height: _hostSizeCache.h4071}, hostSizeChanged);4072dispatchCallback('onContentSizeChanged', {4073width: _contentScrollSizeCache.w,4074height: _contentScrollSizeCache.h4075}, contentSizeChanged);4076dispatchCallback('onOverflowChanged', {4077x: hasOverflow.x,4078y: hasOverflow.y,4079xScrollable: hideOverflow.xs,4080yScrollable: hideOverflow.ys,4081clipped: hideOverflow.x || hideOverflow.y4082}, hasOverflow.c || hideOverflow.c);4083dispatchCallback('onOverflowAmountChanged', {4084x: overflowAmount.x,4085y: overflowAmount.y4086}, overflowAmount.c);4087}4088
4089//fix body min size4090if (_isBody && _bodyMinSizeCache && (_hasOverflowCache.c || _bodyMinSizeCache.c)) {4091//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.4092if (!_bodyMinSizeCache.f)4093bodyMinSizeChanged();4094if (_nativeScrollbarIsOverlaid.y && _hasOverflowCache.x)4095_contentElement.css(_strMinMinus + _strWidth, _bodyMinSizeCache.w + _overlayScrollbarDummySize.y);4096if (_nativeScrollbarIsOverlaid.x && _hasOverflowCache.y)4097_contentElement.css(_strMinMinus + _strHeight, _bodyMinSizeCache.h + _overlayScrollbarDummySize.x);4098_bodyMinSizeCache.c = false;4099}4100
4101if (_initialized && changedOptions.updateOnLoad) {4102updateElementsOnLoad();4103}4104
4105//freezeResizeObserver(_sizeObserverElement, false);4106//freezeResizeObserver(_sizeAutoObserverElement, false);4107
4108dispatchCallback('onUpdated', { forced: force });4109}4110
4111/**4112* Updates the found elements of which the load event shall be handled.
4113*/
4114function updateElementsOnLoad() {4115if (!_isTextarea) {4116eachUpdateOnLoad(function (i, updateOnLoadSelector) {4117_contentElement.find(updateOnLoadSelector).each(function (i, el) {4118// if element doesn't have a updateOnLoadCallback applied4119if (COMPATIBILITY.inA(el, _updateOnLoadElms) < 0) {4120_updateOnLoadElms.push(el);4121FRAMEWORK(el)4122.off(_updateOnLoadEventName, updateOnLoadCallback)4123.on(_updateOnLoadEventName, updateOnLoadCallback);4124}4125});4126});4127}4128}4129
4130//==== Options ====//4131
4132/**4133* Sets new options but doesn't call the update method.
4134* @param newOptions The object which contains the new options.
4135* @returns {*} A object which contains the changed options.
4136*/
4137function setOptions(newOptions) {4138var validatedOpts = _pluginsOptions._validate(newOptions, _pluginsOptions._template, true, _currentOptions)4139
4140_currentOptions = extendDeep({}, _currentOptions, validatedOpts._default);4141_currentPreparedOptions = extendDeep({}, _currentPreparedOptions, validatedOpts._prepared);4142
4143return validatedOpts._prepared;4144}4145
4146
4147//==== Structure ====//4148
4149/**4150* Builds or destroys the wrapper and helper DOM elements.
4151* @param destroy Indicates whether the DOM shall be build or destroyed.
4152*/
4153/**4154* Builds or destroys the wrapper and helper DOM elements.
4155* @param destroy Indicates whether the DOM shall be build or destroyed.
4156*/
4157function setupStructureDOM(destroy) {4158var strParent = 'parent';4159var classNameResizeObserverHost = 'os-resize-observer-host';4160var classNameTextareaElementFull = _classNameTextareaElement + _strSpace + _classNameTextInherit;4161var textareaClass = _isTextarea ? _strSpace + _classNameTextInherit : _strEmpty;4162var adoptAttrs = _currentPreparedOptions.textarea.inheritedAttrs;4163var adoptAttrsMap = {};4164var applyAdoptedAttrs = function () {4165var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement;4166each(adoptAttrsMap, function (key, value) {4167if (type(value) == TYPES.s) {4168if (key == LEXICON.c)4169applyAdoptedAttrsElm.addClass(value);4170else4171applyAdoptedAttrsElm.attr(key, value);4172}4173});4174};4175var hostElementClassNames = [4176_classNameHostElement,4177_classNameHostElementForeign,4178_classNameHostTextareaElement,4179_classNameHostResizeDisabled,4180_classNameHostRTL,4181_classNameHostScrollbarHorizontalHidden,4182_classNameHostScrollbarVerticalHidden,4183_classNameHostTransition,4184_classNameHostScrolling,4185_classNameHostOverflow,4186_classNameHostOverflowX,4187_classNameHostOverflowY,4188_classNameThemeNone,4189_classNameTextareaElement,4190_classNameTextInherit,4191_classNameCache].join(_strSpace);4192var hostElementCSS = {};4193
4194//get host element as first element, because that's the most upper element and required for the other elements4195_hostElement = _hostElement || (_isTextarea ? (_domExists ? _targetElement[strParent]()[strParent]()[strParent]()[strParent]() : FRAMEWORK(generateDiv(_classNameHostTextareaElement))) : _targetElement);4196_contentElement = _contentElement || selectOrGenerateDivByClass(_classNameContentElement + textareaClass);4197_viewportElement = _viewportElement || selectOrGenerateDivByClass(_classNameViewportElement + textareaClass);4198_paddingElement = _paddingElement || selectOrGenerateDivByClass(_classNamePaddingElement + textareaClass);4199_sizeObserverElement = _sizeObserverElement || selectOrGenerateDivByClass(classNameResizeObserverHost);4200_textareaCoverElement = _textareaCoverElement || (_isTextarea ? selectOrGenerateDivByClass(_classNameTextareaCoverElement) : undefined);4201
4202//add this class to workaround class changing issues with UI frameworks especially Vue4203if (_domExists)4204addClass(_hostElement, _classNameHostElementForeign);4205
4206//on destroy, remove all generated class names from the host element before collecting the adopted attributes4207//to prevent adopting generated class names4208if (destroy)4209removeClass(_hostElement, hostElementClassNames);4210
4211//collect all adopted attributes4212adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(_strSpace) : adoptAttrs;4213if (COMPATIBILITY.isA(adoptAttrs) && _isTextarea) {4214each(adoptAttrs, function (i, v) {4215if (type(v) == TYPES.s) {4216adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v);4217}4218});4219}4220
4221if (!destroy) {4222if (_isTextarea) {4223if (!_currentPreparedOptions.sizeAutoCapable) {4224hostElementCSS[_strWidth] = _targetElement.css(_strWidth);4225hostElementCSS[_strHeight] = _targetElement.css(_strHeight);4226}4227
4228if (!_domExists)4229_targetElement.addClass(_classNameTextInherit).wrap(_hostElement);4230
4231//jQuery clones elements in wrap functions, so we have to select them again4232_hostElement = _targetElement[strParent]().css(hostElementCSS);4233}4234
4235if (!_domExists) {4236//add the correct class to the target element4237addClass(_targetElement, _isTextarea ? classNameTextareaElementFull : _classNameHostElement);4238
4239//wrap the content into the generated elements to create the required DOM4240_hostElement.wrapInner(_contentElement)4241.wrapInner(_viewportElement)4242.wrapInner(_paddingElement)4243.prepend(_sizeObserverElement);4244
4245//jQuery clones elements in wrap functions, so we have to select them again4246_contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);4247_viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);4248_paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);4249
4250if (_isTextarea) {4251_contentElement.prepend(_textareaCoverElement);4252applyAdoptedAttrs();4253}4254}4255
4256if (_nativeScrollbarStyling)4257addClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);4258if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)4259addClass(_viewportElement, _classNameViewportNativeScrollbarsOverlaid);4260if (_isBody)4261addClass(_htmlElement, _classNameHTMLElement);4262
4263_sizeObserverElementNative = _sizeObserverElement[0];4264_hostElementNative = _hostElement[0];4265_paddingElementNative = _paddingElement[0];4266_viewportElementNative = _viewportElement[0];4267_contentElementNative = _contentElement[0];4268
4269updateViewportAttrsFromTarget();4270}4271else {4272if (_domExists && _initialized) {4273//clear size observer4274_sizeObserverElement.children().remove();4275
4276//remove the style property and classes from already generated elements4277each([_paddingElement, _viewportElement, _contentElement, _textareaCoverElement], function (i, elm) {4278if (elm) {4279removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);4280}4281});4282
4283//add classes to the host element which was removed previously to match the expected DOM4284addClass(_hostElement, _isTextarea ? _classNameHostTextareaElement : _classNameHostElement);4285}4286else {4287//remove size observer4288remove(_sizeObserverElement);4289
4290//unwrap the content to restore DOM4291_contentElement.contents()4292.unwrap()4293.unwrap()4294.unwrap();4295
4296if (_isTextarea) {4297_targetElement.unwrap();4298remove(_hostElement);4299remove(_textareaCoverElement);4300applyAdoptedAttrs();4301}4302}4303
4304if (_isTextarea)4305_targetElement.removeAttr(LEXICON.s);4306
4307if (_isBody)4308removeClass(_htmlElement, _classNameHTMLElement);4309}4310}4311
4312/**4313* Adds or removes all wrapper elements interactivity events.
4314* @param destroy Indicates whether the Events shall be added or removed.
4315*/
4316function setupStructureEvents() {4317var textareaKeyDownRestrictedKeyCodes = [4318112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, //F1 to F12431933, 34, //page up, page down432037, 38, 39, 40, //left, up, right, down arrows432116, 17, 18, 19, 20, 144 //Shift, Ctrl, Alt, Pause, CapsLock, NumLock4322];4323var textareaKeyDownKeyCodesList = [];4324var textareaUpdateIntervalID;4325var scrollStopTimeoutId;4326var scrollStopDelay = 175;4327var strFocus = 'focus';4328
4329function updateTextarea(doClearInterval) {4330textareaUpdate();4331_base.update(_strAuto);4332if (doClearInterval && _autoUpdateRecommended)4333clearInterval(textareaUpdateIntervalID);4334}4335function textareaOnScroll(event) {4336_targetElement[_strScrollLeft](_rtlScrollBehavior.i && _normalizeRTLCache ? 9999999 : 0);4337_targetElement[_strScrollTop](0);4338COMPATIBILITY.prvD(event);4339COMPATIBILITY.stpP(event);4340return false;4341}4342function textareaOnDrop(event) {4343setTimeout(function () {4344if (!_destroyed)4345updateTextarea();4346}, 50);4347}4348function textareaOnFocus() {4349_textareaHasFocus = true;4350addClass(_hostElement, strFocus);4351}4352function textareaOnFocusout() {4353_textareaHasFocus = false;4354textareaKeyDownKeyCodesList = [];4355removeClass(_hostElement, strFocus);4356updateTextarea(true);4357}4358function textareaOnKeyDown(event) {4359var keyCode = event.keyCode;4360
4361if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {4362if (!textareaKeyDownKeyCodesList[LEXICON.l]) {4363updateTextarea();4364textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60);4365}4366if (inArray(keyCode, textareaKeyDownKeyCodesList) < 0)4367textareaKeyDownKeyCodesList.push(keyCode);4368}4369}4370function textareaOnKeyUp(event) {4371var keyCode = event.keyCode;4372var index = inArray(keyCode, textareaKeyDownKeyCodesList);4373
4374if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {4375if (index > -1)4376textareaKeyDownKeyCodesList.splice(index, 1);4377if (!textareaKeyDownKeyCodesList[LEXICON.l])4378updateTextarea(true);4379}4380}4381function contentOnTransitionEnd(event) {4382if (_autoUpdateCache === true)4383return;4384event = event.originalEvent || event;4385if (isSizeAffectingCSSProperty(event.propertyName))4386_base.update(_strAuto);4387}4388function viewportOnScroll(event) {4389if (!_sleeping) {4390if (scrollStopTimeoutId !== undefined)4391clearTimeout(scrollStopTimeoutId);4392else {4393if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)4394refreshScrollbarsAutoHide(true);4395
4396if (!nativeOverlayScrollbarsAreActive())4397addClass(_hostElement, _classNameHostScrolling);4398
4399dispatchCallback('onScrollStart', event);4400}4401
4402//if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset4403//because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point4404//this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove4405if (!_scrollbarsHandlesDefineScrollPos) {4406refreshScrollbarHandleOffset(true);4407refreshScrollbarHandleOffset(false);4408}4409dispatchCallback('onScroll', event);4410
4411scrollStopTimeoutId = setTimeout(function () {4412if (!_destroyed) {4413//OnScrollStop:4414clearTimeout(scrollStopTimeoutId);4415scrollStopTimeoutId = undefined;4416
4417if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)4418refreshScrollbarsAutoHide(false);4419
4420if (!nativeOverlayScrollbarsAreActive())4421removeClass(_hostElement, _classNameHostScrolling);4422
4423dispatchCallback('onScrollStop', event);4424}4425}, scrollStopDelay);4426}4427}4428
4429
4430if (_isTextarea) {4431if (_msieVersion > 9 || !_autoUpdateRecommended) {4432addDestroyEventListener(_targetElement, 'input', updateTextarea);4433}4434else {4435addDestroyEventListener(_targetElement,4436[_strKeyDownEvent, _strKeyUpEvent],4437[textareaOnKeyDown, textareaOnKeyUp]);4438}4439
4440addDestroyEventListener(_targetElement,4441[_strScroll, 'drop', strFocus, strFocus + 'out'],4442[textareaOnScroll, textareaOnDrop, textareaOnFocus, textareaOnFocusout]);4443}4444else {4445addDestroyEventListener(_contentElement, _strTransitionEndEvent, contentOnTransitionEnd);4446}4447addDestroyEventListener(_viewportElement, _strScroll, viewportOnScroll, true);4448}4449
4450
4451//==== Scrollbars ====//4452
4453/**4454* Builds or destroys all scrollbar DOM elements (scrollbar, track, handle)
4455* @param destroy Indicates whether the DOM shall be build or destroyed.
4456*/
4457function setupScrollbarsDOM(destroy) {4458var selectOrGenerateScrollbarDOM = function (isHorizontal) {4459var scrollbarClassName = isHorizontal ? _classNameScrollbarHorizontal : _classNameScrollbarVertical;4460var scrollbar = selectOrGenerateDivByClass(_classNameScrollbar + _strSpace + scrollbarClassName, true);4461var track = selectOrGenerateDivByClass(_classNameScrollbarTrack, scrollbar);4462var handle = selectOrGenerateDivByClass(_classNameScrollbarHandle, scrollbar);4463
4464if (!_domExists && !destroy) {4465scrollbar.append(track);4466track.append(handle);4467}4468
4469return {4470_scrollbar: scrollbar,4471_track: track,4472_handle: handle4473};4474};4475function resetScrollbarDOM(isHorizontal) {4476var scrollbarVars = getScrollbarVars(isHorizontal);4477var scrollbar = scrollbarVars._scrollbar;4478var track = scrollbarVars._track;4479var handle = scrollbarVars._handle;4480
4481if (_domExists && _initialized) {4482each([scrollbar, track, handle], function (i, elm) {4483removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);4484});4485}4486else {4487remove(scrollbar || selectOrGenerateScrollbarDOM(isHorizontal)._scrollbar);4488}4489}4490var horizontalElements;4491var verticalElements;4492
4493if (!destroy) {4494horizontalElements = selectOrGenerateScrollbarDOM(true);4495verticalElements = selectOrGenerateScrollbarDOM();4496
4497_scrollbarHorizontalElement = horizontalElements._scrollbar;4498_scrollbarHorizontalTrackElement = horizontalElements._track;4499_scrollbarHorizontalHandleElement = horizontalElements._handle;4500_scrollbarVerticalElement = verticalElements._scrollbar;4501_scrollbarVerticalTrackElement = verticalElements._track;4502_scrollbarVerticalHandleElement = verticalElements._handle;4503
4504if (!_domExists) {4505_paddingElement.after(_scrollbarVerticalElement);4506_paddingElement.after(_scrollbarHorizontalElement);4507}4508}4509else {4510resetScrollbarDOM(true);4511resetScrollbarDOM();4512}4513}4514
4515/**4516* Initializes all scrollbar interactivity events. (track and handle dragging, clicking, scrolling)
4517* @param isHorizontal True if the target scrollbar is the horizontal scrollbar, false if the target scrollbar is the vertical scrollbar.
4518*/
4519function setupScrollbarEvents(isHorizontal) {4520var scrollbarVars = getScrollbarVars(isHorizontal);4521var scrollbarVarsInfo = scrollbarVars._info;4522var insideIFrame = _windowElementNative.top !== _windowElementNative;4523var xy = scrollbarVars._x_y;4524var XY = scrollbarVars._X_Y;4525var scroll = _strScroll + scrollbarVars._Left_Top;4526var strActive = 'active';4527var strSnapHandle = 'snapHandle';4528var strClickEvent = 'click';4529var scrollDurationFactor = 1;4530var increaseDecreaseScrollAmountKeyCodes = [16, 17]; //shift, ctrl4531var trackTimeout;4532var mouseDownScroll;4533var mouseDownOffset;4534var mouseDownInvertedScale;4535
4536function getPointerPosition(event) {4537return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames.4538}4539function getPreparedScrollbarsOption(name) {4540return _currentPreparedOptions.scrollbars[name];4541}4542function increaseTrackScrollAmount() {4543scrollDurationFactor = 0.5;4544}4545function decreaseTrackScrollAmount() {4546scrollDurationFactor = 1;4547}4548function stopClickEventPropagation(event) {4549COMPATIBILITY.stpP(event);4550}4551function documentKeyDown(event) {4552if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)4553increaseTrackScrollAmount();4554}4555function documentKeyUp(event) {4556if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)4557decreaseTrackScrollAmount();4558}4559function onMouseTouchDownContinue(event) {4560var originalEvent = event.originalEvent || event;4561var isTouchEvent = originalEvent.touches !== undefined;4562return _sleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;4563}4564function documentDragMove(event) {4565if (onMouseTouchDownContinue(event)) {4566var trackLength = scrollbarVarsInfo._trackLength;4567var handleLength = scrollbarVarsInfo._handleLength;4568var scrollRange = scrollbarVarsInfo._maxScroll;4569var scrollRaw = (getPointerPosition(event) - mouseDownOffset) * mouseDownInvertedScale;4570var scrollDeltaPercent = scrollRaw / (trackLength - handleLength);4571var scrollDelta = (scrollRange * scrollDeltaPercent);4572scrollDelta = isFinite(scrollDelta) ? scrollDelta : 0;4573if (_isRTL && isHorizontal && !_rtlScrollBehavior.i)4574scrollDelta *= -1;4575
4576_viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta));4577
4578if (_scrollbarsHandlesDefineScrollPos)4579refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta);4580
4581if (!_supportPassiveEvents)4582COMPATIBILITY.prvD(event);4583}4584else4585documentMouseTouchUp(event);4586}4587function documentMouseTouchUp(event) {4588event = event || event.originalEvent;4589
4590setupResponsiveEventListener(_documentElement,4591[_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],4592[documentDragMove, documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart],4593true);4594COMPATIBILITY.rAF()(function() {4595setupResponsiveEventListener(_documentElement, strClickEvent, stopClickEventPropagation, true, { _capture: true });4596});4597
4598
4599if (_scrollbarsHandlesDefineScrollPos)4600refreshScrollbarHandleOffset(isHorizontal, true);4601
4602_scrollbarsHandlesDefineScrollPos = false;4603removeClass(_bodyElement, _classNameDragging);4604removeClass(scrollbarVars._handle, strActive);4605removeClass(scrollbarVars._track, strActive);4606removeClass(scrollbarVars._scrollbar, strActive);4607
4608mouseDownScroll = undefined;4609mouseDownOffset = undefined;4610mouseDownInvertedScale = 1;4611
4612decreaseTrackScrollAmount();4613
4614if (trackTimeout !== undefined) {4615_base.scrollStop();4616clearTimeout(trackTimeout);4617trackTimeout = undefined;4618}4619
4620if (event) {4621var rect = _hostElementNative[LEXICON.bCR]();4622var mouseInsideHost = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;4623
4624//if mouse is outside host element4625if (!mouseInsideHost)4626hostOnMouseLeave();4627
4628if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)4629refreshScrollbarsAutoHide(false);4630}4631}4632function onHandleMouseTouchDown(event) {4633if (onMouseTouchDownContinue(event))4634onHandleMouseTouchDownAction(event);4635}4636function onHandleMouseTouchDownAction(event) {4637mouseDownScroll = _viewportElement[scroll]();4638mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll;4639if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL)4640mouseDownScroll = mouseDownScroll < 0 ? 0 : mouseDownScroll;4641
4642mouseDownInvertedScale = getHostElementInvertedScale()[xy];4643mouseDownOffset = getPointerPosition(event);4644
4645_scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);4646addClass(_bodyElement, _classNameDragging);4647addClass(scrollbarVars._handle, strActive);4648addClass(scrollbarVars._scrollbar, strActive);4649
4650setupResponsiveEventListener(_documentElement,4651[_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strSelectStartEvent],4652[documentDragMove, documentMouseTouchUp, documentOnSelectStart]);4653COMPATIBILITY.rAF()(function() {4654setupResponsiveEventListener(_documentElement, strClickEvent, stopClickEventPropagation, false, { _capture: true });4655});4656
4657
4658if (_msieVersion || !_documentMixed)4659COMPATIBILITY.prvD(event);4660COMPATIBILITY.stpP(event);4661}4662function onTrackMouseTouchDown(event) {4663if (onMouseTouchDownContinue(event)) {4664var handleToViewportRatio = scrollbarVars._info._handleLength / Math.round(MATH.min(1, _viewportSize[scrollbarVars._w_h] / _contentScrollSizeCache[scrollbarVars._w_h]) * scrollbarVars._info._trackLength);4665var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h] * handleToViewportRatio);4666var scrollBaseDuration = 270 * handleToViewportRatio;4667var scrollFirstIterationDelay = 400 * handleToViewportRatio;4668var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top];4669var ctrlKey = event.ctrlKey;4670var instantScroll = event.shiftKey;4671var instantScrollTransition = instantScroll && ctrlKey;4672var isFirstIteration = true;4673var easing = 'linear';4674var decreaseScroll;4675var finishedCondition;4676var scrollActionFinsished = function (transition) {4677if (_scrollbarsHandlesDefineScrollPos)4678refreshScrollbarHandleOffset(isHorizontal, transition);4679};4680var scrollActionInstantFinished = function () {4681scrollActionFinsished();4682onHandleMouseTouchDownAction(event);4683};4684var scrollAction = function () {4685if (!_destroyed) {4686var mouseOffset = (mouseDownOffset - trackOffset) * mouseDownInvertedScale;4687var handleOffset = scrollbarVarsInfo._handleOffset;4688var trackLength = scrollbarVarsInfo._trackLength;4689var handleLength = scrollbarVarsInfo._handleLength;4690var scrollRange = scrollbarVarsInfo._maxScroll;4691var currScroll = scrollbarVarsInfo._currentScroll;4692var scrollDuration = scrollBaseDuration * scrollDurationFactor;4693var timeoutDelay = isFirstIteration ? MATH.max(scrollFirstIterationDelay, scrollDuration) : scrollDuration;4694var instantScrollPosition = scrollRange * ((mouseOffset - (handleLength / 2)) / (trackLength - handleLength)); // 100% * positionPercent4695var rtlIsNormal = _isRTL && isHorizontal && ((!_rtlScrollBehavior.i && !_rtlScrollBehavior.n) || _normalizeRTLCache);4696var decreaseScrollCondition = rtlIsNormal ? handleOffset < mouseOffset : handleOffset > mouseOffset;4697var scrollObj = {};4698var animationObj = {4699easing: easing,4700step: function (now) {4701if (_scrollbarsHandlesDefineScrollPos) {4702_viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/43404703refreshScrollbarHandleOffset(isHorizontal, now);4704}4705}4706};4707instantScrollPosition = isFinite(instantScrollPosition) ? instantScrollPosition : 0;4708instantScrollPosition = _isRTL && isHorizontal && !_rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;4709
4710//_base.scrollStop();4711
4712if (instantScroll) {4713_viewportElement[scroll](instantScrollPosition); //scroll instantly to new position4714if (instantScrollTransition) {4715//get the scroll position after instant scroll (in case CSS Snap Points are used) to get the correct snapped scroll position4716//and the animation stops at the correct point4717instantScrollPosition = _viewportElement[scroll]();4718//scroll back to the position before instant scrolling so animation can be performed4719_viewportElement[scroll](currScroll);4720
4721instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;4722instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.n ? -instantScrollPosition : instantScrollPosition;4723
4724scrollObj[xy] = instantScrollPosition;4725_base.scroll(scrollObj, extendDeep(animationObj, {4726duration: 130,4727complete: scrollActionInstantFinished4728}));4729}4730else4731scrollActionInstantFinished();4732}4733else {4734decreaseScroll = isFirstIteration ? decreaseScrollCondition : decreaseScroll;4735finishedCondition = rtlIsNormal4736? (decreaseScroll ? handleOffset + handleLength >= mouseOffset : handleOffset <= mouseOffset)4737: (decreaseScroll ? handleOffset <= mouseOffset : handleOffset + handleLength >= mouseOffset);4738
4739if (finishedCondition) {4740clearTimeout(trackTimeout);4741_base.scrollStop();4742trackTimeout = undefined;4743scrollActionFinsished(true);4744}4745else {4746trackTimeout = setTimeout(scrollAction, timeoutDelay);4747
4748scrollObj[xy] = (decreaseScroll ? '-=' : '+=') + scrollDistance;4749_base.scroll(scrollObj, extendDeep(animationObj, {4750duration: scrollDuration4751}));4752}4753isFirstIteration = false;4754}4755}4756};4757if (ctrlKey)4758increaseTrackScrollAmount();4759
4760mouseDownInvertedScale = getHostElementInvertedScale()[xy];4761mouseDownOffset = COMPATIBILITY.page(event)[xy];4762
4763_scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);4764addClass(_bodyElement, _classNameDragging);4765addClass(scrollbarVars._track, strActive);4766addClass(scrollbarVars._scrollbar, strActive);4767
4768setupResponsiveEventListener(_documentElement,4769[_strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],4770[documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart]);4771
4772scrollAction();4773COMPATIBILITY.prvD(event);4774COMPATIBILITY.stpP(event);4775}4776}4777function onTrackMouseTouchEnter(event) {4778//make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move".4779_scrollbarsHandleHovered = true;4780if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)4781refreshScrollbarsAutoHide(true);4782}4783function onTrackMouseTouchLeave(event) {4784_scrollbarsHandleHovered = false;4785if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)4786refreshScrollbarsAutoHide(false);4787}4788function onScrollbarMouseTouchDown(event) {4789COMPATIBILITY.stpP(event);4790}4791
4792addDestroyEventListener(scrollbarVars._handle,4793_strMouseTouchDownEvent,4794onHandleMouseTouchDown);4795addDestroyEventListener(scrollbarVars._track,4796[_strMouseTouchDownEvent, _strMouseEnter, _strMouseLeave],4797[onTrackMouseTouchDown, onTrackMouseTouchEnter, onTrackMouseTouchLeave]);4798addDestroyEventListener(scrollbarVars._scrollbar,4799_strMouseTouchDownEvent,4800onScrollbarMouseTouchDown);4801
4802if (_supportTransition) {4803addDestroyEventListener(scrollbarVars._scrollbar, _strTransitionEndEvent, function (event) {4804if (event.target !== scrollbarVars._scrollbar[0])4805return;4806refreshScrollbarHandleLength(isHorizontal);4807refreshScrollbarHandleOffset(isHorizontal);4808});4809}4810}4811
4812/**4813* Shows or hides the given scrollbar and applied a class name which indicates if the scrollbar is scrollable or not.
4814* @param isHorizontal True if the horizontal scrollbar is the target, false if the vertical scrollbar is the target.
4815* @param shallBeVisible True if the scrollbar shall be shown, false if hidden.
4816* @param canScroll True if the scrollbar is scrollable, false otherwise.
4817*/
4818function refreshScrollbarAppearance(isHorizontal, shallBeVisible, canScroll) {4819var scrollbarHiddenClassName = isHorizontal ? _classNameHostScrollbarHorizontalHidden : _classNameHostScrollbarVerticalHidden;4820var scrollbarElement = isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement;4821
4822addRemoveClass(_hostElement, scrollbarHiddenClassName, !shallBeVisible);4823addRemoveClass(scrollbarElement, _classNameScrollbarUnusable, !canScroll);4824}4825
4826/**4827* Autoshows / autohides both scrollbars with.
4828* @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.
4829* @param delayfree True if the scrollbars shall be hidden without a delay, false or undefined otherwise.
4830*/
4831function refreshScrollbarsAutoHide(shallBeVisible, delayfree) {4832clearTimeout(_scrollbarsAutoHideTimeoutId);4833if (shallBeVisible) {4834//if(_hasOverflowCache.x && _hideOverflowCache.xs)4835removeClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);4836//if(_hasOverflowCache.y && _hideOverflowCache.ys)4837removeClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);4838}4839else {4840var anyActive;4841var strActive = 'active';4842var hide = function () {4843if (!_scrollbarsHandleHovered && !_destroyed) {4844anyActive = _scrollbarHorizontalHandleElement.hasClass(strActive) || _scrollbarVerticalHandleElement.hasClass(strActive);4845if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))4846addClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);4847if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))4848addClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);4849}4850};4851if (_scrollbarsAutoHideDelay > 0 && delayfree !== true)4852_scrollbarsAutoHideTimeoutId = setTimeout(hide, _scrollbarsAutoHideDelay);4853else4854hide();4855}4856}4857
4858/**4859* Refreshes the handle length of the given scrollbar.
4860* @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
4861*/
4862function refreshScrollbarHandleLength(isHorizontal) {4863var handleCSS = {};4864var scrollbarVars = getScrollbarVars(isHorizontal);4865var scrollbarVarsInfo = scrollbarVars._info;4866var digit = 1000000;4867//get and apply intended handle length4868var handleRatio = MATH.min(1, _viewportSize[scrollbarVars._w_h] / _contentScrollSizeCache[scrollbarVars._w_h]);4869handleCSS[scrollbarVars._width_height] = (MATH.floor(handleRatio * 100 * digit) / digit) + '%'; //the last * digit / digit is for flooring to the 4th digit4870
4871if (!nativeOverlayScrollbarsAreActive())4872scrollbarVars._handle.css(handleCSS);4873
4874//measure the handle length to respect min & max length4875scrollbarVarsInfo._handleLength = scrollbarVars._handle[0]['offset' + scrollbarVars._Width_Height];4876scrollbarVarsInfo._handleLengthRatio = handleRatio;4877}4878
4879/**4880* Refreshes the handle offset of the given scrollbar.
4881* @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
4882* @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)
4883*/
4884function refreshScrollbarHandleOffset(isHorizontal, scrollOrTransition) {4885var transition = type(scrollOrTransition) == TYPES.b;4886var transitionDuration = 250;4887var isRTLisHorizontal = _isRTL && isHorizontal;4888var scrollbarVars = getScrollbarVars(isHorizontal);4889var scrollbarVarsInfo = scrollbarVars._info;4890var strTranslateBrace = 'translate(';4891var strTransform = VENDORS._cssProperty('transform');4892var strTransition = VENDORS._cssProperty('transition');4893var nativeScroll = isHorizontal ? _viewportElement[_strScrollLeft]() : _viewportElement[_strScrollTop]();4894var currentScroll = scrollOrTransition === undefined || transition ? nativeScroll : scrollOrTransition;4895
4896//measure the handle length to respect min & max length4897var handleLength = scrollbarVarsInfo._handleLength;4898var trackLength = scrollbarVars._track[0]['offset' + scrollbarVars._Width_Height];4899var handleTrackDiff = trackLength - handleLength;4900var handleCSS = {};4901var transformOffset;4902var translateValue;4903
4904//DONT use the variable '_contentScrollSizeCache[scrollbarVars._w_h]' instead of '_viewportElement[0]['scroll' + scrollbarVars._Width_Height]'4905// because its a bit behind during the small delay when content size updates4906//(delay = mutationObserverContentLag, if its 0 then this var could be used)4907var maxScroll = (_viewportElementNative[_strScroll + scrollbarVars._Width_Height] - _viewportElementNative['client' + scrollbarVars._Width_Height]) * (_rtlScrollBehavior.n && isRTLisHorizontal ? -1 : 1); //* -1 if rtl scroll max is negative4908var getScrollRatio = function (base) {4909return isNaN(base / maxScroll) ? 0 : MATH.max(0, MATH.min(1, base / maxScroll));4910};4911var getHandleOffset = function (scrollRatio) {4912var offset = handleTrackDiff * scrollRatio;4913offset = isNaN(offset) ? 0 : offset;4914offset = (isRTLisHorizontal && !_rtlScrollBehavior.i) ? (trackLength - handleLength - offset) : offset;4915offset = MATH.max(0, offset);4916return offset;4917};4918var scrollRatio = getScrollRatio(nativeScroll);4919var unsnappedScrollRatio = getScrollRatio(currentScroll);4920var handleOffset = getHandleOffset(unsnappedScrollRatio);4921var snappedHandleOffset = getHandleOffset(scrollRatio);4922
4923scrollbarVarsInfo._maxScroll = maxScroll;4924scrollbarVarsInfo._currentScroll = nativeScroll;4925scrollbarVarsInfo._currentScrollRatio = scrollRatio;4926
4927if (_supportTransform) {4928transformOffset = isRTLisHorizontal ? -(trackLength - handleLength - handleOffset) : handleOffset; //in px4929//transformOffset = (transformOffset / trackLength * 100) * (trackLength / handleLength); //in %4930translateValue = isHorizontal ? strTranslateBrace + transformOffset + 'px, 0)' : strTranslateBrace + '0, ' + transformOffset + 'px)';4931
4932handleCSS[strTransform] = translateValue;4933
4934//apply or clear up transition4935if (_supportTransition)4936handleCSS[strTransition] = transition && MATH.abs(handleOffset - scrollbarVarsInfo._handleOffset) > 1 ? getCSSTransitionString(scrollbarVars._handle) + ', ' + (strTransform + _strSpace + transitionDuration + 'ms') : _strEmpty;4937}4938else4939handleCSS[scrollbarVars._left_top] = handleOffset;4940
4941
4942//only apply css if offset has changed and overflow exists.4943if (!nativeOverlayScrollbarsAreActive()) {4944scrollbarVars._handle.css(handleCSS);4945
4946//clear up transition4947if (_supportTransform && _supportTransition && transition) {4948scrollbarVars._handle.one(_strTransitionEndEvent, function () {4949if (!_destroyed)4950scrollbarVars._handle.css(strTransition, _strEmpty);4951});4952}4953}4954
4955scrollbarVarsInfo._handleOffset = handleOffset;4956scrollbarVarsInfo._snappedHandleOffset = snappedHandleOffset;4957scrollbarVarsInfo._trackLength = trackLength;4958}4959
4960/**4961* Refreshes the interactivity of the given scrollbar element.
4962* @param isTrack True if the track element is the target, false if the handle element is the target.
4963* @param value True for interactivity false for no interactivity.
4964*/
4965function refreshScrollbarsInteractive(isTrack, value) {4966var action = value ? 'removeClass' : 'addClass';4967var element1 = isTrack ? _scrollbarHorizontalTrackElement : _scrollbarHorizontalHandleElement;4968var element2 = isTrack ? _scrollbarVerticalTrackElement : _scrollbarVerticalHandleElement;4969var className = isTrack ? _classNameScrollbarTrackOff : _classNameScrollbarHandleOff;4970
4971element1[action](className);4972element2[action](className);4973}4974
4975/**4976* Returns a object which is used for fast access for specific variables.
4977* @param isHorizontal True if the horizontal scrollbar vars shall be accessed, false if the vertical scrollbar vars shall be accessed.
4978* @returns {{wh: string, WH: string, lt: string, _wh: string, _lt: string, t: *, h: *, c: {}, s: *}}
4979*/
4980function getScrollbarVars(isHorizontal) {4981return {4982_width_height: isHorizontal ? _strWidth : _strHeight,4983_Width_Height: isHorizontal ? 'Width' : 'Height',4984_left_top: isHorizontal ? _strLeft : _strTop,4985_Left_Top: isHorizontal ? 'Left' : 'Top',4986_x_y: isHorizontal ? _strX : _strY,4987_X_Y: isHorizontal ? 'X' : 'Y',4988_w_h: isHorizontal ? 'w' : 'h',4989_l_t: isHorizontal ? 'l' : 't',4990_track: isHorizontal ? _scrollbarHorizontalTrackElement : _scrollbarVerticalTrackElement,4991_handle: isHorizontal ? _scrollbarHorizontalHandleElement : _scrollbarVerticalHandleElement,4992_scrollbar: isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement,4993_info: isHorizontal ? _scrollHorizontalInfo : _scrollVerticalInfo4994};4995}4996
4997
4998//==== Scrollbar Corner ====//4999
5000/**5001* Builds or destroys the scrollbar corner DOM element.
5002* @param destroy Indicates whether the DOM shall be build or destroyed.
5003*/
5004function setupScrollbarCornerDOM(destroy) {5005_scrollbarCornerElement = _scrollbarCornerElement || selectOrGenerateDivByClass(_classNameScrollbarCorner, true);5006
5007if (!destroy) {5008if (!_domExists) {5009_hostElement.append(_scrollbarCornerElement);5010}5011}5012else {5013if (_domExists && _initialized) {5014removeClass(_scrollbarCornerElement.removeAttr(LEXICON.s), _classNamesDynamicDestroy);5015}5016else {5017remove(_scrollbarCornerElement);5018}5019}5020}5021
5022/**5023* Initializes all scrollbar corner interactivity events.
5024*/
5025function setupScrollbarCornerEvents() {5026var insideIFrame = _windowElementNative.top !== _windowElementNative;5027var mouseDownPosition = {};5028var mouseDownSize = {};5029var mouseDownInvertedScale = {};5030var reconnectMutationObserver;5031
5032function documentDragMove(event) {5033if (onMouseTouchDownContinue(event)) {5034var pageOffset = getCoordinates(event);5035var hostElementCSS = {};5036if (_resizeHorizontal || _resizeBoth)5037hostElementCSS[_strWidth] = (mouseDownSize.w + (pageOffset.x - mouseDownPosition.x) * mouseDownInvertedScale.x);5038if (_resizeVertical || _resizeBoth)5039hostElementCSS[_strHeight] = (mouseDownSize.h + (pageOffset.y - mouseDownPosition.y) * mouseDownInvertedScale.y);5040_hostElement.css(hostElementCSS);5041COMPATIBILITY.stpP(event);5042}5043else {5044documentMouseTouchUp(event);5045}5046}5047function documentMouseTouchUp(event) {5048var eventIsTrusted = event !== undefined;5049
5050setupResponsiveEventListener(_documentElement,5051[_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],5052[documentOnSelectStart, documentDragMove, documentMouseTouchUp],5053true);5054
5055removeClass(_bodyElement, _classNameDragging);5056if (_scrollbarCornerElement.releaseCapture)5057_scrollbarCornerElement.releaseCapture();5058
5059if (eventIsTrusted) {5060if (reconnectMutationObserver)5061connectMutationObservers();5062_base.update(_strAuto);5063}5064reconnectMutationObserver = false;5065}5066function onMouseTouchDownContinue(event) {5067var originalEvent = event.originalEvent || event;5068var isTouchEvent = originalEvent.touches !== undefined;5069return _sleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;5070}5071function getCoordinates(event) {5072return _msieVersion && insideIFrame ? { x: event.screenX, y: event.screenY } : COMPATIBILITY.page(event);5073}5074
5075addDestroyEventListener(_scrollbarCornerElement, _strMouseTouchDownEvent, function (event) {5076if (onMouseTouchDownContinue(event) && !_resizeNone) {5077if (_mutationObserversConnected) {5078reconnectMutationObserver = true;5079disconnectMutationObservers();5080}5081
5082mouseDownPosition = getCoordinates(event);5083
5084mouseDownSize.w = _hostElementNative[LEXICON.oW] - (!_isBorderBox ? _paddingX : 0);5085mouseDownSize.h = _hostElementNative[LEXICON.oH] - (!_isBorderBox ? _paddingY : 0);5086mouseDownInvertedScale = getHostElementInvertedScale();5087
5088setupResponsiveEventListener(_documentElement,5089[_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],5090[documentOnSelectStart, documentDragMove, documentMouseTouchUp]);5091
5092addClass(_bodyElement, _classNameDragging);5093if (_scrollbarCornerElement.setCapture)5094_scrollbarCornerElement.setCapture();5095
5096COMPATIBILITY.prvD(event);5097COMPATIBILITY.stpP(event);5098}5099});5100}5101
5102
5103//==== Utils ====//5104
5105/**5106* Calls the callback with the given name. The Context of this callback is always _base (this).
5107* @param name The name of the target which shall be called.
5108* @param args The args with which the callback shall be called.
5109* @param dependent Boolean which decides whether the callback shall be fired, undefined is like a "true" value.
5110*/
5111function dispatchCallback(name, args, dependent) {5112if (dependent === false)5113return;5114if (_initialized) {5115var callback = _currentPreparedOptions.callbacks[name];5116var extensionOnName = name;5117var ext;5118
5119if (extensionOnName.substr(0, 2) === 'on')5120extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3);5121
5122if (type(callback) == TYPES.f)5123callback.call(_base, args);5124
5125each(_extensions, function () {5126ext = this;5127if (type(ext.on) == TYPES.f)5128ext.on(extensionOnName, args);5129});5130}5131else if (!_destroyed)5132_callbacksInitQeueue.push({ n: name, a: args });5133}5134
5135/**5136* Sets the "top, right, bottom, left" properties, with a given prefix, of the given css object.
5137* @param targetCSSObject The css object to which the values shall be applied.
5138* @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
5139* @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].
5140* If this argument is undefined the value '' (empty string) will be applied to all properties.
5141*/
5142function setTopRightBottomLeft(targetCSSObject, prefix, values) {5143prefix = prefix || _strEmpty;5144values = values || [_strEmpty, _strEmpty, _strEmpty, _strEmpty];5145
5146targetCSSObject[prefix + _strTop] = values[0];5147targetCSSObject[prefix + _strRight] = values[1];5148targetCSSObject[prefix + _strBottom] = values[2];5149targetCSSObject[prefix + _strLeft] = values[3];5150}5151
5152/**5153* Gets the "top, right, bottom, left" CSS properties of the CSS property with the given prefix from the host element.
5154* @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
5155* @param suffix The suffix of the "top, right, bottom, left" css properties. (example: 'border-' is a valid prefix with '-width' is a valid suffix)
5156* @param zeroX True if the x axis shall be 0.
5157* @param zeroY True if the y axis shall be 0.
5158* @returns {{}} The object which contains the numbers of the read CSS properties.
5159*/
5160function getTopRightBottomLeftHost(prefix, suffix, zeroX, zeroY) {5161suffix = suffix || _strEmpty;5162prefix = prefix || _strEmpty;5163return {5164t: zeroY ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strTop + suffix)),5165r: zeroX ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strRight + suffix)),5166b: zeroY ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strBottom + suffix)),5167l: zeroX ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strLeft + suffix))5168};5169}5170
5171/**5172* Returns the computed CSS transition string from the given element.
5173* @param element The element from which the transition string shall be returned.
5174* @returns {string} The CSS transition string from the given element.
5175*/
5176function getCSSTransitionString(element) {5177var transitionStr = VENDORS._cssProperty('transition');5178var assembledValue = element.css(transitionStr);5179if (assembledValue)5180return assembledValue;5181var regExpString = '\\s*(' + '([^,(]+(\\(.+?\\))?)+' + ')[\\s,]*';5182var regExpMain = new RegExp(regExpString);5183var regExpValidate = new RegExp('^(' + regExpString + ')+$');5184var properties = 'property duration timing-function delay'.split(' ');5185var result = [];5186var strResult;5187var valueArray;5188var i = 0;5189var j;5190var splitCssStyleByComma = function (str) {5191strResult = [];5192if (!str.match(regExpValidate))5193return str;5194while (str.match(regExpMain)) {5195strResult.push(RegExp.$1);5196str = str.replace(regExpMain, _strEmpty);5197}5198
5199return strResult;5200};5201for (; i < properties[LEXICON.l]; i++) {5202valueArray = splitCssStyleByComma(element.css(transitionStr + '-' + properties[i]));5203for (j = 0; j < valueArray[LEXICON.l]; j++)5204result[j] = (result[j] ? result[j] + _strSpace : _strEmpty) + valueArray[j];5205}5206return result.join(', ');5207}5208
5209/**5210* Generates a Regular Expression which matches with a string which starts with 'os-host'.
5211* @param {boolean} withCurrClassNameOption The Regular Expression also matches if the string is the current ClassName option (multiple values splitted by space possible).
5212* @param {boolean} withOldClassNameOption The Regular Expression also matches if the string is the old ClassName option (multiple values splitted by space possible).
5213*/
5214function createHostClassNameRegExp(withCurrClassNameOption, withOldClassNameOption) {5215var i;5216var split;5217var appendix;5218var appendClasses = function (classes, condition) {5219appendix = '';5220if (condition && typeof classes == TYPES.s) {5221split = classes.split(_strSpace);5222for (i = 0; i < split[LEXICON.l]; i++)5223appendix += '|' + split[i] + '$';5224// split[i].replace(/[.*+?^${}()|[\]\\]/g, '\\$&') for escaping regex characters5225}5226return appendix;5227};5228
5229return new RegExp(5230'(^' + _classNameHostElement + '([-_].+|)$)' +5231appendClasses(_classNameCache, withCurrClassNameOption) +5232appendClasses(_oldClassName, withOldClassNameOption), 'g');5233}5234
5235/**5236* Calculates the host-elements inverted scale. (invertedScale = 1 / scale)
5237* @returns {{x: number, y: number}} The scale of the host-element.
5238*/
5239function getHostElementInvertedScale() {5240var rect = _paddingElementNative[LEXICON.bCR]();5241return {5242x: _supportTransform ? 1 / (MATH.round(rect.width) / _paddingElementNative[LEXICON.oW]) || 1 : 1,5243y: _supportTransform ? 1 / (MATH.round(rect.height) / _paddingElementNative[LEXICON.oH]) || 1 : 15244};5245}5246
5247/**5248* Checks whether the given object is a HTMLElement.
5249* @param o The object which shall be checked.
5250* @returns {boolean} True the given object is a HTMLElement, false otherwise.
5251*/
5252function isHTMLElement(o) {5253var strOwnerDocument = 'ownerDocument';5254var strHTMLElement = 'HTMLElement';5255var wnd = o && o[strOwnerDocument] ? (o[strOwnerDocument].parentWindow || window) : window;5256return (5257typeof wnd[strHTMLElement] == TYPES.o ? o instanceof wnd[strHTMLElement] : //DOM25258o && typeof o == TYPES.o && o !== null && o.nodeType === 1 && typeof o.nodeName == TYPES.s5259);5260}5261
5262/**5263* Compares 2 arrays and returns the differences between them as a array.
5264* @param a1 The first array which shall be compared.
5265* @param a2 The second array which shall be compared.
5266* @returns {Array} The differences between the two arrays.
5267*/
5268function getArrayDifferences(a1, a2) {5269var a = [];5270var diff = [];5271var i;5272var k;5273for (i = 0; i < a1.length; i++)5274a[a1[i]] = true;5275for (i = 0; i < a2.length; i++) {5276if (a[a2[i]])5277delete a[a2[i]];5278else5279a[a2[i]] = true;5280}5281for (k in a)5282diff.push(k);5283return diff;5284}5285
5286/**5287* Returns Zero or the number to which the value can be parsed.
5288* @param value The value which shall be parsed.
5289* @param toFloat Indicates whether the number shall be parsed to a float.
5290*/
5291function parseToZeroOrNumber(value, toFloat) {5292var num = toFloat ? parseFloat(value) : parseInt(value, 10);5293return isNaN(num) ? 0 : num;5294}5295
5296/**5297* Gets several information of the textarea and returns them as a object or undefined if the browser doesn't support it.
5298* @returns {{cursorRow: Number, cursorCol, rows: Number, cols: number, wRow: number, pos: number, max : number}} or undefined if not supported.
5299*/
5300function getTextareaInfo() {5301//read needed values5302var textareaCursorPosition = _targetElementNative.selectionStart;5303if (textareaCursorPosition === undefined)5304return;5305
5306var textareaValue = _targetElement.val();5307var textareaLength = textareaValue[LEXICON.l];5308var textareaRowSplit = textareaValue.split('\n');5309var textareaLastRow = textareaRowSplit[LEXICON.l];5310var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split('\n');5311var widestRow = 0;5312var textareaLastCol = 0;5313var cursorRow = textareaCurrentCursorRowSplit[LEXICON.l];5314var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[LEXICON.l] - 1][LEXICON.l];5315var rowCols;5316var i;5317
5318//get widest Row and the last column of the textarea5319for (i = 0; i < textareaRowSplit[LEXICON.l]; i++) {5320rowCols = textareaRowSplit[i][LEXICON.l];5321if (rowCols > textareaLastCol) {5322widestRow = i + 1;5323textareaLastCol = rowCols;5324}5325}5326
5327return {5328_cursorRow: cursorRow, //cursorRow5329_cursorColumn: cursorCol, //cursorCol5330_rows: textareaLastRow, //rows5331_columns: textareaLastCol, //cols5332_widestRow: widestRow, //wRow5333_cursorPosition: textareaCursorPosition, //pos5334_cursorMax: textareaLength //max5335};5336}5337
5338/**5339* Determines whether native overlay scrollbars are active.
5340* @returns {boolean} True if native overlay scrollbars are active, false otherwise.
5341*/
5342function nativeOverlayScrollbarsAreActive() {5343return (_ignoreOverlayScrollbarHidingCache && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y));5344}5345
5346/**5347* Gets the element which is used to measure the content size.
5348* @returns {*} TextareaCover if target element is textarea else the ContentElement.
5349*/
5350function getContentMeasureElement() {5351return _isTextarea ? _textareaCoverElement[0] : _contentElementNative;5352}5353
5354/**5355* Generates a string which represents a HTML div with the given classes or attributes.
5356* @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".)
5357* @param content The content of the div as string.
5358* @returns {string} The concated string which represents a HTML div and its content.
5359*/
5360function generateDiv(classesOrAttrs, content) {5361return '<div ' + (classesOrAttrs ? type(classesOrAttrs) == TYPES.s ?5362'class="' + classesOrAttrs + '"' :5363(function () {5364var key;5365var attrs = _strEmpty;5366if (FRAMEWORK.isPlainObject(classesOrAttrs)) {5367for (key in classesOrAttrs)5368attrs += (key === 'c' ? 'class' : key) + '="' + classesOrAttrs[key] + '" ';5369}5370return attrs;5371})() :5372_strEmpty) +5373'>' +5374(content || _strEmpty) +5375'</div>';5376}5377
5378/**5379* Selects or generates a div with the given class attribute.
5380* @param className The class names (divided by spaces) of the div which shall be selected or generated.
5381* @param selectParentOrOnlyChildren The parent element from which of the element shall be selected. (if undefined or boolean its hostElement)
5382* If its a boolean it decides whether only the children of the host element shall be selected.
5383* @returns {*} The generated or selected element.
5384*/
5385function selectOrGenerateDivByClass(className, selectParentOrOnlyChildren) {5386var onlyChildren = type(selectParentOrOnlyChildren) == TYPES.b;5387var selectParent = onlyChildren ? _hostElement : (selectParentOrOnlyChildren || _hostElement);5388
5389return (_domExists && !selectParent[LEXICON.l])5390? null5391: _domExists5392? selectParent[onlyChildren ? 'children' : 'find'](_strDot + className.replace(/\s/g, _strDot)).eq(0)5393: FRAMEWORK(generateDiv(className))5394}5395
5396/**5397* Gets the value of the given property from the given object.
5398* @param obj The object from which the property value shall be got.
5399* @param path The property of which the value shall be got.
5400* @returns {*} Returns the value of the searched property or undefined of the property wasn't found.
5401*/
5402function getObjectPropVal(obj, path) {5403var splits = path.split(_strDot);5404var i = 0;5405var val;5406for (; i < splits.length; i++) {5407if (!obj[LEXICON.hOP](splits[i]))5408return;5409val = obj[splits[i]];5410if (i < splits.length && type(val) == TYPES.o)5411obj = val;5412}5413return val;5414}5415
5416/**5417* Sets the value of the given property from the given object.
5418* @param obj The object from which the property value shall be set.
5419* @param path The property of which the value shall be set.
5420* @param val The value of the property which shall be set.
5421*/
5422function setObjectPropVal(obj, path, val) {5423var splits = path.split(_strDot);5424var splitsLength = splits.length;5425var i = 0;5426var extendObj = {};5427var extendObjRoot = extendObj;5428for (; i < splitsLength; i++)5429extendObj = extendObj[splits[i]] = i + 1 < splitsLength ? {} : val;5430FRAMEWORK.extend(obj, extendObjRoot, true);5431}5432
5433/**5434* Runs a action for each selector inside the updateOnLoad option.
5435* @param {Function} action The action for each updateOnLoad selector, the arguments the function takes is the index and the value (the selector).
5436*/
5437function eachUpdateOnLoad(action) {5438var updateOnLoad = _currentPreparedOptions.updateOnLoad;5439updateOnLoad = type(updateOnLoad) == TYPES.s ? updateOnLoad.split(_strSpace) : updateOnLoad;5440
5441if (COMPATIBILITY.isA(updateOnLoad) && !_destroyed) {5442each(updateOnLoad, action);5443}5444}5445
5446
5447//==== Utils Cache ====//5448
5449/**5450* Compares two values or objects and returns true if they aren't equal.
5451* @param current The first value or object which shall be compared.
5452* @param cache The second value or object which shall be compared.
5453* @param force If true the returned value is always true.
5454* @returns {boolean} True if both values or objects aren't equal or force is true, false otherwise.
5455*/
5456function checkCache(current, cache, force) {5457if (force)5458return force;5459if (type(current) == TYPES.o && type(cache) == TYPES.o) {5460for (var prop in current) {5461if (prop !== 'c') {5462if (current[LEXICON.hOP](prop) && cache[LEXICON.hOP](prop)) {5463if (checkCache(current[prop], cache[prop]))5464return true;5465}5466else {5467return true;5468}5469}5470}5471}5472else {5473return current !== cache;5474}5475return false;5476}5477
5478
5479//==== Shortcuts ====//5480
5481/**5482* jQuery extend method shortcut with a appended "true" as first argument.
5483*/
5484function extendDeep() {5485return FRAMEWORK.extend.apply(this, [true].concat([].slice.call(arguments)));5486}5487
5488/**5489* jQuery addClass method shortcut.
5490*/
5491function addClass(el, classes) {5492return _frameworkProto.addClass.call(el, classes);5493}5494
5495/**5496* jQuery removeClass method shortcut.
5497*/
5498function removeClass(el, classes) {5499return _frameworkProto.removeClass.call(el, classes);5500}5501
5502/**5503* Adds or removes the given classes dependent on the boolean value. True for add, false for remove.
5504*/
5505function addRemoveClass(el, classes, doAdd) {5506return doAdd ? addClass(el, classes) : removeClass(el, classes);5507}5508
5509/**5510* jQuery remove method shortcut.
5511*/
5512function remove(el) {5513return _frameworkProto.remove.call(el);5514}5515
5516/**5517* Finds the first child element with the given selector of the given element.
5518* @param el The root element from which the selector shall be valid.
5519* @param selector The selector of the searched element.
5520* @returns {*} The first element which is a child of the given element and matches the givens selector.
5521*/
5522function findFirst(el, selector) {5523return _frameworkProto.find.call(el, selector).eq(0);5524}5525
5526
5527//==== API ====//5528
5529/**5530* 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.
5531* This behavior can be reset by calling the update method.
5532*/
5533_base.sleep = function () {5534_sleeping = true;5535};5536
5537/**5538* Updates the plugin and DOM to the current options.
5539* This method should only be called if a update is 100% required.
5540* @param force True if every property shall be updated and the cache shall be ignored.
5541* !INTERNAL USAGE! : force can be a string "auto", "sync" or "zoom" too
5542* 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.
5543* 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.
5544* if "zoom" then a update takes place where it's assumed that content and host size changed
5545* @returns {boolean|undefined}
5546* If force is "sync" then a boolean is returned which indicates whether a update was needed due to pending changes.
5547* If force is "auto" then a boolean is returned whether a update was needed due to attribute or size changes.
5548* undefined otherwise.
5549*/
5550_base.update = function (force) {5551if (_destroyed)5552return;5553
5554var attrsChanged;5555var contentSizeC;5556var isString = type(force) == TYPES.s;5557var doUpdateAuto;5558var mutHost;5559var mutContent;5560
5561if (isString) {5562if (force === _strAuto) {5563attrsChanged = meaningfulAttrsChanged();5564contentSizeC = updateAutoContentSizeChanged();5565doUpdateAuto = attrsChanged || contentSizeC;5566if (doUpdateAuto) {5567update({5568_contentSizeChanged: contentSizeC,5569_changedOptions: _initialized ? undefined : _currentPreparedOptions5570});5571}5572}5573else if (force === _strSync) {5574if (_mutationObserversConnected) {5575mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords());5576mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords());5577}5578else {5579mutHost = _base.update(_strAuto);5580}5581}5582else if (force === 'zoom') {5583update({5584_hostSizeChanged: true,5585_contentSizeChanged: true5586});5587}5588}5589else {5590force = _sleeping || force;5591_sleeping = false;5592if (!_base.update(_strSync) || force)5593update({ _force: force });5594}5595
5596updateElementsOnLoad();5597
5598return doUpdateAuto || mutHost || mutContent;5599};5600
5601/**5602Gets or sets the current options. The update method will be called automatically if new options were set.
5603* @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.
5604* @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.
5605* @returns {*}
5606*/
5607_base.options = function (newOptions, value) {5608var option = {};5609var changedOps;5610
5611//return current options if newOptions are undefined or empty5612if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) {5613if (type(newOptions) == TYPES.s) {5614if (arguments.length > 1) {5615setObjectPropVal(option, newOptions, value);5616changedOps = setOptions(option);5617}5618else5619return getObjectPropVal(_currentOptions, newOptions);5620}5621else5622return _currentOptions;5623}5624else {5625changedOps = setOptions(newOptions);5626}5627
5628if (!FRAMEWORK.isEmptyObject(changedOps)) {5629update({ _changedOptions: changedOps });5630}5631};5632
5633/**5634* Restore the DOM, disconnects all observers, remove all resize observers and put the instance to sleep.
5635*/
5636_base.destroy = function () {5637if (_destroyed)5638return;5639
5640//remove this instance from auto update loop5641autoUpdateLoop.remove(_base);5642
5643//disconnect all mutation observers5644disconnectMutationObservers();5645
5646//remove all resize observers5647setupResizeObserver(_sizeObserverElement);5648setupResizeObserver(_sizeAutoObserverElement);5649
5650//remove all extensions5651for (var extName in _extensions)5652_base.removeExt(extName);5653
5654//remove all 'destroy' events5655while (_destroyEvents[LEXICON.l] > 0)5656_destroyEvents.pop()();5657
5658//remove all events from host element5659setupHostMouseTouchEvents(true);5660
5661//remove all helper / detection elements5662if (_contentGlueElement)5663remove(_contentGlueElement);5664if (_contentArrangeElement)5665remove(_contentArrangeElement);5666if (_sizeAutoObserverAdded)5667remove(_sizeAutoObserverElement);5668
5669//remove all generated DOM5670setupScrollbarsDOM(true);5671setupScrollbarCornerDOM(true);5672setupStructureDOM(true);5673
5674//remove all generated image load events5675for (var i = 0; i < _updateOnLoadElms[LEXICON.l]; i++)5676FRAMEWORK(_updateOnLoadElms[i]).off(_updateOnLoadEventName, updateOnLoadCallback);5677_updateOnLoadElms = undefined;5678
5679_destroyed = true;5680_sleeping = true;5681
5682//remove this instance from the instances list5683INSTANCES(pluginTargetElement, 0);5684dispatchCallback('onDestroyed');5685
5686//remove all properties and methods5687//for (var property in _base)5688// delete _base[property];5689//_base = undefined;5690};5691
5692/**5693* Scrolls to a given position or element.
5694* @param coordinates
5695* 1. Can be "coordinates" which looks like:
5696* { x : ?, y : ? } OR Object with x and y properties
5697* { left : ?, top : ? } OR Object with left and top properties
5698* { l : ?, t : ? } OR Object with l and t properties
5699* [ ?, ? ] OR Array where the first two element are the coordinates (first is x, second is y)
5700* ? A single value which stays for both axis
5701* A value can be a number, a string or a calculation.
5702*
5703* Operators:
5704* [NONE] The current scroll will be overwritten by the value.
5705* '+=' The value will be added to the current scroll offset
5706* '-=' The value will be subtracted from the current scroll offset
5707* '*=' The current scroll wil be multiplicated by the value.
5708* '/=' The current scroll wil be divided by the value.
5709*
5710* Units:
5711* [NONE] The value is the final scroll amount. final = (value * 1)
5712* 'px' Same as none
5713* '%' The value is dependent on the current scroll value. final = ((currentScrollValue / 100) * value)
5714* 'vw' The value is multiplicated by the viewport width. final = (value * viewportWidth)
5715* 'vh' The value is multiplicated by the viewport height. final = (value * viewportHeight)
5716*
5717* example final values:
5718* 200, '200px', '50%', '1vw', '1vh', '+=200', '/=1vw', '*=2px', '-=5vh', '+=33%', '+= 50% - 2px', '-= 1vw - 50%'
5719*
5720* 2. Can be a HTML or jQuery element:
5721* The final scroll offset is the offset (without margin) of the given HTML / jQuery element.
5722*
5723* 3. Can be a object with a HTML or jQuery element with additional settings:
5724* {
5725* el : [HTMLElement, jQuery element], MUST be specified, else this object isn't valid.
5726* scroll : [string, array, object], Default value is 'always'.
5727* block : [string, array, object], Default value is 'begin'.
5728* margin : [number, boolean, array, object] Default value is false.
5729* }
5730*
5731* Possible scroll settings are:
5732* 'always' Scrolls always.
5733* 'ifneeded' Scrolls only if the element isnt fully in view.
5734* 'never' Scrolls never.
5735*
5736* Possible block settings are:
5737* 'begin' Both axis shall be docked to the "begin" edge. - The element will be docked to the top and left edge of the viewport.
5738* '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.)
5739* 'center' Both axis shall be docked to "center". - The element will be centered in the viewport.
5740* 'nearest' The element will be docked to the nearest edge(s).
5741*
5742* Possible margin settings are: -- The actual margin of the element wont be affect, this option affects only the final scroll offset.
5743* [BOOLEAN] If true the css margin of the element will be used, if false no margin will be used.
5744* [NUMBER] The margin will be used for all edges.
5745*
5746* @param duration The duration of the scroll animation, OR a jQuery animation configuration object.
5747* @param easing The animation easing.
5748* @param complete The animation complete callback.
5749* @returns {{
5750* position: {x: number, y: number},
5751* ratio: {x: number, y: number},
5752* max: {x: number, y: number},
5753* handleOffset: {x: number, y: number},
5754* handleLength: {x: number, y: number},
5755* handleLengthRatio: {x: number, y: number}, t
5756* rackLength: {x: number, y: number},
5757* isRTL: boolean,
5758* isRTLNormalized: boolean
5759* }}
5760*/
5761_base.scroll = function (coordinates, duration, easing, complete) {5762if (arguments.length === 0 || coordinates === undefined) {5763var infoX = _scrollHorizontalInfo;5764var infoY = _scrollVerticalInfo;5765var normalizeInvert = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.i;5766var normalizeNegate = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.n;5767var scrollX = infoX._currentScroll;5768var scrollXRatio = infoX._currentScrollRatio;5769var maxScrollX = infoX._maxScroll;5770scrollXRatio = normalizeInvert ? 1 - scrollXRatio : scrollXRatio;5771scrollX = normalizeInvert ? maxScrollX - scrollX : scrollX;5772scrollX *= normalizeNegate ? -1 : 1;5773maxScrollX *= normalizeNegate ? -1 : 1;5774
5775return {5776position: {5777x: scrollX,5778y: infoY._currentScroll5779},5780ratio: {5781x: scrollXRatio,5782y: infoY._currentScrollRatio5783},5784max: {5785x: maxScrollX,5786y: infoY._maxScroll5787},5788handleOffset: {5789x: infoX._handleOffset,5790y: infoY._handleOffset5791},5792handleLength: {5793x: infoX._handleLength,5794y: infoY._handleLength5795},5796handleLengthRatio: {5797x: infoX._handleLengthRatio,5798y: infoY._handleLengthRatio5799},5800trackLength: {5801x: infoX._trackLength,5802y: infoY._trackLength5803},5804snappedHandleOffset: {5805x: infoX._snappedHandleOffset,5806y: infoY._snappedHandleOffset5807},5808isRTL: _isRTL,5809isRTLNormalized: _normalizeRTLCache5810};5811}5812
5813_base.update(_strSync);5814
5815var normalizeRTL = _normalizeRTLCache;5816var coordinatesXAxisProps = [_strX, _strLeft, 'l'];5817var coordinatesYAxisProps = [_strY, _strTop, 't'];5818var coordinatesOperators = ['+=', '-=', '*=', '/='];5819var durationIsObject = type(duration) == TYPES.o;5820var completeCallback = durationIsObject ? duration.complete : complete;5821var i;5822var finalScroll = {};5823var specialEasing = {};5824var doScrollLeft;5825var doScrollTop;5826var animationOptions;5827var strEnd = 'end';5828var strBegin = 'begin';5829var strCenter = 'center';5830var strNearest = 'nearest';5831var strAlways = 'always';5832var strNever = 'never';5833var strIfNeeded = 'ifneeded';5834var strLength = LEXICON.l;5835var settingsAxis;5836var settingsScroll;5837var settingsBlock;5838var settingsMargin;5839var finalElement;5840var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx'];5841var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest];5842var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded];5843var coordinatesIsElementObj = coordinates[LEXICON.hOP]('el');5844var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates;5845var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false;5846var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement);5847var updateScrollbarInfos = function () {5848if (doScrollLeft)5849refreshScrollbarHandleOffset(true);5850if (doScrollTop)5851refreshScrollbarHandleOffset(false);5852};5853var proxyCompleteCallback = type(completeCallback) != TYPES.f ? undefined : function () {5854updateScrollbarInfos();5855completeCallback();5856};5857function checkSettingsStringValue(currValue, allowedValues) {5858for (i = 0; i < allowedValues[strLength]; i++) {5859if (currValue === allowedValues[i])5860return true;5861}5862return false;5863}5864function getRawScroll(isX, coordinates) {5865var coordinateProps = isX ? coordinatesXAxisProps : coordinatesYAxisProps;5866coordinates = type(coordinates) == TYPES.s || type(coordinates) == TYPES.n ? [coordinates, coordinates] : coordinates;5867
5868if (COMPATIBILITY.isA(coordinates))5869return isX ? coordinates[0] : coordinates[1];5870else if (type(coordinates) == TYPES.o) {5871//decides RTL normalization "hack" with .n5872//normalizeRTL = type(coordinates.n) == TYPES.b ? coordinates.n : normalizeRTL;5873for (i = 0; i < coordinateProps[strLength]; i++)5874if (coordinateProps[i] in coordinates)5875return coordinates[coordinateProps[i]];5876}5877}5878function getFinalScroll(isX, rawScroll) {5879var isString = type(rawScroll) == TYPES.s;5880var operator;5881var amount;5882var scrollInfo = isX ? _scrollHorizontalInfo : _scrollVerticalInfo;5883var currScroll = scrollInfo._currentScroll;5884var maxScroll = scrollInfo._maxScroll;5885var mult = ' * ';5886var finalValue;5887var isRTLisX = _isRTL && isX;5888var normalizeShortcuts = isRTLisX && _rtlScrollBehavior.n && !normalizeRTL;5889var strReplace = 'replace';5890var evalFunc = eval;5891var possibleOperator;5892if (isString) {5893//check operator5894if (rawScroll[strLength] > 2) {5895possibleOperator = rawScroll.substr(0, 2);5896if (inArray(possibleOperator, coordinatesOperators) > -1)5897operator = possibleOperator;5898}5899
5900//calculate units and shortcuts5901rawScroll = operator ? rawScroll.substr(2) : rawScroll;5902rawScroll = rawScroll5903[strReplace](/min/g, 0) //'min' = 0%5904[strReplace](/</g, 0) //'<' = 0%5905[strReplace](/max/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'max' = 100%5906[strReplace](/>/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'>' = 100%5907[strReplace](/px/g, _strEmpty)5908[strReplace](/%/g, mult + (maxScroll * (isRTLisX && _rtlScrollBehavior.n ? -1 : 1) / 100.0))5909[strReplace](/vw/g, mult + _viewportSize.w)5910[strReplace](/vh/g, mult + _viewportSize.h);5911amount = parseToZeroOrNumber(isNaN(rawScroll) ? parseToZeroOrNumber(evalFunc(rawScroll), true).toFixed() : rawScroll);5912}5913else {5914amount = rawScroll;5915}5916
5917if (amount !== undefined && !isNaN(amount) && type(amount) == TYPES.n) {5918var normalizeIsRTLisX = normalizeRTL && isRTLisX;5919var operatorCurrScroll = currScroll * (normalizeIsRTLisX && _rtlScrollBehavior.n ? -1 : 1);5920var invert = normalizeIsRTLisX && _rtlScrollBehavior.i;5921var negate = normalizeIsRTLisX && _rtlScrollBehavior.n;5922operatorCurrScroll = invert ? (maxScroll - operatorCurrScroll) : operatorCurrScroll;5923switch (operator) {5924case '+=':5925finalValue = operatorCurrScroll + amount;5926break;5927case '-=':5928finalValue = operatorCurrScroll - amount;5929break;5930case '*=':5931finalValue = operatorCurrScroll * amount;5932break;5933case '/=':5934finalValue = operatorCurrScroll / amount;5935break;5936default:5937finalValue = amount;5938break;5939}5940finalValue = invert ? maxScroll - finalValue : finalValue;5941finalValue *= negate ? -1 : 1;5942finalValue = isRTLisX && _rtlScrollBehavior.n ? MATH.min(0, MATH.max(maxScroll, finalValue)) : MATH.max(0, MATH.min(maxScroll, finalValue));5943}5944return finalValue === currScroll ? undefined : finalValue;5945}5946function getPerAxisValue(value, valueInternalType, defaultValue, allowedValues) {5947var resultDefault = [defaultValue, defaultValue];5948var valueType = type(value);5949var valueArrLength;5950var valueArrItem;5951
5952//value can be [ string, or array of two strings ]5953if (valueType == valueInternalType) {5954value = [value, value];5955}5956else if (valueType == TYPES.a) {5957valueArrLength = value[strLength];5958if (valueArrLength > 2 || valueArrLength < 1)5959value = resultDefault;5960else {5961if (valueArrLength === 1)5962value[1] = defaultValue;5963for (i = 0; i < valueArrLength; i++) {5964valueArrItem = value[i];5965if (type(valueArrItem) != valueInternalType || !checkSettingsStringValue(valueArrItem, allowedValues)) {5966value = resultDefault;5967break;5968}5969}5970}5971}5972else if (valueType == TYPES.o)5973value = [value[_strX] || defaultValue, value[_strY] || defaultValue];5974else5975value = resultDefault;5976return { x: value[0], y: value[1] };5977}5978function generateMargin(marginTopRightBottomLeftArray) {5979var result = [];5980var currValue;5981var currValueType;5982var valueDirections = [_strTop, _strRight, _strBottom, _strLeft];5983for (i = 0; i < marginTopRightBottomLeftArray[strLength]; i++) {5984if (i === valueDirections[strLength])5985break;5986currValue = marginTopRightBottomLeftArray[i];5987currValueType = type(currValue);5988if (currValueType == TYPES.b)5989result.push(currValue ? parseToZeroOrNumber(finalElement.css(_strMarginMinus + valueDirections[i])) : 0);5990else5991result.push(currValueType == TYPES.n ? currValue : 0);5992}5993return result;5994}5995
5996if (possibleElementIsJQuery || possibleElementIsHTMLElement) {5997//get settings5998var margin = coordinatesIsElementObj ? coordinates.margin : 0;5999var axis = coordinatesIsElementObj ? coordinates.axis : 0;6000var scroll = coordinatesIsElementObj ? coordinates.scroll : 0;6001var block = coordinatesIsElementObj ? coordinates.block : 0;6002var marginDefault = [0, 0, 0, 0];6003var marginType = type(margin);6004var marginLength;6005finalElement = possibleElementIsJQuery ? possibleElement : FRAMEWORK(possibleElement);6006
6007if (finalElement[strLength] > 0) {6008//margin can be [ boolean, number, array of 2, array of 4, object ]6009if (marginType == TYPES.n || marginType == TYPES.b)6010margin = generateMargin([margin, margin, margin, margin]);6011else if (marginType == TYPES.a) {6012marginLength = margin[strLength];6013if (marginLength === 2)6014margin = generateMargin([margin[0], margin[1], margin[0], margin[1]]);6015else if (marginLength >= 4)6016margin = generateMargin(margin);6017else6018margin = marginDefault;6019}6020else if (marginType == TYPES.o)6021margin = generateMargin([margin[_strTop], margin[_strRight], margin[_strBottom], margin[_strLeft]]);6022else6023margin = marginDefault;6024
6025//block = type(block) === TYPES.b ? block ? [ strNearest, strBegin ] : [ strNearest, strEnd ] : block;6026settingsAxis = checkSettingsStringValue(axis, elementObjSettingsAxisValues) ? axis : 'xy';6027settingsScroll = getPerAxisValue(scroll, TYPES.s, strAlways, elementObjSettingsScrollValues);6028settingsBlock = getPerAxisValue(block, TYPES.s, strBegin, elementObjSettingsBlockValues);6029settingsMargin = margin;6030
6031var viewportScroll = {6032l: _scrollHorizontalInfo._currentScroll,6033t: _scrollVerticalInfo._currentScroll6034};6035// use padding element instead of viewport element because padding element has never padding, margin or position applied.6036var viewportOffset = _paddingElement.offset();6037
6038//get coordinates6039var elementOffset = finalElement.offset();6040var doNotScroll = {6041x: settingsScroll.x == strNever || settingsAxis == _strY,6042y: settingsScroll.y == strNever || settingsAxis == _strX6043};6044elementOffset[_strTop] -= settingsMargin[0];6045elementOffset[_strLeft] -= settingsMargin[3];6046var elementScrollCoordinates = {6047x: MATH.round(elementOffset[_strLeft] - viewportOffset[_strLeft] + viewportScroll.l),6048y: MATH.round(elementOffset[_strTop] - viewportOffset[_strTop] + viewportScroll.t)6049};6050if (_isRTL) {6051if (!_rtlScrollBehavior.n && !_rtlScrollBehavior.i)6052elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + viewportScroll.l);6053if (_rtlScrollBehavior.n && normalizeRTL)6054elementScrollCoordinates.x *= -1;6055if (_rtlScrollBehavior.i && normalizeRTL)6056elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + (_scrollHorizontalInfo._maxScroll - viewportScroll.l));6057}6058
6059//measuring is required6060if (settingsBlock.x != strBegin || settingsBlock.y != strBegin || settingsScroll.x == strIfNeeded || settingsScroll.y == strIfNeeded || _isRTL) {6061var measuringElm = finalElement[0];6062var rawElementSize = _supportTransform ? measuringElm[LEXICON.bCR]() : {6063width: measuringElm[LEXICON.oW],6064height: measuringElm[LEXICON.oH]6065};6066var elementSize = {6067w: rawElementSize[_strWidth] + settingsMargin[3] + settingsMargin[1],6068h: rawElementSize[_strHeight] + settingsMargin[0] + settingsMargin[2]6069};6070var finalizeBlock = function (isX) {6071var vars = getScrollbarVars(isX);6072var wh = vars._w_h;6073var lt = vars._left_top;6074var xy = vars._x_y;6075var blockIsEnd = settingsBlock[xy] == (isX ? _isRTL ? strBegin : strEnd : strEnd);6076var blockIsCenter = settingsBlock[xy] == strCenter;6077var blockIsNearest = settingsBlock[xy] == strNearest;6078var scrollNever = settingsScroll[xy] == strNever;6079var scrollIfNeeded = settingsScroll[xy] == strIfNeeded;6080var vpSize = _viewportSize[wh];6081var vpOffset = viewportOffset[lt];6082var elSize = elementSize[wh];6083var elOffset = elementOffset[lt];6084var divide = blockIsCenter ? 2 : 1;6085var elementCenterOffset = elOffset + (elSize / 2);6086var viewportCenterOffset = vpOffset + (vpSize / 2);6087var isInView =6088elSize <= vpSize6089&& elOffset >= vpOffset6090&& elOffset + elSize <= vpOffset + vpSize;6091
6092if (scrollNever)6093doNotScroll[xy] = true;6094else if (!doNotScroll[xy]) {6095if (blockIsNearest || scrollIfNeeded) {6096doNotScroll[xy] = scrollIfNeeded ? isInView : false;6097blockIsEnd = elSize < vpSize ? elementCenterOffset > viewportCenterOffset : elementCenterOffset < viewportCenterOffset;6098}6099elementScrollCoordinates[xy] -= blockIsEnd || blockIsCenter ? ((vpSize / divide) - (elSize / divide)) * (isX && _isRTL && normalizeRTL ? -1 : 1) : 0;6100}6101};6102finalizeBlock(true);6103finalizeBlock(false);6104}6105
6106if (doNotScroll.y)6107delete elementScrollCoordinates.y;6108if (doNotScroll.x)6109delete elementScrollCoordinates.x;6110
6111coordinates = elementScrollCoordinates;6112}6113}6114
6115finalScroll[_strScrollLeft] = getFinalScroll(true, getRawScroll(true, coordinates));6116finalScroll[_strScrollTop] = getFinalScroll(false, getRawScroll(false, coordinates));6117doScrollLeft = finalScroll[_strScrollLeft] !== undefined;6118doScrollTop = finalScroll[_strScrollTop] !== undefined;6119
6120if ((doScrollLeft || doScrollTop) && (duration > 0 || durationIsObject)) {6121if (durationIsObject) {6122duration.complete = proxyCompleteCallback;6123_viewportElement.animate(finalScroll, duration);6124}6125else {6126animationOptions = {6127duration: duration,6128complete: proxyCompleteCallback6129};6130if (COMPATIBILITY.isA(easing) || FRAMEWORK.isPlainObject(easing)) {6131specialEasing[_strScrollLeft] = easing[0] || easing.x;6132specialEasing[_strScrollTop] = easing[1] || easing.y;6133animationOptions.specialEasing = specialEasing;6134}6135else {6136animationOptions.easing = easing;6137}6138_viewportElement.animate(finalScroll, animationOptions);6139}6140}6141else {6142if (doScrollLeft)6143_viewportElement[_strScrollLeft](finalScroll[_strScrollLeft]);6144if (doScrollTop)6145_viewportElement[_strScrollTop](finalScroll[_strScrollTop]);6146updateScrollbarInfos();6147}6148};6149
6150/**6151* Stops all scroll animations.
6152* @returns {*} The current OverlayScrollbars instance (for chaining).
6153*/
6154_base.scrollStop = function (param1, param2, param3) {6155_viewportElement.stop(param1, param2, param3);6156return _base;6157};6158
6159/**6160* Returns all relevant elements.
6161* @param elementName The name of the element which shall be returned.
6162* @returns {{target: *, host: *, padding: *, viewport: *, content: *, scrollbarHorizontal: {scrollbar: *, track: *, handle: *}, scrollbarVertical: {scrollbar: *, track: *, handle: *}, scrollbarCorner: *} | *}
6163*/
6164_base.getElements = function (elementName) {6165var obj = {6166target: _targetElementNative,6167host: _hostElementNative,6168padding: _paddingElementNative,6169viewport: _viewportElementNative,6170content: _contentElementNative,6171scrollbarHorizontal: {6172scrollbar: _scrollbarHorizontalElement[0],6173track: _scrollbarHorizontalTrackElement[0],6174handle: _scrollbarHorizontalHandleElement[0]6175},6176scrollbarVertical: {6177scrollbar: _scrollbarVerticalElement[0],6178track: _scrollbarVerticalTrackElement[0],6179handle: _scrollbarVerticalHandleElement[0]6180},6181scrollbarCorner: _scrollbarCornerElement[0]6182};6183return type(elementName) == TYPES.s ? getObjectPropVal(obj, elementName) : obj;6184};6185
6186/**6187* Returns a object which describes the current state of this instance.
6188* @param stateProperty A specific property from the state object which shall be returned.
6189* @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *}
6190*/
6191_base.getState = function (stateProperty) {6192function prepare(obj) {6193if (!FRAMEWORK.isPlainObject(obj))6194return obj;6195var extended = extendDeep({}, obj);6196var changePropertyName = function (from, to) {6197if (extended[LEXICON.hOP](from)) {6198extended[to] = extended[from];6199delete extended[from];6200}6201};6202changePropertyName('w', _strWidth); //change w to width6203changePropertyName('h', _strHeight); //change h to height6204delete extended.c; //delete c (the 'changed' prop)6205return extended;6206};6207var obj = {6208destroyed: !!prepare(_destroyed),6209sleeping: !!prepare(_sleeping),6210autoUpdate: prepare(!_mutationObserversConnected),6211widthAuto: prepare(_widthAutoCache),6212heightAuto: prepare(_heightAutoCache),6213padding: prepare(_cssPaddingCache),6214overflowAmount: prepare(_overflowAmountCache),6215hideOverflow: prepare(_hideOverflowCache),6216hasOverflow: prepare(_hasOverflowCache),6217contentScrollSize: prepare(_contentScrollSizeCache),6218viewportSize: prepare(_viewportSize),6219hostSize: prepare(_hostSizeCache),6220documentMixed: prepare(_documentMixed)6221};6222return type(stateProperty) == TYPES.s ? getObjectPropVal(obj, stateProperty) : obj;6223};6224
6225/**6226* Gets all or specific extension instance.
6227* @param extName The name of the extension from which the instance shall be got.
6228* @returns {{}} The instance of the extension with the given name or undefined if the instance couldn't be found.
6229*/
6230_base.ext = function (extName) {6231var result;6232var privateMethods = _extensionsPrivateMethods.split(' ');6233var i = 0;6234if (type(extName) == TYPES.s) {6235if (_extensions[LEXICON.hOP](extName)) {6236result = extendDeep({}, _extensions[extName]);6237for (; i < privateMethods.length; i++)6238delete result[privateMethods[i]];6239}6240}6241else {6242result = {};6243for (i in _extensions)6244result[i] = extendDeep({}, _base.ext(i));6245}6246return result;6247};6248
6249/**6250* Adds a extension to this instance.
6251* @param extName The name of the extension which shall be added.
6252* @param extensionOptions The extension options which shall be used.
6253* @returns {{}} The instance of the added extension or undefined if the extension couldn't be added properly.
6254*/
6255_base.addExt = function (extName, extensionOptions) {6256var registeredExtensionObj = _plugin.extension(extName);6257var instance;6258var instanceAdded;6259var instanceContract;6260var contractResult;6261var contractFulfilled = true;6262if (registeredExtensionObj) {6263if (!_extensions[LEXICON.hOP](extName)) {6264instance = registeredExtensionObj.extensionFactory.call(_base,6265extendDeep({}, registeredExtensionObj.defaultOptions),6266FRAMEWORK,6267COMPATIBILITY);6268
6269if (instance) {6270instanceContract = instance.contract;6271if (type(instanceContract) == TYPES.f) {6272contractResult = instanceContract(window);6273contractFulfilled = type(contractResult) == TYPES.b ? contractResult : contractFulfilled;6274}6275if (contractFulfilled) {6276_extensions[extName] = instance;6277instanceAdded = instance.added;6278if (type(instanceAdded) == TYPES.f)6279instanceAdded(extensionOptions);6280
6281return _base.ext(extName);6282}6283}6284}6285else6286return _base.ext(extName);6287}6288else6289console.warn("A extension with the name \"" + extName + "\" isn't registered.");6290};6291
6292/**6293* Removes a extension from this instance.
6294* @param extName The name of the extension which shall be removed.
6295* @returns {boolean} True if the extension was removed, false otherwise e.g. if the extension wasn't added before.
6296*/
6297_base.removeExt = function (extName) {6298var instance = _extensions[extName];6299var instanceRemoved;6300if (instance) {6301delete _extensions[extName];6302
6303instanceRemoved = instance.removed;6304if (type(instanceRemoved) == TYPES.f)6305instanceRemoved();6306
6307return true;6308}6309return false;6310};6311
6312/**6313* Constructs the plugin.
6314* @param targetElement The element to which the plugin shall be applied.
6315* @param options The initial options of the plugin.
6316* @param extensions The extension(s) which shall be added right after the initialization.
6317* @returns {boolean} True if the plugin was successfully initialized, false otherwise.
6318*/
6319function construct(targetElement, options, extensions) {6320_defaultOptions = globals.defaultOptions;6321_nativeScrollbarStyling = globals.nativeScrollbarStyling;6322_nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);6323_nativeScrollbarIsOverlaid = extendDeep({}, globals.nativeScrollbarIsOverlaid);6324_overlayScrollbarDummySize = extendDeep({}, globals.overlayScrollbarDummySize);6325_rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior);6326
6327//parse & set options but don't update6328setOptions(extendDeep({}, _defaultOptions, options));6329
6330_cssCalc = globals.cssCalc;6331_msieVersion = globals.msie;6332_autoUpdateRecommended = globals.autoUpdateRecommended;6333_supportTransition = globals.supportTransition;6334_supportTransform = globals.supportTransform;6335_supportPassiveEvents = globals.supportPassiveEvents;6336_supportResizeObserver = globals.supportResizeObserver;6337_supportMutationObserver = globals.supportMutationObserver;6338_restrictedMeasuring = globals.restrictedMeasuring;6339_documentElement = FRAMEWORK(targetElement.ownerDocument);6340_documentElementNative = _documentElement[0];6341_windowElement = FRAMEWORK(_documentElementNative.defaultView || _documentElementNative.parentWindow);6342_windowElementNative = _windowElement[0];6343_htmlElement = findFirst(_documentElement, 'html');6344_bodyElement = findFirst(_htmlElement, 'body');6345_targetElement = FRAMEWORK(targetElement);6346_targetElementNative = _targetElement[0];6347_isTextarea = _targetElement.is('textarea');6348_isBody = _targetElement.is('body');6349_documentMixed = _documentElementNative !== document;6350
6351/* On a div Element The if checks only whether:6352* - the targetElement has the class "os-host"
6353* - the targetElement has a a child with the class "os-padding"
6354*
6355* If that's the case, its assumed the DOM has already the following structure:
6356* (The ".os-host" element is the targetElement)
6357*
6358* <div class="os-host">
6359* <div class="os-resize-observer-host"></div>
6360* <div class="os-padding">
6361* <div class="os-viewport">
6362* <div class="os-content"></div>
6363* </div>
6364* </div>
6365* <div class="os-scrollbar os-scrollbar-horizontal ">
6366* <div class="os-scrollbar-track">
6367* <div class="os-scrollbar-handle"></div>
6368* </div>
6369* </div>
6370* <div class="os-scrollbar os-scrollbar-vertical">
6371* <div class="os-scrollbar-track">
6372* <div class="os-scrollbar-handle"></div>
6373* </div>
6374* </div>
6375* <div class="os-scrollbar-corner"></div>
6376* </div>
6377*
6378* =====================================================================================
6379*
6380* On a Textarea Element The if checks only whether:
6381* - the targetElement has the class "os-textarea"
6382* - the targetElement is inside a element with the class "os-content"
6383*
6384* If that's the case, its assumed the DOM has already the following structure:
6385* (The ".os-textarea" (textarea) element is the targetElement)
6386*
6387* <div class="os-host-textarea">
6388* <div class="os-resize-observer-host"></div>
6389* <div class="os-padding os-text-inherit">
6390* <div class="os-viewport os-text-inherit">
6391* <div class="os-content os-text-inherit">
6392* <div class="os-textarea-cover"></div>
6393* <textarea class="os-textarea os-text-inherit"></textarea>
6394* </div>
6395* </div>
6396* </div>
6397* <div class="os-scrollbar os-scrollbar-horizontal ">
6398* <div class="os-scrollbar-track">
6399* <div class="os-scrollbar-handle"></div>
6400* </div>
6401* </div>
6402* <div class="os-scrollbar os-scrollbar-vertical">
6403* <div class="os-scrollbar-track">
6404* <div class="os-scrollbar-handle"></div>
6405* </div>
6406* </div>
6407* <div class="os-scrollbar-corner"></div>
6408* </div>
6409*/
6410_domExists = _isTextarea6411? _targetElement.hasClass(_classNameTextareaElement) && _targetElement.parent().hasClass(_classNameContentElement)6412: _targetElement.hasClass(_classNameHostElement) && _targetElement.children(_strDot + _classNamePaddingElement)[LEXICON.l];6413
6414var initBodyScroll;6415var bodyMouseTouchDownListener;6416
6417//check if the plugin hasn't to be initialized6418if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) {6419dispatchCallback('onInitializationWithdrawn');6420if (_domExists) {6421setupStructureDOM(true);6422setupScrollbarsDOM(true);6423setupScrollbarCornerDOM(true);6424}6425
6426_destroyed = true;6427_sleeping = true;6428
6429return _base;6430}6431
6432if (_isBody) {6433initBodyScroll = {};6434initBodyScroll.l = MATH.max(_targetElement[_strScrollLeft](), _htmlElement[_strScrollLeft](), _windowElement[_strScrollLeft]());6435initBodyScroll.t = MATH.max(_targetElement[_strScrollTop](), _htmlElement[_strScrollTop](), _windowElement[_strScrollTop]());6436
6437bodyMouseTouchDownListener = function () {6438_viewportElement.removeAttr(LEXICON.ti);6439setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, true, true);6440}6441}6442
6443//build OverlayScrollbars DOM6444setupStructureDOM();6445setupScrollbarsDOM();6446setupScrollbarCornerDOM();6447
6448//create OverlayScrollbars events6449setupStructureEvents();6450setupScrollbarEvents(true);6451setupScrollbarEvents(false);6452setupScrollbarCornerEvents();6453
6454//create mutation observers6455createMutationObservers();6456
6457//build resize observer for the host element6458setupResizeObserver(_sizeObserverElement, hostOnResized);6459
6460if (_isBody) {6461//apply the body scroll to handle it right in the update method6462_viewportElement[_strScrollLeft](initBodyScroll.l)[_strScrollTop](initBodyScroll.t);6463
6464//set the focus on the viewport element so you dont have to click on the page to use keyboard keys (up / down / space) for scrolling6465if (document.activeElement == targetElement && _viewportElementNative.focus) {6466//set a tabindex to make the viewportElement focusable6467_viewportElement.attr(LEXICON.ti, '-1');6468_viewportElementNative.focus();6469
6470/* the tabindex has to be removed due to;6471* If you set the tabindex attribute on an <div>, then its child content cannot be scrolled with the arrow keys unless you set tabindex on the content, too
6472* https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
6473*/
6474setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, false, true);6475}6476}6477
6478//update for the first time & initialize cache6479_base.update(_strAuto);6480
6481//the plugin is initialized now!6482_initialized = true;6483dispatchCallback('onInitialized');6484
6485//call all callbacks which would fire before the initialized was complete6486each(_callbacksInitQeueue, function (index, value) { dispatchCallback(value.n, value.a); });6487_callbacksInitQeueue = [];6488
6489//add extensions6490if (type(extensions) == TYPES.s)6491extensions = [extensions];6492if (COMPATIBILITY.isA(extensions))6493each(extensions, function (index, value) { _base.addExt(value); });6494else if (FRAMEWORK.isPlainObject(extensions))6495each(extensions, function (key, value) { _base.addExt(key, value); });6496
6497//add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions)6498setTimeout(function () {6499if (_supportTransition && !_destroyed)6500addClass(_hostElement, _classNameHostTransition);6501}, 333);6502
6503return _base;6504}6505
6506if (_plugin.valid(construct(pluginTargetElement, options, extensions))) {6507INSTANCES(pluginTargetElement, _base);6508}6509
6510return _base;6511}6512
6513/**6514* Initializes a new OverlayScrollbarsInstance object or changes options if already initialized or returns the current instance.
6515* @param pluginTargetElements The elements to which the Plugin shall be initialized.
6516* @param options The custom options with which the plugin shall be initialized.
6517* @param extensions The extension(s) which shall be added right after initialization.
6518* @returns {*}
6519*/
6520_plugin = window[PLUGINNAME] = function (pluginTargetElements, options, extensions) {6521if (arguments[LEXICON.l] === 0)6522return this;6523
6524var arr = [];6525var optsIsPlainObj = FRAMEWORK.isPlainObject(options);6526var inst;6527var result;6528
6529//pluginTargetElements is null or undefined6530if (!pluginTargetElements)6531return optsIsPlainObj || !options ? result : arr;6532
6533/*6534pluginTargetElements will be converted to:
65351. A jQueryElement Array
65362. A HTMLElement Array
65373. A Array with a single HTML Element
6538so pluginTargetElements is always a array.
6539*/
6540pluginTargetElements = pluginTargetElements[LEXICON.l] != undefined ? pluginTargetElements : [pluginTargetElements[0] || pluginTargetElements];6541initOverlayScrollbarsStatics();6542
6543if (pluginTargetElements[LEXICON.l] > 0) {6544if (optsIsPlainObj) {6545FRAMEWORK.each(pluginTargetElements, function (i, v) {6546inst = v;6547if (inst !== undefined)6548arr.push(OverlayScrollbarsInstance(inst, options, extensions, _pluginsGlobals, _pluginsAutoUpdateLoop));6549});6550}6551else {6552FRAMEWORK.each(pluginTargetElements, function (i, v) {6553inst = INSTANCES(v);6554if ((options === '!' && _plugin.valid(inst)) || (COMPATIBILITY.type(options) == TYPES.f && options(v, inst)))6555arr.push(inst);6556else if (options === undefined)6557arr.push(inst);6558});6559}6560result = arr[LEXICON.l] === 1 ? arr[0] : arr;6561}6562return result;6563};6564
6565/**6566* Returns a object which contains global information about the plugin and each instance of it.
6567* The returned object is just a copy, that means that changes to the returned object won't have any effect to the original object.
6568*/
6569_plugin.globals = function () {6570initOverlayScrollbarsStatics();6571var globals = FRAMEWORK.extend(true, {}, _pluginsGlobals);6572delete globals['msie'];6573return globals;6574};6575
6576/**6577* Gets or Sets the default options for each new plugin initialization.
6578* @param newDefaultOptions The object with which the default options shall be extended.
6579*/
6580_plugin.defaultOptions = function (newDefaultOptions) {6581initOverlayScrollbarsStatics();6582var currDefaultOptions = _pluginsGlobals.defaultOptions;6583if (newDefaultOptions === undefined)6584return FRAMEWORK.extend(true, {}, currDefaultOptions);6585
6586//set the new default options6587_pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, {}, currDefaultOptions, _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true, currDefaultOptions)._default);6588};6589
6590/**6591* Checks whether the passed instance is a non-destroyed OverlayScrollbars instance.
6592* @param osInstance The potential OverlayScrollbars instance which shall be checked.
6593* @returns {boolean} True if the passed value is a non-destroyed OverlayScrollbars instance, false otherwise.
6594*/
6595_plugin.valid = function (osInstance) {6596return osInstance instanceof _plugin && !osInstance.getState().destroyed;6597};6598
6599/**6600* Registers, Unregisters or returns a extension.
6601* Register: Pass the name and the extension. (defaultOptions is optional)
6602* Unregister: Pass the name and anything except a function as extension parameter.
6603* Get extension: Pass the name of the extension which shall be got.
6604* Get all extensions: Pass no arguments.
6605* @param extensionName The name of the extension which shall be registered, unregistered or returned.
6606* @param extension A function which generates the instance of the extension or anything other to remove a already registered extension.
6607* @param defaultOptions The default options which shall be used for the registered extension.
6608*/
6609_plugin.extension = function (extensionName, extension, defaultOptions) {6610var extNameTypeString = COMPATIBILITY.type(extensionName) == TYPES.s;6611var argLen = arguments[LEXICON.l];6612var i = 0;6613if (argLen < 1 || !extNameTypeString) {6614//return a copy of all extension objects6615return FRAMEWORK.extend(true, { length: _pluginsExtensions[LEXICON.l] }, _pluginsExtensions);6616}6617else if (extNameTypeString) {6618if (COMPATIBILITY.type(extension) == TYPES.f) {6619//register extension6620_pluginsExtensions.push({6621name: extensionName,6622extensionFactory: extension,6623defaultOptions: defaultOptions6624});6625}6626else {6627for (; i < _pluginsExtensions[LEXICON.l]; i++) {6628if (_pluginsExtensions[i].name === extensionName) {6629if (argLen > 1)6630_pluginsExtensions.splice(i, 1); //remove extension6631else6632return FRAMEWORK.extend(true, {}, _pluginsExtensions[i]); //return extension with the given name6633}6634}6635}6636}6637};6638
6639return _plugin;6640})();6641
6642if (JQUERY && JQUERY.fn) {6643/**6644* The jQuery initialization interface.
6645* @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.
6646* @param extensions The extension(s) which shall be added right after initialization.
6647* @returns {*} After initialization it returns the jQuery element array, else it returns the instance(s) of the elements which are selected.
6648*/
6649JQUERY.fn.overlayScrollbars = function (options, extensions) {6650var _elements = this;6651if (JQUERY.isPlainObject(options)) {6652JQUERY.each(_elements, function () { PLUGIN(this, options, extensions); });6653return _elements;6654}6655else6656return PLUGIN(_elements, options);6657};6658}6659return PLUGIN;6660}6661));