LaravelTest

Форк
0
/
jquery.overlayScrollbars.js 
5578 строк · 310.6 Кб
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) {
15
    if (typeof define === 'function' && define.amd)
16
        define(['jquery'], function (framework) { return factory(global, global.document, undefined, framework); });
17
    else if (typeof module === 'object' && typeof module.exports === 'object')
18
        module.exports = factory(global, global.document, undefined, require('jquery'));
19
    else
20
        factory(global, global.document, undefined, global.jQuery);
21
}(typeof window !== 'undefined' ? window : this,
22
    function (window, document, undefined, framework) {
23
        'use strict';
24
        var PLUGINNAME = 'OverlayScrollbars';
25
        var TYPES = {
26
            o: 'object',
27
            f: 'function',
28
            a: 'array',
29
            s: 'string',
30
            b: 'boolean',
31
            n: 'number',
32
            u: 'undefined',
33
            z: 'null'
34
            //d : 'date',
35
            //e : 'error',
36
            //r : 'regexp',
37
            //y : 'symbol'
38
        };
39
        var LEXICON = {
40
            c: 'class',
41
            s: 'style',
42
            i: 'id',
43
            l: 'length',
44
            p: 'prototype',
45
            ti: 'tabindex',
46
            oH: 'offsetHeight',
47
            cH: 'clientHeight',
48
            sH: 'scrollHeight',
49
            oW: 'offsetWidth',
50
            cW: 'clientWidth',
51
            sW: 'scrollWidth',
52
            hOP: 'hasOwnProperty',
53
            bCR: 'getBoundingClientRect'
54
        };
55
        var VENDORS = (function () {
56
            //https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix
57
            var jsCache = {};
58
            var cssCache = {};
59
            var cssPrefixes = ['-webkit-', '-moz-', '-o-', '-ms-'];
60
            var jsPrefixes = ['WebKit', 'Moz', 'O', 'MS'];
61
            function firstLetterToUpper(str) {
62
                return str.charAt(0).toUpperCase() + str.slice(1);
63
            }
64

65
            return {
66
                _cssPrefixes: cssPrefixes,
67
                _jsPrefixes: jsPrefixes,
68
                _cssProperty: function (name) {
69
                    var result = cssCache[name];
70

71
                    if (cssCache[LEXICON.hOP](name))
72
                        return result;
73

74
                    var uppercasedName = firstLetterToUpper(name);
75
                    var elmStyle = document.createElement('div')[LEXICON.s];
76
                    var resultPossibilities;
77
                    var i = 0;
78
                    var v;
79
                    var currVendorWithoutDashes;
80

81
                    for (; i < cssPrefixes.length; i++) {
82
                        currVendorWithoutDashes = cssPrefixes[i].replace(/-/g, '');
83
                        resultPossibilities = [
84
                            name, //transition
85
                            cssPrefixes[i] + name, //-webkit-transition
86
                            currVendorWithoutDashes + uppercasedName, //webkitTransition
87
                            firstLetterToUpper(currVendorWithoutDashes) + uppercasedName //WebkitTransition
88
                        ];
89
                        for (v = 0; v < resultPossibilities[LEXICON.l]; v++) {
90
                            if (elmStyle[resultPossibilities[v]] !== undefined) {
91
                                result = resultPossibilities[v];
92
                                break;
93
                            }
94
                        }
95
                    }
96

97
                    cssCache[name] = result;
98
                    return result;
99
                },
100
                _cssPropertyValue: function (property, values, suffix) {
101
                    var name = property + ' ' + values;
102
                    var result = cssCache[name];
103

104
                    if (cssCache[LEXICON.hOP](name))
105
                        return result;
106

107
                    var dummyStyle = document.createElement('div')[LEXICON.s];
108
                    var possbleValues = values.split(' ');
109
                    var preparedSuffix = suffix || '';
110
                    var i = 0;
111
                    var v = -1;
112
                    var prop;
113

114
                    for (; i < possbleValues[LEXICON.l]; i++) {
115
                        for (; v < VENDORS._cssPrefixes[LEXICON.l]; v++) {
116
                            prop = v < 0 ? possbleValues[i] : VENDORS._cssPrefixes[v] + possbleValues[i];
117
                            dummyStyle.cssText = property + ':' + prop + preparedSuffix;
118
                            if (dummyStyle[LEXICON.l]) {
119
                                result = prop;
120
                                break;
121
                            }
122
                        }
123
                    }
124

125
                    cssCache[name] = result;
126
                    return result;
127
                },
128
                _jsAPI: function (name, isInterface, fallback) {
129
                    var i = 0;
130
                    var result = jsCache[name];
131

132
                    if (!jsCache[LEXICON.hOP](name)) {
133
                        result = window[name];
134
                        for (; i < jsPrefixes[LEXICON.l]; i++)
135
                            result = result || window[(isInterface ? jsPrefixes[i] : jsPrefixes[i].toLowerCase()) + firstLetterToUpper(name)];
136
                        jsCache[name] = result;
137
                    }
138
                    return result || fallback;
139
                }
140
            }
141
        })();
142
        var COMPATIBILITY = (function () {
143
            function windowSize(x) {
144
                return x ? window.innerWidth || document.documentElement[LEXICON.cW] || document.body[LEXICON.cW] : window.innerHeight || document.documentElement[LEXICON.cH] || document.body[LEXICON.cH];
145
            }
146
            function bind(func, thisObj) {
147
                if (typeof func != TYPES.f) {
148
                    throw "Can't bind function!";
149
                    // closest thing possible to the ECMAScript 5
150
                    // internal IsCallable function
151
                    //throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
152
                }
153
                var proto = LEXICON.p;
154
                var aArgs = Array[proto].slice.call(arguments, 2);
155
                var fNOP = function () { };
156
                var fBound = function () { return func.apply(this instanceof fNOP ? this : thisObj, aArgs.concat(Array[proto].slice.call(arguments))); };
157

158
                if (func[proto])
159
                    fNOP[proto] = func[proto]; // Function.prototype doesn't have a prototype property
160
                fBound[proto] = new fNOP();
161

162
                return fBound;
163
            }
164

165
            return {
166
                /**
167
                 * Gets the current window width.
168
                 * @returns {Number|number} The current window width in pixel.
169
                 */
170
                wW: bind(windowSize, 0, true),
171

172
                /**
173
                 * Gets the current window height.
174
                 * @returns {Number|number} The current window height in pixel.
175
                 */
176
                wH: 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
                 */
182
                mO: 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
                 */
188
                rO: 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
                 */
194
                rAF: 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
                 */
200
                cAF: 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
                 */
206
                now: function () {
207
                    return 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
                 */
214
                stpP: function (event) {
215
                    if (event.stopPropagation)
216
                        event.stopPropagation();
217
                    else
218
                        event.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
                 */
225
                prvD: function (event) {
226
                    if (event.preventDefault && event.cancelable)
227
                        event.preventDefault();
228
                    else
229
                        event.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
                 */
237
                page: function (event) {
238
                    event = event.originalEvent || event;
239

240
                    var strPage = 'page';
241
                    var strClient = 'client';
242
                    var strX = 'X';
243
                    var strY = 'Y';
244
                    var target = event.target || event.srcElement || document;
245
                    var eventDoc = target.ownerDocument || document;
246
                    var doc = eventDoc.documentElement;
247
                    var body = eventDoc.body;
248

249
                    //if touch event return return pageX/Y of it
250
                    if (event.touches !== undefined) {
251
                        var touch = event.touches[0];
252
                        return {
253
                            x: touch[strPage + strX],
254
                            y: touch[strPage + strY]
255
                        }
256
                    }
257

258
                    // Calculate pageX/Y if not native supported
259
                    if (!event[strPage + strX] && event[strClient + strX] && event[strClient + strX] != null) {
260

261
                        return {
262
                            x: event[strClient + strX] +
263
                                (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
264
                                (doc && doc.clientLeft || body && body.clientLeft || 0),
265
                            y: event[strClient + strY] +
266
                                (doc && doc.scrollTop || body && body.scrollTop || 0) -
267
                                (doc && doc.clientTop || body && body.clientTop || 0)
268
                        }
269
                    }
270
                    return {
271
                        x: event[strPage + strX],
272
                        y: 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
                 */
281
                mBtn: function (event) {
282
                    var button = event.button;
283
                    if (!event.which && button !== undefined)
284
                        return (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));
285
                    else
286
                        return 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
                 */
295
                inA: function (item, arr) {
296
                    for (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 compared
298
                        try {
299
                            if (arr[i] === item)
300
                                return i;
301
                        }
302
                        catch (e) { }
303
                    return -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
                 */
311
                isA: function (arr) {
312
                    var def = Array.isArray;
313
                    return 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
                 */
321
                type: function (obj) {
322
                    if (obj === undefined)
323
                        return obj + '';
324
                    if (obj === null)
325
                        return obj + '';
326
                    return Object[LEXICON.p].toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
327
                },
328

329

330
                bind: bind
331

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

340
                cssProp: function(propName) {
341
                    return VENDORS._cssProperty(propName);
342
                }
343
                */
344
            }
345
        })();
346

347
        var MATH = Math;
348
        var JQUERY = framework;
349
        var EASING = framework.easing;
350
        var FRAMEWORK = framework;
351
        var INSTANCES = (function () {
352
            var _targets = [];
353
            var _instancePropertyString = '__overlayScrollbars__';
354

355
            /**
356
             * Register, unregister or get a certain (or all) instances.
357
             * Register: Pass the target and the instance.
358
             * Unregister: Pass the target and null.
359
             * Get Instance: Pass the target from which the instance shall be got.
360
             * Get Targets: Pass no arguments.
361
             * @param target The target to which the instance shall be registered / from which the instance shall be unregistered / the instance shall be got
362
             * @param instance The instance.
363
             * @returns {*|void} Returns the instance from the given target.
364
             */
365
            return function (target, instance) {
366
                var argLen = arguments[LEXICON.l];
367
                if (argLen < 1) {
368
                    //return all targets
369
                    return _targets;
370
                }
371
                else {
372
                    if (instance) {
373
                        //register instance
374
                        target[_instancePropertyString] = instance;
375
                        _targets.push(target);
376
                    }
377
                    else {
378
                        var index = COMPATIBILITY.inA(target, _targets);
379
                        if (index > -1) {
380
                            if (argLen > 1) {
381
                                //unregister instance
382
                                delete target[_instancePropertyString];
383
                                _targets.splice(index, 1);
384
                            }
385
                            else {
386
                                //get instance from target
387
                                return _targets[index][_instancePropertyString];
388
                            }
389
                        }
390
                    }
391
                }
392
            }
393
        })();
394
        var PLUGIN = (function () {
395
            var _plugin;
396
            var _pluginsGlobals;
397
            var _pluginsAutoUpdateLoop;
398
            var _pluginsExtensions = [];
399
            var _pluginsOptions = (function () {
400
                var type = COMPATIBILITY.type;
401
                var possibleTemplateTypes = [
402
                    TYPES.b, //boolean
403
                    TYPES.n, //number
404
                    TYPES.s, //string
405
                    TYPES.a, //array
406
                    TYPES.o, //object
407
                    TYPES.f, //function
408
                    TYPES.z  //null
409
                ];
410
                var restrictedStringsSplit = ' ';
411
                var restrictedStringsPossibilitiesSplit = ':';
412
                var classNameAllowedValues = [TYPES.z, TYPES.s];
413
                var numberAllowedValues = TYPES.n;
414
                var booleanNullAllowedValues = [TYPES.z, TYPES.b];
415
                var booleanTrueTemplate = [true, TYPES.b];
416
                var booleanFalseTemplate = [false, TYPES.b];
417
                var callbackTemplate = [null, [TYPES.z, TYPES.f]];
418
                var updateOnLoadTemplate = [['img'], [TYPES.s, TYPES.a, TYPES.z]];
419
                var inheritedAttrsTemplate = [['style', 'class'], [TYPES.s, TYPES.a, TYPES.z]];
420
                var resizeAllowedValues = 'n:none b:both h:horizontal v:vertical';
421
                var overflowBehaviorAllowedValues = 'v-h:visible-hidden v-s:visible-scroll s:scroll h:hidden';
422
                var scrollbarsVisibilityAllowedValues = 'v:visible h:hidden a:auto';
423
                var scrollbarsAutoHideAllowedValues = 'n:never s:scroll l:leave m:move';
424
                var optionsDefaultsAndTemplate = {
425
                    className: ['os-theme-dark', classNameAllowedValues],                //null || string
426
                    resize: ['none', resizeAllowedValues],                               //none || both  || horizontal || vertical || n || b || h || v
427
                    sizeAutoCapable: booleanTrueTemplate,                                //true || false
428
                    clipAlways: booleanTrueTemplate,                                     //true || false
429
                    normalizeRTL: booleanTrueTemplate,                                   //true || false
430
                    paddingAbsolute: booleanFalseTemplate,                               //true || false
431
                    autoUpdate: [null, booleanNullAllowedValues],                        //true || false || null
432
                    autoUpdateInterval: [33, numberAllowedValues],                       //number
433
                    updateOnLoad: updateOnLoadTemplate,                                  //string || array || null
434
                    nativeScrollbarsOverlaid: {
435
                        showNativeScrollbars: booleanFalseTemplate,                      //true || false
436
                        initialize: booleanTrueTemplate                                  //true || false
437
                    },
438
                    overflowBehavior: {
439
                        x: ['scroll', overflowBehaviorAllowedValues],                    //visible-hidden  || visible-scroll || hidden || scroll || v-h || v-s || h || s
440
                        y: ['scroll', overflowBehaviorAllowedValues]                     //visible-hidden  || visible-scroll || hidden || scroll || v-h || v-s || h || s
441
                    },
442
                    scrollbars: {
443
                        visibility: ['auto', scrollbarsVisibilityAllowedValues],         //visible || hidden || auto || v || h || a
444
                        autoHide: ['never', scrollbarsAutoHideAllowedValues],            //never || scroll || leave || move || n || s || l || m
445
                        autoHideDelay: [800, numberAllowedValues],                       //number
446
                        dragScrolling: booleanTrueTemplate,                              //true || false
447
                        clickScrolling: booleanFalseTemplate,                            //true || false
448
                        touchSupport: booleanTrueTemplate,                               //true || false
449
                        snapHandle: booleanFalseTemplate                                 //true || false
450
                    },
451
                    textarea: {
452
                        dynWidth: booleanFalseTemplate,                                  //true || false
453
                        dynHeight: booleanFalseTemplate,                                 //true || false
454
                        inheritedAttrs: inheritedAttrsTemplate                           //string || array || null
455
                    },
456
                    callbacks: {
457
                        onInitialized: callbackTemplate,                                 //null || function
458
                        onInitializationWithdrawn: callbackTemplate,                     //null || function
459
                        onDestroyed: callbackTemplate,                                   //null || function
460
                        onScrollStart: callbackTemplate,                                 //null || function
461
                        onScroll: callbackTemplate,                                      //null || function
462
                        onScrollStop: callbackTemplate,                                  //null || function
463
                        onOverflowChanged: callbackTemplate,                             //null || function
464
                        onOverflowAmountChanged: callbackTemplate,                       //null || function
465
                        onDirectionChanged: callbackTemplate,                            //null || function
466
                        onContentSizeChanged: callbackTemplate,                          //null || function
467
                        onHostSizeChanged: callbackTemplate,                             //null || function
468
                        onUpdated: callbackTemplate                                      //null || function
469
                    }
470
                };
471
                var convert = function (template) {
472
                    var recursive = function (obj) {
473
                        var key;
474
                        var val;
475
                        var valType;
476
                        for (key in obj) {
477
                            if (!obj[LEXICON.hOP](key))
478
                                continue;
479
                            val = obj[key];
480
                            valType = type(val);
481
                            if (valType == TYPES.a)
482
                                obj[key] = val[template ? 1 : 0];
483
                            else if (valType == TYPES.o)
484
                                obj[key] = recursive(val);
485
                        }
486
                        return obj;
487
                    };
488
                    return recursive(FRAMEWORK.extend(true, {}, optionsDefaultsAndTemplate));
489
                };
490

491
                return {
492
                    _defaults: convert(),
493

494
                    _template: convert(true),
495

496
                    /**
497
                     * Validates the passed object by the passed template.
498
                     * @param obj The object which shall be validated.
499
                     * @param template The template which defines the allowed values and types.
500
                     * @param writeErrors True if errors shall be logged to the console.
501
                     * @param diffObj If a object is passed then only valid differences to this object will be returned.
502
                     * @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.
503
                     */
504
                    _validate: function (obj, template, writeErrors, diffObj) {
505
                        var validatedOptions = {};
506
                        var validatedOptionsPrepared = {};
507
                        var objectCopy = FRAMEWORK.extend(true, {}, obj);
508
                        var inArray = FRAMEWORK.inArray;
509
                        var isEmptyObj = FRAMEWORK.isEmptyObject;
510
                        var checkObjectProps = function (data, template, diffData, validatedOptions, validatedOptionsPrepared, prevPropName) {
511
                            for (var prop in template) {
512
                                if (template[LEXICON.hOP](prop) && data[LEXICON.hOP](prop)) {
513
                                    var isValid = false;
514
                                    var isDiff = false;
515
                                    var templateValue = template[prop];
516
                                    var templateValueType = type(templateValue);
517
                                    var templateIsComplex = templateValueType == TYPES.o;
518
                                    var templateTypes = !COMPATIBILITY.isA(templateValue) ? [templateValue] : templateValue;
519
                                    var dataDiffValue = diffData[prop];
520
                                    var dataValue = data[prop];
521
                                    var dataValueType = type(dataValue);
522
                                    var propPrefix = prevPropName ? prevPropName + '.' : '';
523
                                    var error = "The option \"" + propPrefix + prop + "\" wasn't set, because";
524
                                    var errorPossibleTypes = [];
525
                                    var errorRestrictedStrings = [];
526
                                    var restrictedStringValuesSplit;
527
                                    var restrictedStringValuesPossibilitiesSplit;
528
                                    var isRestrictedValue;
529
                                    var mainPossibility;
530
                                    var currType;
531
                                    var i;
532
                                    var v;
533
                                    var j;
534

535
                                    dataDiffValue = dataDiffValue === undefined ? {} : dataDiffValue;
536

537
                                    //if the template has a object as value, it means that the options are complex (verschachtelt)
538
                                    if (templateIsComplex && dataValueType == TYPES.o) {
539
                                        validatedOptions[prop] = {};
540
                                        validatedOptionsPrepared[prop] = {};
541
                                        checkObjectProps(dataValue, templateValue, dataDiffValue, validatedOptions[prop], validatedOptionsPrepared[prop], propPrefix + prop);
542
                                        FRAMEWORK.each([data, validatedOptions, validatedOptionsPrepared], function (index, value) {
543
                                            if (isEmptyObj(value[prop])) {
544
                                                delete value[prop];
545
                                            }
546
                                        });
547
                                    }
548
                                    else if (!templateIsComplex) {
549
                                        for (i = 0; i < templateTypes[LEXICON.l]; i++) {
550
                                            currType = templateTypes[i];
551
                                            templateValueType = type(currType);
552
                                            //if currtype is string and starts with restrictedStringPrefix and end with restrictedStringSuffix
553
                                            isRestrictedValue = templateValueType == TYPES.s && inArray(currType, possibleTemplateTypes) === -1;
554
                                            if (isRestrictedValue) {
555
                                                errorPossibleTypes.push(TYPES.s);
556

557
                                                //split it into a array which contains all possible values for example: ["y:yes", "n:no", "m:maybe"]
558
                                                restrictedStringValuesSplit = currType.split(restrictedStringsSplit);
559
                                                errorRestrictedStrings = errorRestrictedStrings.concat(restrictedStringValuesSplit);
560
                                                for (v = 0; v < restrictedStringValuesSplit[LEXICON.l]; v++) {
561
                                                    //split the possible values into their possibiliteis for example: ["y", "yes"] -> the first is always the mainPossibility
562
                                                    restrictedStringValuesPossibilitiesSplit = restrictedStringValuesSplit[v].split(restrictedStringsPossibilitiesSplit);
563
                                                    mainPossibility = restrictedStringValuesPossibilitiesSplit[0];
564
                                                    for (j = 0; j < restrictedStringValuesPossibilitiesSplit[LEXICON.l]; j++) {
565
                                                        //if any possibility matches with the dataValue, its valid
566
                                                        if (dataValue === restrictedStringValuesPossibilitiesSplit[j]) {
567
                                                            isValid = true;
568
                                                            break;
569
                                                        }
570
                                                    }
571
                                                    if (isValid)
572
                                                        break;
573
                                                }
574
                                            }
575
                                            else {
576
                                                errorPossibleTypes.push(currType);
577

578
                                                if (dataValueType === currType) {
579
                                                    isValid = true;
580
                                                    break;
581
                                                }
582
                                            }
583
                                        }
584

585
                                        if (isValid) {
586
                                            isDiff = dataValue !== dataDiffValue;
587

588
                                            if (isDiff)
589
                                                validatedOptions[prop] = dataValue;
590

591
                                            if (isRestrictedValue ? inArray(dataDiffValue, restrictedStringValuesPossibilitiesSplit) < 0 : isDiff)
592
                                                validatedOptionsPrepared[prop] = isRestrictedValue ? mainPossibility : dataValue;
593
                                        }
594
                                        else if (writeErrors) {
595
                                            console.warn(error + " it doesn't accept the type [ " + dataValueType.toUpperCase() + " ] with the value of \"" + dataValue + "\".\r\n" +
596
                                                "Accepted types are: [ " + errorPossibleTypes.join(', ').toUpperCase() + " ]." +
597
                                                (errorRestrictedStrings[length] > 0 ? "\r\nValid strings are: [ " + errorRestrictedStrings.join(', ').split(restrictedStringsPossibilitiesSplit).join(', ') + " ]." : ''));
598
                                        }
599
                                        delete data[prop];
600
                                    }
601
                                }
602
                            }
603
                        };
604
                        checkObjectProps(objectCopy, template, diffObj || {}, validatedOptions, validatedOptionsPrepared);
605

606
                        //add values which aren't specified in the template to the finished validated object to prevent them from being discarded
607
                        /*
608
                        if(keepForeignProps) {
609
                            FRAMEWORK.extend(true, validatedOptions, objectCopy);
610
                            FRAMEWORK.extend(true, validatedOptionsPrepared, objectCopy);
611
                        }
612
                        */
613

614
                        if (!isEmptyObj(objectCopy) && writeErrors)
615
                            console.warn('The following options are discarded due to invalidity:\r\n' + window.JSON.stringify(objectCopy, null, 2));
616

617
                        return {
618
                            _default: validatedOptions,
619
                            _prepared: validatedOptionsPrepared
620
                        };
621
                    }
622
                }
623
            }());
624

625
            /**
626
             * Initializes the object which contains global information about the plugin and each instance of it.
627
             */
628
            function initOverlayScrollbarsStatics() {
629
                if (!_pluginsGlobals)
630
                    _pluginsGlobals = new OverlayScrollbarsGlobals(_pluginsOptions._defaults);
631
                if (!_pluginsAutoUpdateLoop)
632
                    _pluginsAutoUpdateLoop = new OverlayScrollbarsAutoUpdateLoop(_pluginsGlobals);
633
            }
634

635
            /**
636
             * 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.
637
             * @param defaultOptions
638
             * @constructor
639
             */
640
            function OverlayScrollbarsGlobals(defaultOptions) {
641
                var _base = this;
642
                var strOverflow = 'overflow';
643
                var strHidden = 'hidden';
644
                var strScroll = 'scroll';
645
                var bodyElement = FRAMEWORK('body');
646
                var scrollbarDummyElement = FRAMEWORK('<div id="os-dummy-scrollbar-size"><div></div></div>');
647
                var scrollbarDummyElement0 = scrollbarDummyElement[0];
648
                var dummyContainerChild = FRAMEWORK(scrollbarDummyElement.children('div').eq(0));
649

650
                bodyElement.append(scrollbarDummyElement);
651
                scrollbarDummyElement.hide().show(); //fix IE8 bug (incorrect measuring)
652

653
                var nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement0);
654
                var nativeScrollbarIsOverlaid = {
655
                    x: nativeScrollbarSize.x === 0,
656
                    y: nativeScrollbarSize.y === 0
657
                };
658
                var msie = (function () {
659
                    var ua = window.navigator.userAgent;
660
                    var strIndexOf = 'indexOf';
661
                    var strSubString = 'substring';
662
                    var msie = ua[strIndexOf]('MSIE ');
663
                    var trident = ua[strIndexOf]('Trident/');
664
                    var edge = ua[strIndexOf]('Edge/');
665
                    var rv = ua[strIndexOf]('rv:');
666
                    var result;
667
                    var parseIntFunc = parseInt;
668

669
                    // IE 10 or older => return version number
670
                    if (msie > 0)
671
                        result = parseIntFunc(ua[strSubString](msie + 5, ua[strIndexOf]('.', msie)), 10);
672

673
                    // IE 11 => return version number
674
                    else if (trident > 0)
675
                        result = parseIntFunc(ua[strSubString](rv + 3, ua[strIndexOf]('.', rv)), 10);
676

677
                    // Edge (IE 12+) => return version number
678
                    else if (edge > 0)
679
                        result = parseIntFunc(ua[strSubString](edge + 5, ua[strIndexOf]('.', edge)), 10);
680

681
                    // other browser
682
                    return result;
683
                })();
684

685
                FRAMEWORK.extend(_base, {
686
                    defaultOptions: defaultOptions,
687
                    msie: msie,
688
                    autoUpdateLoop: false,
689
                    autoUpdateRecommended: !COMPATIBILITY.mO(),
690
                    nativeScrollbarSize: nativeScrollbarSize,
691
                    nativeScrollbarIsOverlaid: nativeScrollbarIsOverlaid,
692
                    nativeScrollbarStyling: (function () {
693
                        var result = false;
694
                        scrollbarDummyElement.addClass('os-viewport-native-scrollbars-invisible');
695
                        try {
696
                            result = (scrollbarDummyElement.css('scrollbar-width') === 'none' && (msie > 9 || !msie)) || window.getComputedStyle(scrollbarDummyElement0, '::-webkit-scrollbar').getPropertyValue('display') === 'none';
697
                        } catch (ex) { }
698

699
                        //fix opera bug: scrollbar styles will only appear if overflow value is scroll or auto during the activation of the style.
700
                        //and set overflow to scroll
701
                        //scrollbarDummyElement.css(strOverflow, strHidden).hide().css(strOverflow, strScroll).show();
702
                        //return (scrollbarDummyElement0[LEXICON.oH] - scrollbarDummyElement0[LEXICON.cH]) === 0 && (scrollbarDummyElement0[LEXICON.oW] - scrollbarDummyElement0[LEXICON.cW]) === 0;
703

704
                        return result;
705
                    })(),
706
                    overlayScrollbarDummySize: { x: 30, y: 30 },
707
                    cssCalc: VENDORS._cssPropertyValue('width', 'calc', '(1px)') || null,
708
                    restrictedMeasuring: (function () {
709
                        //https://bugzilla.mozilla.org/show_bug.cgi?id=1439305
710
                        //since 1.11.0 always false -> fixed via CSS (hopefully)
711
                        scrollbarDummyElement.css(strOverflow, strHidden);
712
                        var scrollSize = {
713
                            w: scrollbarDummyElement0[LEXICON.sW],
714
                            h: scrollbarDummyElement0[LEXICON.sH]
715
                        };
716
                        scrollbarDummyElement.css(strOverflow, 'visible');
717
                        var scrollSize2 = {
718
                            w: scrollbarDummyElement0[LEXICON.sW],
719
                            h: scrollbarDummyElement0[LEXICON.sH]
720
                        };
721
                        return (scrollSize.w - scrollSize2.w) !== 0 || (scrollSize.h - scrollSize2.h) !== 0;
722
                    })(),
723
                    rtlScrollBehavior: (function () {
724
                        scrollbarDummyElement.css({ 'overflow-y': strHidden, 'overflow-x': strScroll, 'direction': 'rtl' }).scrollLeft(0);
725
                        var dummyContainerOffset = scrollbarDummyElement.offset();
726
                        var dummyContainerChildOffset = dummyContainerChild.offset();
727
                        //https://github.com/KingSora/OverlayScrollbars/issues/187
728
                        scrollbarDummyElement.scrollLeft(-999);
729
                        var dummyContainerChildOffsetAfterScroll = dummyContainerChild.offset();
730
                        return {
731
                            //origin direction = determines if the zero scroll position is on the left or right side
732
                            //'i' means 'invert' (i === true means that the axis must be inverted to be correct)
733
                            //true = on the left side
734
                            //false = on the right side
735
                            i: dummyContainerOffset.left === dummyContainerChildOffset.left,
736
                            //negative = determines if the maximum scroll is positive or negative
737
                            //'n' means 'negate' (n === true means that the axis must be negated to be correct)
738
                            //true = negative
739
                            //false = positive
740
                            n: dummyContainerChildOffset.left !== dummyContainerChildOffsetAfterScroll.left
741
                        };
742
                    })(),
743
                    supportTransform: !!VENDORS._cssProperty('transform'),
744
                    supportTransition: !!VENDORS._cssProperty('transition'),
745
                    supportPassiveEvents: (function () {
746
                        var supportsPassive = false;
747
                        try {
748
                            window.addEventListener('test', null, Object.defineProperty({}, 'passive', {
749
                                get: function () {
750
                                    supportsPassive = true;
751
                                }
752
                            }));
753
                        } catch (e) { }
754
                        return supportsPassive;
755
                    })(),
756
                    supportResizeObserver: !!COMPATIBILITY.rO(),
757
                    supportMutationObserver: !!COMPATIBILITY.mO()
758
                });
759

760
                scrollbarDummyElement.removeAttr(LEXICON.s).remove();
761

762
                //Catch zoom event:
763
                (function () {
764
                    if (nativeScrollbarIsOverlaid.x && nativeScrollbarIsOverlaid.y)
765
                        return;
766

767
                    var abs = MATH.abs;
768
                    var windowWidth = COMPATIBILITY.wW();
769
                    var windowHeight = COMPATIBILITY.wH();
770
                    var windowDpr = getWindowDPR();
771
                    var onResize = function () {
772
                        if (INSTANCES().length > 0) {
773
                            var newW = COMPATIBILITY.wW();
774
                            var newH = COMPATIBILITY.wH();
775
                            var deltaW = newW - windowWidth;
776
                            var deltaH = newH - windowHeight;
777

778
                            if (deltaW === 0 && deltaH === 0)
779
                                return;
780

781
                            var deltaWRatio = MATH.round(newW / (windowWidth / 100.0));
782
                            var deltaHRatio = MATH.round(newH / (windowHeight / 100.0));
783
                            var absDeltaW = abs(deltaW);
784
                            var absDeltaH = abs(deltaH);
785
                            var absDeltaWRatio = abs(deltaWRatio);
786
                            var absDeltaHRatio = abs(deltaHRatio);
787
                            var newDPR = getWindowDPR();
788

789
                            var deltaIsBigger = absDeltaW > 2 && absDeltaH > 2;
790
                            var difference = !differenceIsBiggerThanOne(absDeltaWRatio, absDeltaHRatio);
791
                            var dprChanged = newDPR !== windowDpr && windowDpr > 0;
792
                            var isZoom = deltaIsBigger && difference && dprChanged;
793
                            var oldScrollbarSize = _base.nativeScrollbarSize;
794
                            var newScrollbarSize;
795

796
                            if (isZoom) {
797
                                bodyElement.append(scrollbarDummyElement);
798
                                newScrollbarSize = _base.nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement[0]);
799
                                scrollbarDummyElement.remove();
800
                                if (oldScrollbarSize.x !== newScrollbarSize.x || oldScrollbarSize.y !== newScrollbarSize.y) {
801
                                    FRAMEWORK.each(INSTANCES(), function () {
802
                                        if (INSTANCES(this))
803
                                            INSTANCES(this).update('zoom');
804
                                    });
805
                                }
806
                            }
807

808
                            windowWidth = newW;
809
                            windowHeight = newH;
810
                            windowDpr = newDPR;
811
                        }
812
                    };
813

814
                    function differenceIsBiggerThanOne(valOne, valTwo) {
815
                        var absValOne = abs(valOne);
816
                        var absValTwo = abs(valTwo);
817
                        return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
818
                    }
819

820
                    function getWindowDPR() {
821
                        var dDPI = window.screen.deviceXDPI || 0;
822
                        var sDPI = window.screen.logicalXDPI || 1;
823
                        return window.devicePixelRatio || (dDPI / sDPI);
824
                    }
825

826
                    FRAMEWORK(window).on('resize', onResize);
827
                })();
828

829
                function calcNativeScrollbarSize(measureElement) {
830
                    return {
831
                        x: measureElement[LEXICON.oH] - measureElement[LEXICON.cH],
832
                        y: measureElement[LEXICON.oW] - measureElement[LEXICON.cW]
833
                    };
834
                }
835
            }
836

837
            /**
838
             * 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.
839
             * @constructor
840
             */
841
            function OverlayScrollbarsAutoUpdateLoop(globals) {
842
                var _base = this;
843
                var _inArray = FRAMEWORK.inArray;
844
                var _getNow = COMPATIBILITY.now;
845
                var _strAutoUpdate = 'autoUpdate';
846
                var _strAutoUpdateInterval = _strAutoUpdate + 'Interval';
847
                var _strLength = LEXICON.l;
848
                var _loopingInstances = [];
849
                var _loopingInstancesIntervalCache = [];
850
                var _loopIsActive = false;
851
                var _loopIntervalDefault = 33;
852
                var _loopInterval = _loopIntervalDefault;
853
                var _loopTimeOld = _getNow();
854
                var _loopID;
855

856

857
                /**
858
                 * The auto update loop which will run every 50 milliseconds or less if the update interval of a instance is lower than 50 milliseconds.
859
                 */
860
                var loop = function () {
861
                    if (_loopingInstances[_strLength] > 0 && _loopIsActive) {
862
                        _loopID = COMPATIBILITY.rAF()(function () {
863
                            loop();
864
                        });
865
                        var timeNew = _getNow();
866
                        var timeDelta = timeNew - _loopTimeOld;
867
                        var lowestInterval;
868
                        var instance;
869
                        var instanceOptions;
870
                        var instanceAutoUpdateAllowed;
871
                        var instanceAutoUpdateInterval;
872
                        var now;
873

874
                        if (timeDelta > _loopInterval) {
875
                            _loopTimeOld = timeNew - (timeDelta % _loopInterval);
876
                            lowestInterval = _loopIntervalDefault;
877
                            for (var i = 0; i < _loopingInstances[_strLength]; i++) {
878
                                instance = _loopingInstances[i];
879
                                if (instance !== undefined) {
880
                                    instanceOptions = instance.options();
881
                                    instanceAutoUpdateAllowed = instanceOptions[_strAutoUpdate];
882
                                    instanceAutoUpdateInterval = MATH.max(1, instanceOptions[_strAutoUpdateInterval]);
883
                                    now = _getNow();
884

885
                                    if ((instanceAutoUpdateAllowed === true || instanceAutoUpdateAllowed === null) && (now - _loopingInstancesIntervalCache[i]) > instanceAutoUpdateInterval) {
886
                                        instance.update('auto');
887
                                        _loopingInstancesIntervalCache[i] = new Date(now += instanceAutoUpdateInterval);
888
                                    }
889

890
                                    lowestInterval = MATH.max(1, MATH.min(lowestInterval, instanceAutoUpdateInterval));
891
                                }
892
                            }
893
                            _loopInterval = lowestInterval;
894
                        }
895
                    } else {
896
                        _loopInterval = _loopIntervalDefault;
897
                    }
898
                };
899

900
                /**
901
                 * Add OverlayScrollbars instance to the auto update loop. Only successful if the instance isn't already added.
902
                 * @param instance The instance which shall be updated in a loop automatically.
903
                 */
904
                _base.add = function (instance) {
905
                    if (_inArray(instance, _loopingInstances) === -1) {
906
                        _loopingInstances.push(instance);
907
                        _loopingInstancesIntervalCache.push(_getNow());
908
                        if (_loopingInstances[_strLength] > 0 && !_loopIsActive) {
909
                            _loopIsActive = true;
910
                            globals.autoUpdateLoop = _loopIsActive;
911
                            loop();
912
                        }
913
                    }
914
                };
915

916
                /**
917
                 * Remove OverlayScrollbars instance from the auto update loop. Only successful if the instance was added before.
918
                 * @param instance The instance which shall be updated in a loop automatically.
919
                 */
920
                _base.remove = function (instance) {
921
                    var index = _inArray(instance, _loopingInstances);
922
                    if (index > -1) {
923
                        //remove from loopingInstances list
924
                        _loopingInstancesIntervalCache.splice(index, 1);
925
                        _loopingInstances.splice(index, 1);
926

927
                        //correct update loop behavior
928
                        if (_loopingInstances[_strLength] === 0 && _loopIsActive) {
929
                            _loopIsActive = false;
930
                            globals.autoUpdateLoop = _loopIsActive;
931
                            if (_loopID !== undefined) {
932
                                COMPATIBILITY.cAF()(_loopID);
933
                                _loopID = -1;
934
                            }
935
                        }
936
                    }
937
                };
938
            }
939

940
            /**
941
             * A object which manages the scrollbars visibility of the target element.
942
             * @param pluginTargetElement The element from which the scrollbars shall be hidden.
943
             * @param options The custom options.
944
             * @param extensions The custom extensions.
945
             * @param globals
946
             * @param autoUpdateLoop
947
             * @returns {*}
948
             * @constructor
949
             */
950
            function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) {
951
                //shortcuts
952
                var type = COMPATIBILITY.type;
953
                var inArray = FRAMEWORK.inArray;
954
                var each = FRAMEWORK.each;
955

956
                //make correct instanceof
957
                var _base = new _plugin();
958
                var _frameworkProto = FRAMEWORK[LEXICON.p];
959

960
                //if passed element is no HTML element: skip and return
961
                if (!isHTMLElement(pluginTargetElement))
962
                    return;
963

964
                //if passed element is already initialized: set passed options if there are any and return its instance
965
                if (INSTANCES(pluginTargetElement)) {
966
                    var inst = INSTANCES(pluginTargetElement);
967
                    inst.options(options);
968
                    return inst;
969
                }
970

971
                //globals:
972
                var _nativeScrollbarIsOverlaid;
973
                var _overlayScrollbarDummySize;
974
                var _rtlScrollBehavior;
975
                var _autoUpdateRecommended;
976
                var _msieVersion;
977
                var _nativeScrollbarStyling;
978
                var _cssCalc;
979
                var _nativeScrollbarSize;
980
                var _supportTransition;
981
                var _supportTransform;
982
                var _supportPassiveEvents;
983
                var _supportResizeObserver;
984
                var _supportMutationObserver;
985
                var _restrictedMeasuring;
986

987
                //general readonly:
988
                var _initialized;
989
                var _destroyed;
990
                var _isTextarea;
991
                var _isBody;
992
                var _documentMixed;
993
                var _domExists;
994

995
                //general:
996
                var _isBorderBox;
997
                var _sizeAutoObserverAdded;
998
                var _paddingX;
999
                var _paddingY;
1000
                var _borderX;
1001
                var _borderY;
1002
                var _marginX;
1003
                var _marginY;
1004
                var _isRTL;
1005
                var _sleeping;
1006
                var _contentBorderSize = {};
1007
                var _scrollHorizontalInfo = {};
1008
                var _scrollVerticalInfo = {};
1009
                var _viewportSize = {};
1010
                var _nativeScrollbarMinSize = {};
1011

1012
                //naming:	
1013
                var _strMinusHidden = '-hidden';
1014
                var _strMarginMinus = 'margin-';
1015
                var _strPaddingMinus = 'padding-';
1016
                var _strBorderMinus = 'border-';
1017
                var _strTop = 'top';
1018
                var _strRight = 'right';
1019
                var _strBottom = 'bottom';
1020
                var _strLeft = 'left';
1021
                var _strMinMinus = 'min-';
1022
                var _strMaxMinus = 'max-';
1023
                var _strWidth = 'width';
1024
                var _strHeight = 'height';
1025
                var _strFloat = 'float';
1026
                var _strEmpty = '';
1027
                var _strAuto = 'auto';
1028
                var _strSync = 'sync';
1029
                var _strScroll = 'scroll';
1030
                var _strHundredPercent = '100%';
1031
                var _strX = 'x';
1032
                var _strY = 'y';
1033
                var _strDot = '.';
1034
                var _strSpace = ' ';
1035
                var _strScrollbar = 'scrollbar';
1036
                var _strMinusHorizontal = '-horizontal';
1037
                var _strMinusVertical = '-vertical';
1038
                var _strScrollLeft = _strScroll + 'Left';
1039
                var _strScrollTop = _strScroll + 'Top';
1040
                var _strMouseTouchDownEvent = 'mousedown touchstart';
1041
                var _strMouseTouchUpEvent = 'mouseup touchend touchcancel';
1042
                var _strMouseTouchMoveEvent = 'mousemove touchmove';
1043
                var _strMouseEnter = 'mouseenter';
1044
                var _strMouseLeave = 'mouseleave';
1045
                var _strKeyDownEvent = 'keydown';
1046
                var _strKeyUpEvent = 'keyup';
1047
                var _strSelectStartEvent = 'selectstart';
1048
                var _strTransitionEndEvent = 'transitionend webkitTransitionEnd oTransitionEnd';
1049
                var _strResizeObserverProperty = '__overlayScrollbarsRO__';
1050

1051
                //class names:	
1052
                var _cassNamesPrefix = 'os-';
1053
                var _classNameHTMLElement = _cassNamesPrefix + 'html';
1054
                var _classNameHostElement = _cassNamesPrefix + 'host';
1055
                var _classNameHostElementForeign = _classNameHostElement + '-foreign';
1056
                var _classNameHostTextareaElement = _classNameHostElement + '-textarea';
1057
                var _classNameHostScrollbarHorizontalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusHorizontal + _strMinusHidden;
1058
                var _classNameHostScrollbarVerticalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusVertical + _strMinusHidden;
1059
                var _classNameHostTransition = _classNameHostElement + '-transition';
1060
                var _classNameHostRTL = _classNameHostElement + '-rtl';
1061
                var _classNameHostResizeDisabled = _classNameHostElement + '-resize-disabled';
1062
                var _classNameHostScrolling = _classNameHostElement + '-scrolling';
1063
                var _classNameHostOverflow = _classNameHostElement + '-overflow';
1064
                var _classNameHostOverflow = _classNameHostElement + '-overflow';
1065
                var _classNameHostOverflowX = _classNameHostOverflow + '-x';
1066
                var _classNameHostOverflowY = _classNameHostOverflow + '-y';
1067
                var _classNameTextareaElement = _cassNamesPrefix + 'textarea';
1068
                var _classNameTextareaCoverElement = _classNameTextareaElement + '-cover';
1069
                var _classNamePaddingElement = _cassNamesPrefix + 'padding';
1070
                var _classNameViewportElement = _cassNamesPrefix + 'viewport';
1071
                var _classNameViewportNativeScrollbarsInvisible = _classNameViewportElement + '-native-scrollbars-invisible';
1072
                var _classNameViewportNativeScrollbarsOverlaid = _classNameViewportElement + '-native-scrollbars-overlaid';
1073
                var _classNameContentElement = _cassNamesPrefix + 'content';
1074
                var _classNameContentArrangeElement = _cassNamesPrefix + 'content-arrange';
1075
                var _classNameContentGlueElement = _cassNamesPrefix + 'content-glue';
1076
                var _classNameSizeAutoObserverElement = _cassNamesPrefix + 'size-auto-observer';
1077
                var _classNameResizeObserverElement = _cassNamesPrefix + 'resize-observer';
1078
                var _classNameResizeObserverItemElement = _cassNamesPrefix + 'resize-observer-item';
1079
                var _classNameResizeObserverItemFinalElement = _classNameResizeObserverItemElement + '-final';
1080
                var _classNameTextInherit = _cassNamesPrefix + 'text-inherit';
1081
                var _classNameScrollbar = _cassNamesPrefix + _strScrollbar;
1082
                var _classNameScrollbarTrack = _classNameScrollbar + '-track';
1083
                var _classNameScrollbarTrackOff = _classNameScrollbarTrack + '-off';
1084
                var _classNameScrollbarHandle = _classNameScrollbar + '-handle';
1085
                var _classNameScrollbarHandleOff = _classNameScrollbarHandle + '-off';
1086
                var _classNameScrollbarUnusable = _classNameScrollbar + '-unusable';
1087
                var _classNameScrollbarAutoHidden = _classNameScrollbar + '-' + _strAuto + _strMinusHidden;
1088
                var _classNameScrollbarCorner = _classNameScrollbar + '-corner';
1089
                var _classNameScrollbarCornerResize = _classNameScrollbarCorner + '-resize';
1090
                var _classNameScrollbarCornerResizeB = _classNameScrollbarCornerResize + '-both';
1091
                var _classNameScrollbarCornerResizeH = _classNameScrollbarCornerResize + _strMinusHorizontal;
1092
                var _classNameScrollbarCornerResizeV = _classNameScrollbarCornerResize + _strMinusVertical;
1093
                var _classNameScrollbarHorizontal = _classNameScrollbar + _strMinusHorizontal;
1094
                var _classNameScrollbarVertical = _classNameScrollbar + _strMinusVertical;
1095
                var _classNameDragging = _cassNamesPrefix + 'dragging';
1096
                var _classNameThemeNone = _cassNamesPrefix + 'theme-none';
1097
                var _classNamesDynamicDestroy = [
1098
                    _classNameViewportNativeScrollbarsInvisible,
1099
                    _classNameViewportNativeScrollbarsOverlaid,
1100
                    _classNameScrollbarTrackOff,
1101
                    _classNameScrollbarHandleOff,
1102
                    _classNameScrollbarUnusable,
1103
                    _classNameScrollbarAutoHidden,
1104
                    _classNameScrollbarCornerResize,
1105
                    _classNameScrollbarCornerResizeB,
1106
                    _classNameScrollbarCornerResizeH,
1107
                    _classNameScrollbarCornerResizeV,
1108
                    _classNameDragging].join(_strSpace);
1109

1110
                //callbacks:	
1111
                var _callbacksInitQeueue = [];
1112

1113
                //attrs viewport shall inherit from target	
1114
                var _viewportAttrsFromTarget = [LEXICON.ti];
1115

1116
                //options:	
1117
                var _defaultOptions;
1118
                var _currentOptions;
1119
                var _currentPreparedOptions;
1120

1121
                //extensions:	
1122
                var _extensions = {};
1123
                var _extensionsPrivateMethods = 'added removed on contract';
1124

1125
                //update	
1126
                var _lastUpdateTime;
1127
                var _swallowedUpdateHints = {};
1128
                var _swallowedUpdateTimeout;
1129
                var _swallowUpdateLag = 42;
1130
                var _updateOnLoadEventName = 'load';
1131
                var _updateOnLoadElms = [];
1132

1133
                //DOM elements:	
1134
                var _windowElement;
1135
                var _documentElement;
1136
                var _htmlElement;
1137
                var _bodyElement;
1138
                var _targetElement;                     //the target element of this OverlayScrollbars object	
1139
                var _hostElement;                       //the host element of this OverlayScrollbars object -> may be the same as targetElement	
1140
                var _sizeAutoObserverElement;           //observes size auto changes	
1141
                var _sizeObserverElement;               //observes size and padding changes	
1142
                var _paddingElement;                    //manages the padding	
1143
                var _viewportElement;                   //is the viewport of our scrollbar model	
1144
                var _contentElement;                    //the element which holds the content	
1145
                var _contentArrangeElement;             //is needed for correct sizing of the content element (only if native scrollbars are overlays)	
1146
                var _contentGlueElement;                //has always the size of the content element	
1147
                var _textareaCoverElement;              //only applied if target is a textarea element. Used for correct size calculation and for prevention of uncontrolled scrolling	
1148
                var _scrollbarCornerElement;
1149
                var _scrollbarHorizontalElement;
1150
                var _scrollbarHorizontalTrackElement;
1151
                var _scrollbarHorizontalHandleElement;
1152
                var _scrollbarVerticalElement;
1153
                var _scrollbarVerticalTrackElement;
1154
                var _scrollbarVerticalHandleElement;
1155
                var _windowElementNative;
1156
                var _documentElementNative;
1157
                var _targetElementNative;
1158
                var _hostElementNative;
1159
                var _sizeAutoObserverElementNative;
1160
                var _sizeObserverElementNative;
1161
                var _paddingElementNative;
1162
                var _viewportElementNative;
1163
                var _contentElementNative;
1164

1165
                //Cache:	
1166
                var _hostSizeCache;
1167
                var _contentScrollSizeCache;
1168
                var _arrangeContentSizeCache;
1169
                var _hasOverflowCache;
1170
                var _hideOverflowCache;
1171
                var _widthAutoCache;
1172
                var _heightAutoCache;
1173
                var _cssBoxSizingCache;
1174
                var _cssPaddingCache;
1175
                var _cssBorderCache;
1176
                var _cssMarginCache;
1177
                var _cssDirectionCache;
1178
                var _cssDirectionDetectedCache;
1179
                var _paddingAbsoluteCache;
1180
                var _clipAlwaysCache;
1181
                var _contentGlueSizeCache;
1182
                var _overflowBehaviorCache;
1183
                var _overflowAmountCache;
1184
                var _ignoreOverlayScrollbarHidingCache;
1185
                var _autoUpdateCache;
1186
                var _sizeAutoCapableCache;
1187
                var _contentElementScrollSizeChangeDetectedCache;
1188
                var _hostElementSizeChangeDetectedCache;
1189
                var _scrollbarsVisibilityCache;
1190
                var _scrollbarsAutoHideCache;
1191
                var _scrollbarsClickScrollingCache;
1192
                var _scrollbarsDragScrollingCache;
1193
                var _resizeCache;
1194
                var _normalizeRTLCache;
1195
                var _classNameCache;
1196
                var _oldClassName;
1197
                var _textareaAutoWrappingCache;
1198
                var _textareaInfoCache;
1199
                var _textareaSizeCache;
1200
                var _textareaDynHeightCache;
1201
                var _textareaDynWidthCache;
1202
                var _bodyMinSizeCache;
1203
                var _updateAutoCache = {};
1204

1205
                //MutationObserver:	
1206
                var _mutationObserverHost;
1207
                var _mutationObserverContent;
1208
                var _mutationObserverHostCallback;
1209
                var _mutationObserverContentCallback;
1210
                var _mutationObserversConnected;
1211
                var _mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows'];
1212
                var _mutationObserverAttrsHost = [LEXICON.i, LEXICON.c, LEXICON.s, 'open'].concat(_viewportAttrsFromTarget);
1213

1214
                //events:	
1215
                var _destroyEvents = [];
1216

1217
                //textarea:	
1218
                var _textareaHasFocus;
1219

1220
                //scrollbars:	
1221
                var _scrollbarsAutoHideTimeoutId;
1222
                var _scrollbarsAutoHideMoveTimeoutId;
1223
                var _scrollbarsAutoHideDelay;
1224
                var _scrollbarsAutoHideNever;
1225
                var _scrollbarsAutoHideScroll;
1226
                var _scrollbarsAutoHideMove;
1227
                var _scrollbarsAutoHideLeave;
1228
                var _scrollbarsHandleHovered;
1229
                var _scrollbarsHandlesDefineScrollPos;
1230

1231
                //resize	
1232
                var _resizeNone;
1233
                var _resizeBoth;
1234
                var _resizeHorizontal;
1235
                var _resizeVertical;
1236

1237

1238
                //==== Event Listener ====//	
1239

1240
                /**	
1241
                 * Adds or removes a event listener from the given element. 	
1242
                 * @param element The element to which the event listener shall be applied or removed.	
1243
                 * @param eventNames The name(s) of the events.	
1244
                 * @param listener The method which shall be called.	
1245
                 * @param remove True if the handler shall be removed, false or undefined if the handler shall be added.	
1246
                 * @param passiveOrOptions The options for the event.
1247
                 */
1248
                function setupResponsiveEventListener(element, eventNames, listener, remove, passiveOrOptions) {
1249
                    var collected = COMPATIBILITY.isA(eventNames) && COMPATIBILITY.isA(listener);
1250
                    var method = remove ? 'removeEventListener' : 'addEventListener';
1251
                    var onOff = remove ? 'off' : 'on';
1252
                    var events = collected ? false : eventNames.split(_strSpace)
1253
                    var i = 0;
1254

1255
                    var passiveOrOptionsIsObj = FRAMEWORK.isPlainObject(passiveOrOptions);
1256
                    var passive = (_supportPassiveEvents && (passiveOrOptionsIsObj ? (passiveOrOptions._passive) : passiveOrOptions)) || false;
1257
                    var capture = passiveOrOptionsIsObj && (passiveOrOptions._capture || false);
1258
                    var nativeParam = _supportPassiveEvents ? {
1259
                        passive: passive,
1260
                        capture: capture,
1261
                    } : capture;
1262

1263
                    if (collected) {
1264
                        for (; i < eventNames[LEXICON.l]; i++)
1265
                            setupResponsiveEventListener(element, eventNames[i], listener[i], remove, passiveOrOptions);
1266
                    }
1267
                    else {
1268
                        for (; i < events[LEXICON.l]; i++) {
1269
                            if(_supportPassiveEvents) {
1270
                                element[0][method](events[i], listener, nativeParam);
1271
                            }
1272
                            else {
1273
                                element[onOff](events[i], listener);
1274
                            }     
1275
                        }
1276
                    }
1277
                }
1278

1279

1280
                function addDestroyEventListener(element, eventNames, listener, passive) {
1281
                    setupResponsiveEventListener(element, eventNames, listener, false, passive);
1282
                    _destroyEvents.push(COMPATIBILITY.bind(setupResponsiveEventListener, 0, element, eventNames, listener, true, passive));
1283
                }
1284

1285
                //==== Resize Observer ====//
1286

1287
                /**
1288
                 * Adds or removes a resize observer from the given element.
1289
                 * @param targetElement The element to which the resize observer shall be added or removed.
1290
                 * @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.
1291
                 */
1292
                function setupResizeObserver(targetElement, onElementResizedCallback) {
1293
                    if (targetElement) {
1294
                        var resizeObserver = COMPATIBILITY.rO();
1295
                        var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart';
1296
                        var strChildNodes = 'childNodes';
1297
                        var constScroll = 3333333;
1298
                        var callback = function () {
1299
                            targetElement[_strScrollTop](constScroll)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll : constScroll);
1300
                            onElementResizedCallback();
1301
                        };
1302
                        //add resize observer:
1303
                        if (onElementResizedCallback) {
1304
                            if (_supportResizeObserver) {
1305
                                var element = targetElement.addClass('observed').append(generateDiv(_classNameResizeObserverElement)).contents()[0];
1306
                                var observer = element[_strResizeObserverProperty] = new resizeObserver(callback);
1307
                                observer.observe(element);
1308
                            }
1309
                            else {
1310
                                if (_msieVersion > 9 || !_autoUpdateRecommended) {
1311
                                    targetElement.prepend(
1312
                                        generateDiv(_classNameResizeObserverElement,
1313
                                            generateDiv({ c: _classNameResizeObserverItemElement, dir: 'ltr' },
1314
                                                generateDiv(_classNameResizeObserverItemElement,
1315
                                                    generateDiv(_classNameResizeObserverItemFinalElement)
1316
                                                ) +
1317
                                                generateDiv(_classNameResizeObserverItemElement,
1318
                                                    generateDiv({ c: _classNameResizeObserverItemFinalElement, style: 'width: 200%; height: 200%' })
1319
                                                )
1320
                                            )
1321
                                        )
1322
                                    );
1323

1324
                                    var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0];
1325
                                    var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]);
1326
                                    var expandElement = FRAMEWORK(observerElement[strChildNodes][0]);
1327
                                    var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]);
1328
                                    var widthCache = observerElement[LEXICON.oW];
1329
                                    var heightCache = observerElement[LEXICON.oH];
1330
                                    var isDirty;
1331
                                    var rAFId;
1332
                                    var currWidth;
1333
                                    var currHeight;
1334
                                    var factor = 2;
1335
                                    var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!!
1336
                                    var reset = function () {
1337
                                        /*
1338
                                         var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
1339
                                         var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
1340
                                         var expandChildCSS = {};
1341
                                         expandChildCSS[_strWidth] = sizeResetWidth;
1342
                                         expandChildCSS[_strHeight] = sizeResetHeight;
1343
                                         expandElementChild.css(expandChildCSS);
1344

1345

1346
                                         expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
1347
                                         shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
1348
                                         */
1349
                                        expandElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);
1350
                                        shrinkElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);
1351
                                    };
1352
                                    var onResized = function () {
1353
                                        rAFId = 0;
1354
                                        if (!isDirty)
1355
                                            return;
1356

1357
                                        widthCache = currWidth;
1358
                                        heightCache = currHeight;
1359
                                        callback();
1360
                                    };
1361
                                    var onScroll = function (event) {
1362
                                        currWidth = observerElement[LEXICON.oW];
1363
                                        currHeight = observerElement[LEXICON.oH];
1364
                                        isDirty = currWidth != widthCache || currHeight != heightCache;
1365

1366
                                        if (event && isDirty && !rAFId) {
1367
                                            COMPATIBILITY.cAF()(rAFId);
1368
                                            rAFId = COMPATIBILITY.rAF()(onResized);
1369
                                        }
1370
                                        else if (!event)
1371
                                            onResized();
1372

1373
                                        reset();
1374
                                        if (event) {
1375
                                            COMPATIBILITY.prvD(event);
1376
                                            COMPATIBILITY.stpP(event);
1377
                                        }
1378
                                        return false;
1379
                                    };
1380
                                    var expandChildCSS = {};
1381
                                    var observerElementCSS = {};
1382

1383
                                    setTopRightBottomLeft(observerElementCSS, _strEmpty, [
1384
                                        -((nativeScrollbarSize.y + 1) * factor),
1385
                                        nativeScrollbarSize.x * -factor,
1386
                                        nativeScrollbarSize.y * -factor,
1387
                                        -((nativeScrollbarSize.x + 1) * factor)
1388
                                    ]);
1389

1390
                                    FRAMEWORK(observerElement).css(observerElementCSS);
1391
                                    expandElement.on(_strScroll, onScroll);
1392
                                    shrinkElement.on(_strScroll, onScroll);
1393
                                    targetElement.on(strAnimationStartEvent, function () {
1394
                                        onScroll(false);
1395
                                    });
1396
                                    //lets assume that the divs will never be that large and a constant value is enough
1397
                                    expandChildCSS[_strWidth] = constScroll;
1398
                                    expandChildCSS[_strHeight] = constScroll;
1399
                                    expandElementChild.css(expandChildCSS);
1400

1401
                                    reset();
1402
                                }
1403
                                else {
1404
                                    var attachEvent = _documentElementNative.attachEvent;
1405
                                    var isIE = _msieVersion !== undefined;
1406
                                    if (attachEvent) {
1407
                                        targetElement.prepend(generateDiv(_classNameResizeObserverElement));
1408
                                        findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback);
1409
                                    }
1410
                                    else {
1411
                                        var obj = _documentElementNative.createElement(TYPES.o);
1412
                                        obj.setAttribute(LEXICON.ti, '-1');
1413
                                        obj.setAttribute(LEXICON.c, _classNameResizeObserverElement);
1414
                                        obj.onload = function () {
1415
                                            var wnd = this.contentDocument.defaultView;
1416
                                            wnd.addEventListener('resize', callback);
1417
                                            wnd.document.documentElement.style.display = 'none';
1418
                                        };
1419
                                        obj.type = 'text/html';
1420
                                        if (isIE)
1421
                                            targetElement.prepend(obj);
1422
                                        obj.data = 'about:blank';
1423
                                        if (!isIE)
1424
                                            targetElement.prepend(obj);
1425
                                        targetElement.on(strAnimationStartEvent, callback);
1426
                                    }
1427
                                }
1428
                            }
1429

1430
                            if (targetElement[0] === _sizeObserverElementNative) {
1431
                                var directionChanged = function () {
1432
                                    var dir = _hostElement.css('direction');
1433
                                    var css = {};
1434
                                    var scrollLeftValue = 0;
1435
                                    var result = false;
1436
                                    if (dir !== _cssDirectionDetectedCache) {
1437
                                        if (dir === 'ltr') {
1438
                                            css[_strLeft] = 0;
1439
                                            css[_strRight] = _strAuto;
1440
                                            scrollLeftValue = constScroll;
1441
                                        }
1442
                                        else {
1443
                                            css[_strLeft] = _strAuto;
1444
                                            css[_strRight] = 0;
1445
                                            scrollLeftValue = _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll;
1446
                                        }
1447
                                        //execution order is important for IE!!!
1448
                                        _sizeObserverElement.children().eq(0).css(css);
1449
                                        _sizeObserverElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constScroll);
1450
                                        _cssDirectionDetectedCache = dir;
1451
                                        result = true;
1452
                                    }
1453
                                    return result;
1454
                                };
1455
                                directionChanged();
1456
                                addDestroyEventListener(targetElement, _strScroll, function (event) {
1457
                                    if (directionChanged())
1458
                                        update();
1459
                                    COMPATIBILITY.prvD(event);
1460
                                    COMPATIBILITY.stpP(event);
1461
                                    return false;
1462
                                });
1463
                            }
1464
                        }
1465
                        //remove resize observer:
1466
                        else {
1467
                            if (_supportResizeObserver) {
1468
                                var element = targetElement.contents()[0];
1469
                                var resizeObserverObj = element[_strResizeObserverProperty];
1470
                                if (resizeObserverObj) {
1471
                                    resizeObserverObj.disconnect();
1472
                                    delete element[_strResizeObserverProperty];
1473
                                }
1474
                            }
1475
                            else {
1476
                                remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0));
1477
                            }
1478
                        }
1479
                    }
1480
                }
1481

1482
                /**
1483
                 * Freezes or unfreezes the given resize observer.
1484
                 * @param targetElement The element to which the target resize observer is applied.
1485
                 * @param freeze True if the resize observer shall be frozen, false otherwise.
1486
                 
1487
                function freezeResizeObserver(targetElement, freeze) {
1488
                    if (targetElement !== undefined) {
1489
                        if(freeze) {
1490
                            if (_supportResizeObserver) {
1491
                                var element = targetElement.contents()[0];
1492
                                element[_strResizeObserverProperty].unobserve(element);
1493
                            }
1494
                            else {
1495
                                targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0);
1496
                                var w = targetElement.css(_strWidth);
1497
                                var h = targetElement.css(_strHeight);
1498
                                var css = {};
1499
                                css[_strWidth] = w;
1500
                                css[_strHeight] = h;
1501
                                targetElement.css(css);
1502
                            }
1503
                        }
1504
                        else {
1505
                            if (_supportResizeObserver) {
1506
                                var element = targetElement.contents()[0];
1507
                                element[_strResizeObserverProperty].observe(element);
1508
                            }
1509
                            else {
1510
                                var css = { };
1511
                                css[_strHeight] = _strEmpty;
1512
                                css[_strWidth] = _strEmpty;
1513
                                targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css);
1514
                            }
1515
                        }
1516
                    }
1517
                }
1518
                */
1519

1520

1521
                //==== Mutation Observers ====//
1522

1523
                /**
1524
                 * Creates MutationObservers for the host and content Element if they are supported.
1525
                 */
1526
                function createMutationObservers() {
1527
                    if (_supportMutationObserver) {
1528
                        var mutationObserverContentLag = 11;
1529
                        var mutationObserver = COMPATIBILITY.mO();
1530
                        var contentLastUpdate = COMPATIBILITY.now();
1531
                        var mutationTarget;
1532
                        var mutationAttrName;
1533
                        var mutationIsClass;
1534
                        var oldMutationVal;
1535
                        var newClassVal;
1536
                        var hostClassNameRegex;
1537
                        var contentTimeout;
1538
                        var now;
1539
                        var sizeAuto;
1540
                        var action;
1541

1542
                        _mutationObserverHostCallback = function (mutations) {
1543

1544
                            var doUpdate = false;
1545
                            var doUpdateForce = false;
1546
                            var mutation;
1547
                            var mutatedAttrs = [];
1548

1549
                            if (_initialized && !_sleeping) {
1550
                                each(mutations, function () {
1551
                                    mutation = this;
1552
                                    mutationTarget = mutation.target;
1553
                                    mutationAttrName = mutation.attributeName;
1554
                                    mutationIsClass = mutationAttrName === LEXICON.c;
1555
                                    oldMutationVal = mutation.oldValue;
1556
                                    newClassVal = mutationTarget.className;
1557

1558
                                    if (_domExists && mutationIsClass && !doUpdateForce) {
1559
                                        // if old class value contains _classNameHostElementForeign and new class value doesn't
1560
                                        if (oldMutationVal.indexOf(_classNameHostElementForeign) > -1 && newClassVal.indexOf(_classNameHostElementForeign) < 0) {
1561
                                            hostClassNameRegex = createHostClassNameRegExp(true);
1562
                                            _hostElementNative.className = newClassVal.split(_strSpace).concat(oldMutationVal.split(_strSpace).filter(function (name) {
1563
                                                return name.match(hostClassNameRegex);
1564
                                            })).join(_strSpace);
1565
                                            doUpdate = doUpdateForce = true;
1566
                                        }
1567
                                    }
1568

1569
                                    if (!doUpdate) {
1570
                                        doUpdate = mutationIsClass
1571
                                            ? hostClassNamesChanged(oldMutationVal, newClassVal)
1572
                                            : mutationAttrName === LEXICON.s
1573
                                                ? oldMutationVal !== mutationTarget[LEXICON.s].cssText
1574
                                                : true;
1575
                                    }
1576

1577
                                    mutatedAttrs.push(mutationAttrName);
1578
                                });
1579

1580
                                updateViewportAttrsFromTarget(mutatedAttrs);
1581

1582
                                if (doUpdate)
1583
                                    _base.update(doUpdateForce || _strAuto);
1584
                            }
1585
                            return doUpdate;
1586
                        };
1587
                        _mutationObserverContentCallback = function (mutations) {
1588
                            var doUpdate = false;
1589
                            var mutation;
1590

1591
                            if (_initialized && !_sleeping) {
1592
                                each(mutations, function () {
1593
                                    mutation = this;
1594
                                    doUpdate = isUnknownMutation(mutation);
1595
                                    return !doUpdate;
1596
                                });
1597

1598
                                if (doUpdate) {
1599
                                    now = COMPATIBILITY.now();
1600
                                    sizeAuto = (_heightAutoCache || _widthAutoCache);
1601
                                    action = function () {
1602
                                        if (!_destroyed) {
1603
                                            contentLastUpdate = now;
1604

1605
                                            //if cols, rows or wrap attr was changed
1606
                                            if (_isTextarea)
1607
                                                textareaUpdate();
1608

1609
                                            if (sizeAuto)
1610
                                                update();
1611
                                            else
1612
                                                _base.update(_strAuto);
1613
                                        }
1614
                                    };
1615
                                    clearTimeout(contentTimeout);
1616
                                    if (mutationObserverContentLag <= 0 || now - contentLastUpdate > mutationObserverContentLag || !sizeAuto)
1617
                                        action();
1618
                                    else
1619
                                        contentTimeout = setTimeout(action, mutationObserverContentLag);
1620
                                }
1621
                            }
1622
                            return doUpdate;
1623
                        }
1624

1625
                        _mutationObserverHost = new mutationObserver(_mutationObserverHostCallback);
1626
                        _mutationObserverContent = new mutationObserver(_mutationObserverContentCallback);
1627
                    }
1628
                }
1629

1630
                /**
1631
                 * Connects the MutationObservers if they are supported.
1632
                 */
1633
                function connectMutationObservers() {
1634
                    if (_supportMutationObserver && !_mutationObserversConnected) {
1635
                        _mutationObserverHost.observe(_hostElementNative, {
1636
                            attributes: true,
1637
                            attributeOldValue: true,
1638
                            attributeFilter: _mutationObserverAttrsHost
1639
                        });
1640

1641
                        _mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, {
1642
                            attributes: true,
1643
                            attributeOldValue: true,
1644
                            subtree: !_isTextarea,
1645
                            childList: !_isTextarea,
1646
                            characterData: !_isTextarea,
1647
                            attributeFilter: _isTextarea ? _mutationObserverAttrsTextarea : _mutationObserverAttrsHost
1648
                        });
1649

1650
                        _mutationObserversConnected = true;
1651
                    }
1652
                }
1653

1654
                /**
1655
                 * Disconnects the MutationObservers if they are supported.
1656
                 */
1657
                function disconnectMutationObservers() {
1658
                    if (_supportMutationObserver && _mutationObserversConnected) {
1659
                        _mutationObserverHost.disconnect();
1660
                        _mutationObserverContent.disconnect();
1661

1662
                        _mutationObserversConnected = false;
1663
                    }
1664
                }
1665

1666

1667
                //==== Events of elements ====//
1668

1669
                /**
1670
                 * This method gets called every time the host element gets resized. IMPORTANT: Padding changes are detected too!!
1671
                 * It refreshes the hostResizedEventArgs and the hostSizeResizeCache.
1672
                 * If there are any size changes, the update method gets called.
1673
                 */
1674
                function hostOnResized() {
1675
                    if (!_sleeping) {
1676
                        var changed;
1677
                        var hostSize = {
1678
                            w: _sizeObserverElementNative[LEXICON.sW],
1679
                            h: _sizeObserverElementNative[LEXICON.sH]
1680
                        };
1681

1682
                        changed = checkCache(hostSize, _hostElementSizeChangeDetectedCache);
1683
                        _hostElementSizeChangeDetectedCache = hostSize;
1684
                        if (changed)
1685
                            update({ _hostSizeChanged: true });
1686
                    }
1687
                }
1688

1689
                /**
1690
                 * The mouse enter event of the host element. This event is only needed for the autoHide feature.
1691
                 */
1692
                function hostOnMouseEnter() {
1693
                    if (_scrollbarsAutoHideLeave)
1694
                        refreshScrollbarsAutoHide(true);
1695
                }
1696

1697
                /**
1698
                 * The mouse leave event of the host element. This event is only needed for the autoHide feature.
1699
                 */
1700
                function hostOnMouseLeave() {
1701
                    if (_scrollbarsAutoHideLeave && !_bodyElement.hasClass(_classNameDragging))
1702
                        refreshScrollbarsAutoHide(false);
1703
                }
1704

1705
                /**
1706
                 * The mouse move event of the host element. This event is only needed for the autoHide "move" feature.
1707
                 */
1708
                function hostOnMouseMove() {
1709
                    if (_scrollbarsAutoHideMove) {
1710
                        refreshScrollbarsAutoHide(true);
1711
                        clearTimeout(_scrollbarsAutoHideMoveTimeoutId);
1712
                        _scrollbarsAutoHideMoveTimeoutId = setTimeout(function () {
1713
                            if (_scrollbarsAutoHideMove && !_destroyed)
1714
                                refreshScrollbarsAutoHide(false);
1715
                        }, 100);
1716
                    }
1717
                }
1718

1719
                /**
1720
                 * Prevents text from deselection if attached to the document element on the mousedown event of a DOM element.
1721
                 * @param event The select start event.
1722
                 */
1723
                function documentOnSelectStart(event) {
1724
                    COMPATIBILITY.prvD(event);
1725
                    return false;
1726
                }
1727

1728
                /**	
1729
                 * A callback which will be called after a element has loaded.	
1730
                 */
1731
                function updateOnLoadCallback(event) {
1732
                    var elm = FRAMEWORK(event.target);
1733

1734
                    eachUpdateOnLoad(function (i, updateOnLoadSelector) {
1735
                        if (elm.is(updateOnLoadSelector)) {
1736
                            update({ _contentSizeChanged: true });
1737
                        }
1738
                    });
1739
                }
1740

1741
                /**
1742
                * Adds or removes mouse & touch events of the host element. (for handling auto-hiding of the scrollbars)
1743
                * @param destroy Indicates whether the events shall be added or removed.
1744
                */
1745
                function setupHostMouseTouchEvents(destroy) {
1746
                    if (!destroy)
1747
                        setupHostMouseTouchEvents(true);
1748

1749
                    setupResponsiveEventListener(_hostElement,
1750
                        _strMouseTouchMoveEvent.split(_strSpace)[0],
1751
                        hostOnMouseMove,
1752
                        (!_scrollbarsAutoHideMove || destroy), true);
1753
                    setupResponsiveEventListener(_hostElement,
1754
                        [_strMouseEnter, _strMouseLeave],
1755
                        [hostOnMouseEnter, hostOnMouseLeave],
1756
                        (!_scrollbarsAutoHideLeave || destroy), true);
1757

1758
                    //if the plugin is initialized and the mouse is over the host element, make the scrollbars visible
1759
                    if (!_initialized && !destroy)
1760
                        _hostElement.one('mouseover', hostOnMouseEnter);
1761
                }
1762

1763

1764
                //==== Update Detection ====//
1765

1766
                /**
1767
                 * Measures the min width and min height of the body element and refreshes the related cache.
1768
                 * @returns {boolean} True if the min width or min height has changed, false otherwise.
1769
                 */
1770
                function bodyMinSizeChanged() {
1771
                    var bodyMinSize = {};
1772
                    if (_isBody && _contentArrangeElement) {
1773
                        bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth));
1774
                        bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight));
1775
                        bodyMinSize.c = checkCache(bodyMinSize, _bodyMinSizeCache);
1776
                        bodyMinSize.f = true; //flag for "measured at least once"
1777
                    }
1778
                    _bodyMinSizeCache = bodyMinSize;
1779
                    return !!bodyMinSize.c;
1780
                }
1781

1782
                /**
1783
                 * Returns true if the class names really changed (new class without plugin host prefix)
1784
                 * @param oldClassNames The old ClassName string or array.
1785
                 * @param newClassNames The new ClassName string or array.
1786
                 * @returns {boolean} True if the class names has really changed, false otherwise.
1787
                 */
1788
                function hostClassNamesChanged(oldClassNames, newClassNames) {
1789
                    var currClasses = typeof newClassNames == TYPES.s ? newClassNames.split(_strSpace) : [];
1790
                    var oldClasses = typeof oldClassNames == TYPES.s ? oldClassNames.split(_strSpace) : [];
1791
                    var diff = getArrayDifferences(oldClasses, currClasses);
1792

1793
                    // remove none theme from diff list to prevent update
1794
                    var idx = inArray(_classNameThemeNone, diff);
1795
                    var i;
1796
                    var regex;
1797

1798
                    if (idx > -1)
1799
                        diff.splice(idx, 1);
1800

1801
                    if (diff[LEXICON.l] > 0) {
1802
                        regex = createHostClassNameRegExp(true, true);
1803
                        for (i = 0; i < diff.length; i++) {
1804
                            if (!diff[i].match(regex)) {
1805
                                return true;
1806
                            }
1807
                        }
1808
                    }
1809
                    return false;
1810
                }
1811

1812
                /**
1813
                 * 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.
1814
                 * @param mutation The mutation which shall be checked.
1815
                 * @returns {boolean} True if the mutation is from a unknown element, false otherwise.
1816
                 */
1817
                function isUnknownMutation(mutation) {
1818
                    var attributeName = mutation.attributeName;
1819
                    var mutationTarget = mutation.target;
1820
                    var mutationType = mutation.type;
1821
                    var strClosest = 'closest';
1822

1823
                    if (mutationTarget === _contentElementNative)
1824
                        return attributeName === null;
1825
                    if (mutationType === 'attributes' && (attributeName === LEXICON.c || attributeName === LEXICON.s) && !_isTextarea) {
1826
                        //ignore className changes by the plugin	
1827
                        if (attributeName === LEXICON.c && FRAMEWORK(mutationTarget).hasClass(_classNameHostElement))
1828
                            return hostClassNamesChanged(mutation.oldValue, mutationTarget.className);
1829

1830
                        //only do it of browser support it natively	
1831
                        if (typeof mutationTarget[strClosest] != TYPES.f)
1832
                            return true;
1833
                        if (mutationTarget[strClosest](_strDot + _classNameResizeObserverElement) !== null ||
1834
                            mutationTarget[strClosest](_strDot + _classNameScrollbar) !== null ||
1835
                            mutationTarget[strClosest](_strDot + _classNameScrollbarCorner) !== null)
1836
                            return false;
1837
                    }
1838
                    return true;
1839
                }
1840

1841
                /**
1842
                 * Returns true if the content size was changed since the last time this method was called.
1843
                 * @returns {boolean} True if the content size was changed, false otherwise.
1844
                 */
1845
                function updateAutoContentSizeChanged() {
1846
                    if (_sleeping)
1847
                        return false;
1848

1849
                    var contentMeasureElement = getContentMeasureElement();
1850
                    var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0;
1851
                    var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea;
1852
                    var css = {};
1853
                    var float;
1854
                    var bodyMinSizeC;
1855
                    var changed;
1856
                    var contentElementScrollSize;
1857

1858
                    if (setCSS) {
1859
                        float = _contentElement.css(_strFloat);
1860
                        css[_strFloat] = _isRTL ? _strRight : _strLeft;
1861
                        css[_strWidth] = _strAuto;
1862
                        _contentElement.css(css);
1863
                    }
1864
                    contentElementScrollSize = {
1865
                        w: contentMeasureElement[LEXICON.sW] + textareaValueLength,
1866
                        h: contentMeasureElement[LEXICON.sH] + textareaValueLength
1867
                    };
1868
                    if (setCSS) {
1869
                        css[_strFloat] = float;
1870
                        css[_strWidth] = _strHundredPercent;
1871
                        _contentElement.css(css);
1872
                    }
1873

1874
                    bodyMinSizeC = bodyMinSizeChanged();
1875
                    changed = checkCache(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache);
1876

1877
                    _contentElementScrollSizeChangeDetectedCache = contentElementScrollSize;
1878

1879
                    return changed || bodyMinSizeC;
1880
                }
1881

1882
                /**
1883
                 * Returns true when a attribute which the MutationObserver would observe has changed.  
1884
                 * @returns {boolean} True if one of the attributes which a MutationObserver would observe has changed, false or undefined otherwise.
1885
                 */
1886
                function meaningfulAttrsChanged() {
1887
                    if (_sleeping || _mutationObserversConnected)
1888
                        return;
1889

1890
                    var elem;
1891
                    var curr;
1892
                    var cache;
1893
                    var changedAttrs = [];
1894
                    var checks = [
1895
                        {
1896
                            _elem: _hostElement,
1897
                            _attrs: _mutationObserverAttrsHost.concat(':visible')
1898
                        },
1899
                        {
1900
                            _elem: _isTextarea ? _targetElement : undefined,
1901
                            _attrs: _mutationObserverAttrsTextarea
1902
                        }
1903
                    ];
1904

1905
                    each(checks, function (index, check) {
1906
                        elem = check._elem;
1907
                        if (elem) {
1908
                            each(check._attrs, function (index, attr) {
1909
                                curr = attr.charAt(0) === ':' ? elem.is(attr) : elem.attr(attr);
1910
                                cache = _updateAutoCache[attr];
1911

1912
                                if (checkCache(curr, cache)) {
1913
                                    changedAttrs.push(attr);
1914
                                }
1915

1916
                                _updateAutoCache[attr] = curr;
1917
                            });
1918
                        }
1919
                    });
1920

1921
                    updateViewportAttrsFromTarget(changedAttrs);
1922

1923
                    return changedAttrs[LEXICON.l] > 0;
1924
                }
1925

1926
                /**
1927
                 * Checks is a CSS Property of a child element is affecting the scroll size of the content.
1928
                 * @param propertyName The CSS property name.
1929
                 * @returns {boolean} True if the property is affecting the content scroll size, false otherwise.
1930
                 */
1931
                function isSizeAffectingCSSProperty(propertyName) {
1932
                    if (!_initialized)
1933
                        return true;
1934
                    var flexGrow = 'flex-grow';
1935
                    var flexShrink = 'flex-shrink';
1936
                    var flexBasis = 'flex-basis';
1937
                    var affectingPropsX = [
1938
                        _strWidth,
1939
                        _strMinMinus + _strWidth,
1940
                        _strMaxMinus + _strWidth,
1941
                        _strMarginMinus + _strLeft,
1942
                        _strMarginMinus + _strRight,
1943
                        _strLeft,
1944
                        _strRight,
1945
                        'font-weight',
1946
                        'word-spacing',
1947
                        flexGrow,
1948
                        flexShrink,
1949
                        flexBasis
1950
                    ];
1951
                    var affectingPropsXContentBox = [
1952
                        _strPaddingMinus + _strLeft,
1953
                        _strPaddingMinus + _strRight,
1954
                        _strBorderMinus + _strLeft + _strWidth,
1955
                        _strBorderMinus + _strRight + _strWidth
1956
                    ];
1957
                    var affectingPropsY = [
1958
                        _strHeight,
1959
                        _strMinMinus + _strHeight,
1960
                        _strMaxMinus + _strHeight,
1961
                        _strMarginMinus + _strTop,
1962
                        _strMarginMinus + _strBottom,
1963
                        _strTop,
1964
                        _strBottom,
1965
                        'line-height',
1966
                        flexGrow,
1967
                        flexShrink,
1968
                        flexBasis
1969
                    ];
1970
                    var affectingPropsYContentBox = [
1971
                        _strPaddingMinus + _strTop,
1972
                        _strPaddingMinus + _strBottom,
1973
                        _strBorderMinus + _strTop + _strWidth,
1974
                        _strBorderMinus + _strBottom + _strWidth
1975
                    ];
1976
                    var _strS = 's';
1977
                    var _strVS = 'v-s';
1978
                    var checkX = _overflowBehaviorCache.x === _strS || _overflowBehaviorCache.x === _strVS;
1979
                    var checkY = _overflowBehaviorCache.y === _strS || _overflowBehaviorCache.y === _strVS;
1980
                    var sizeIsAffected = false;
1981
                    var checkPropertyName = function (arr, name) {
1982
                        for (var i = 0; i < arr[LEXICON.l]; i++) {
1983
                            if (arr[i] === name)
1984
                                return true;
1985
                        }
1986
                        return false;
1987
                    };
1988

1989
                    if (checkY) {
1990
                        sizeIsAffected = checkPropertyName(affectingPropsY, propertyName);
1991
                        if (!sizeIsAffected && !_isBorderBox)
1992
                            sizeIsAffected = checkPropertyName(affectingPropsYContentBox, propertyName);
1993
                    }
1994
                    if (checkX && !sizeIsAffected) {
1995
                        sizeIsAffected = checkPropertyName(affectingPropsX, propertyName);
1996
                        if (!sizeIsAffected && !_isBorderBox)
1997
                            sizeIsAffected = checkPropertyName(affectingPropsXContentBox, propertyName);
1998
                    }
1999
                    return sizeIsAffected;
2000
                }
2001

2002

2003
                //==== Update ====//
2004

2005
                /**
2006
                 * Sets the attribute values of the viewport element to the values from the target element.
2007
                 * The value of a attribute is only set if the attribute is whitelisted.
2008
                 * @attrs attrs The array of attributes which shall be set or undefined if all whitelisted shall be set.
2009
                 */
2010
                function updateViewportAttrsFromTarget(attrs) {
2011
                    attrs = attrs || _viewportAttrsFromTarget;
2012
                    each(attrs, function (index, attr) {
2013
                        if (COMPATIBILITY.inA(attr, _viewportAttrsFromTarget) > -1) {
2014
                            var targetAttr = _targetElement.attr(attr);
2015
                            if (type(targetAttr) == TYPES.s) {
2016
                                _viewportElement.attr(attr, targetAttr);
2017
                            }
2018
                            else {
2019
                                _viewportElement.removeAttr(attr);
2020
                            }
2021
                        }
2022
                    });
2023
                }
2024

2025
                /**
2026
                 * Updates the variables and size of the textarea element, and manages the scroll on new line or new character.
2027
                 */
2028
                function textareaUpdate() {
2029
                    if (!_sleeping) {
2030
                        var wrapAttrOff = !_textareaAutoWrappingCache;
2031
                        var minWidth = _viewportSize.w;
2032
                        var minHeight = _viewportSize.h;
2033
                        var css = {};
2034
                        var doMeasure = _widthAutoCache || wrapAttrOff;
2035
                        var origWidth;
2036
                        var width;
2037
                        var origHeight;
2038
                        var height;
2039

2040
                        //reset min size
2041
                        css[_strMinMinus + _strWidth] = _strEmpty;
2042
                        css[_strMinMinus + _strHeight] = _strEmpty;
2043

2044
                        //set width auto
2045
                        css[_strWidth] = _strAuto;
2046
                        _targetElement.css(css);
2047

2048
                        //measure width
2049
                        origWidth = _targetElementNative[LEXICON.oW];
2050
                        width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1;
2051
                        /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/
2052

2053
                        //set measured width
2054
                        css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent;
2055
                        css[_strMinMinus + _strWidth] = _strHundredPercent;
2056

2057
                        //set height auto
2058
                        css[_strHeight] = _strAuto;
2059
                        _targetElement.css(css);
2060

2061
                        //measure height
2062
                        origHeight = _targetElementNative[LEXICON.oH];
2063
                        height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1);
2064

2065
                        //append correct size values
2066
                        css[_strWidth] = width;
2067
                        css[_strHeight] = height;
2068
                        _textareaCoverElement.css(css);
2069

2070
                        //apply min width / min height to prevent textarea collapsing
2071
                        css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/;
2072
                        css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/;
2073
                        _targetElement.css(css);
2074

2075
                        return {
2076
                            _originalWidth: origWidth,
2077
                            _originalHeight: origHeight,
2078
                            _dynamicWidth: width,
2079
                            _dynamicHeight: height
2080
                        };
2081
                    }
2082
                }
2083

2084
                /**
2085
                 * Updates the plugin and DOM to the current options.
2086
                 * This method should only be called if a update is 100% required.
2087
                 * @param updateHints A objects which contains hints for this update:
2088
                 * {
2089
                 *   _hostSizeChanged : boolean,
2090
                 *   _contentSizeChanged : boolean,
2091
                 *   _force : boolean,                             == preventSwallowing
2092
                 *   _changedOptions : { },                        == preventSwallowing && preventSleep
2093
                *  }
2094
                 */
2095
                function update(updateHints) {
2096
                    clearTimeout(_swallowedUpdateTimeout);
2097
                    updateHints = updateHints || {};
2098
                    _swallowedUpdateHints._hostSizeChanged |= updateHints._hostSizeChanged;
2099
                    _swallowedUpdateHints._contentSizeChanged |= updateHints._contentSizeChanged;
2100
                    _swallowedUpdateHints._force |= updateHints._force;
2101

2102
                    var now = COMPATIBILITY.now();
2103
                    var hostSizeChanged = !!_swallowedUpdateHints._hostSizeChanged;
2104
                    var contentSizeChanged = !!_swallowedUpdateHints._contentSizeChanged;
2105
                    var force = !!_swallowedUpdateHints._force;
2106
                    var changedOptions = updateHints._changedOptions;
2107
                    var swallow = _swallowUpdateLag > 0 && _initialized && !_destroyed && !force && !changedOptions && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache);
2108
                    var displayIsHidden;
2109

2110
                    if (swallow)
2111
                        _swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag);
2112

2113
                    //abort update due to:
2114
                    //destroyed
2115
                    //swallowing
2116
                    //sleeping
2117
                    //host is hidden or has false display
2118
                    if (_destroyed || swallow || (_sleeping && !changedOptions) || (_initialized && !force && (displayIsHidden = _hostElement.is(':hidden'))) || _hostElement.css('display') === 'inline')
2119
                        return;
2120

2121
                    _lastUpdateTime = now;
2122
                    _swallowedUpdateHints = {};
2123

2124
                    //if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely.
2125
                    if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
2126
                        //native scrollbars are hidden, so change the values to zero
2127
                        _nativeScrollbarSize.x = 0;
2128
                        _nativeScrollbarSize.y = 0;
2129
                    }
2130
                    else {
2131
                        //refresh native scrollbar size (in case of zoom)
2132
                        _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
2133
                    }
2134

2135
                    // Scrollbar padding is needed for firefox, because firefox hides scrollbar automatically if the size of the div is too small.
2136
                    // The calculation: [scrollbar size +3 *3]
2137
                    // (+3 because of possible decoration e.g. borders, margins etc., but only if native scrollbar is NOT a overlaid scrollbar)
2138
                    // (*3 because (1)increase / (2)decrease -button and (3)resize handle)
2139
                    _nativeScrollbarMinSize = {
2140
                        x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3,
2141
                        y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 3
2142
                    };
2143

2144
                    changedOptions = changedOptions || {};
2145
                    //freezeResizeObserver(_sizeObserverElement, true);
2146
                    //freezeResizeObserver(_sizeAutoObserverElement, true);
2147

2148
                    var checkCacheAutoForce = function () {
2149
                        return checkCache.apply(this, [].slice.call(arguments).concat([force]));
2150
                    };
2151

2152
                    //save current scroll offset
2153
                    var currScroll = {
2154
                        x: _viewportElement[_strScrollLeft](),
2155
                        y: _viewportElement[_strScrollTop]()
2156
                    };
2157

2158
                    var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars;
2159
                    var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea;
2160

2161
                    //scrollbars visibility:
2162
                    var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility;
2163
                    var scrollbarsVisibilityChanged = checkCacheAutoForce(scrollbarsVisibility, _scrollbarsVisibilityCache);
2164

2165
                    //scrollbars autoHide:
2166
                    var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide;
2167
                    var scrollbarsAutoHideChanged = checkCacheAutoForce(scrollbarsAutoHide, _scrollbarsAutoHideCache);
2168

2169
                    //scrollbars click scrolling
2170
                    var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling;
2171
                    var scrollbarsClickScrollingChanged = checkCacheAutoForce(scrollbarsClickScrolling, _scrollbarsClickScrollingCache);
2172

2173
                    //scrollbars drag scrolling
2174
                    var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling;
2175
                    var scrollbarsDragScrollingChanged = checkCacheAutoForce(scrollbarsDragScrolling, _scrollbarsDragScrollingCache);
2176

2177
                    //className
2178
                    var className = _currentPreparedOptions.className;
2179
                    var classNameChanged = checkCacheAutoForce(className, _classNameCache);
2180

2181
                    //resize
2182
                    var resize = _currentPreparedOptions.resize;
2183
                    var resizeChanged = checkCacheAutoForce(resize, _resizeCache) && !_isBody; //body can't be resized since the window itself acts as resize possibility.
2184

2185
                    //paddingAbsolute
2186
                    var paddingAbsolute = _currentPreparedOptions.paddingAbsolute;
2187
                    var paddingAbsoluteChanged = checkCacheAutoForce(paddingAbsolute, _paddingAbsoluteCache);
2188

2189
                    //clipAlways
2190
                    var clipAlways = _currentPreparedOptions.clipAlways;
2191
                    var clipAlwaysChanged = checkCacheAutoForce(clipAlways, _clipAlwaysCache);
2192

2193
                    //sizeAutoCapable
2194
                    var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport.
2195
                    var sizeAutoCapableChanged = checkCacheAutoForce(sizeAutoCapable, _sizeAutoCapableCache);
2196

2197
                    //showNativeScrollbars
2198
                    var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars;
2199
                    var ignoreOverlayScrollbarHidingChanged = checkCacheAutoForce(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache);
2200

2201
                    //autoUpdate
2202
                    var autoUpdate = _currentPreparedOptions.autoUpdate;
2203
                    var autoUpdateChanged = checkCacheAutoForce(autoUpdate, _autoUpdateCache);
2204

2205
                    //overflowBehavior
2206
                    var overflowBehavior = _currentPreparedOptions.overflowBehavior;
2207
                    var overflowBehaviorChanged = checkCacheAutoForce(overflowBehavior, _overflowBehaviorCache, force);
2208

2209
                    //dynWidth:
2210
                    var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth;
2211
                    var textareaDynWidthChanged = checkCacheAutoForce(_textareaDynWidthCache, textareaDynWidth);
2212

2213
                    //dynHeight:
2214
                    var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight;
2215
                    var textareaDynHeightChanged = checkCacheAutoForce(_textareaDynHeightCache, textareaDynHeight);
2216

2217
                    //scrollbars visibility
2218
                    _scrollbarsAutoHideNever = scrollbarsAutoHide === 'n';
2219
                    _scrollbarsAutoHideScroll = scrollbarsAutoHide === 's';
2220
                    _scrollbarsAutoHideMove = scrollbarsAutoHide === 'm';
2221
                    _scrollbarsAutoHideLeave = scrollbarsAutoHide === 'l';
2222

2223
                    //scrollbars autoHideDelay
2224
                    _scrollbarsAutoHideDelay = currentPreparedOptionsScrollbars.autoHideDelay;
2225

2226
                    //old className
2227
                    _oldClassName = _classNameCache;
2228

2229
                    //resize
2230
                    _resizeNone = resize === 'n';
2231
                    _resizeBoth = resize === 'b';
2232
                    _resizeHorizontal = resize === 'h';
2233
                    _resizeVertical = resize === 'v';
2234

2235
                    //normalizeRTL
2236
                    _normalizeRTLCache = _currentPreparedOptions.normalizeRTL;
2237

2238
                    //ignore overlay scrollbar hiding
2239
                    ignoreOverlayScrollbarHiding = ignoreOverlayScrollbarHiding && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y);
2240

2241
                    //refresh options cache
2242
                    _scrollbarsVisibilityCache = scrollbarsVisibility;
2243
                    _scrollbarsAutoHideCache = scrollbarsAutoHide;
2244
                    _scrollbarsClickScrollingCache = scrollbarsClickScrolling;
2245
                    _scrollbarsDragScrollingCache = scrollbarsDragScrolling;
2246
                    _classNameCache = className;
2247
                    _resizeCache = resize;
2248
                    _paddingAbsoluteCache = paddingAbsolute;
2249
                    _clipAlwaysCache = clipAlways;
2250
                    _sizeAutoCapableCache = sizeAutoCapable;
2251
                    _ignoreOverlayScrollbarHidingCache = ignoreOverlayScrollbarHiding;
2252
                    _autoUpdateCache = autoUpdate;
2253
                    _overflowBehaviorCache = extendDeep({}, overflowBehavior);
2254
                    _textareaDynWidthCache = textareaDynWidth;
2255
                    _textareaDynHeightCache = textareaDynHeight;
2256
                    _hasOverflowCache = _hasOverflowCache || { x: false, y: false };
2257

2258
                    //set correct class name to the host element
2259
                    if (classNameChanged) {
2260
                        removeClass(_hostElement, _oldClassName + _strSpace + _classNameThemeNone);
2261
                        addClass(_hostElement, className !== undefined && className !== null && className.length > 0 ? className : _classNameThemeNone);
2262
                    }
2263

2264
                    //set correct auto Update
2265
                    if (autoUpdateChanged) {
2266
                        if (autoUpdate === true || (autoUpdate === null && _autoUpdateRecommended)) {
2267
                            disconnectMutationObservers();
2268
                            autoUpdateLoop.add(_base);
2269
                        }
2270
                        else {
2271
                            autoUpdateLoop.remove(_base);
2272
                            connectMutationObservers();
2273
                        }
2274
                    }
2275

2276
                    //activate or deactivate size auto capability
2277
                    if (sizeAutoCapableChanged) {
2278
                        if (sizeAutoCapable) {
2279
                            if (_contentGlueElement) {
2280
                                _contentGlueElement.show();
2281
                            }
2282
                            else {
2283
                                _contentGlueElement = FRAMEWORK(generateDiv(_classNameContentGlueElement));
2284
                                _paddingElement.before(_contentGlueElement);
2285
                            }
2286
                            if (_sizeAutoObserverAdded) {
2287
                                _sizeAutoObserverElement.show();
2288
                            }
2289
                            else {
2290
                                _sizeAutoObserverElement = FRAMEWORK(generateDiv(_classNameSizeAutoObserverElement));
2291
                                _sizeAutoObserverElementNative = _sizeAutoObserverElement[0];
2292

2293
                                _contentGlueElement.before(_sizeAutoObserverElement);
2294
                                var oldSize = { w: -1, h: -1 };
2295
                                setupResizeObserver(_sizeAutoObserverElement, function () {
2296
                                    var newSize = {
2297
                                        w: _sizeAutoObserverElementNative[LEXICON.oW],
2298
                                        h: _sizeAutoObserverElementNative[LEXICON.oH]
2299
                                    };
2300
                                    if (checkCache(newSize, oldSize)) {
2301
                                        if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) {
2302
                                            update();
2303
                                        }
2304
                                        else if (_initialized && (!_heightAutoCache && newSize.h === 0) || (!_widthAutoCache && newSize.w === 0)) {
2305
                                            update();
2306
                                        }
2307
                                    }
2308
                                    oldSize = newSize;
2309
                                });
2310
                                _sizeAutoObserverAdded = true;
2311
                                //fix heightAuto detector bug if height is fixed but contentHeight is 0.
2312
                                //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.
2313
                                if (_cssCalc !== null)
2314
                                    _sizeAutoObserverElement.css(_strHeight, _cssCalc + '(100% + 1px)');
2315
                            }
2316
                        }
2317
                        else {
2318
                            if (_sizeAutoObserverAdded)
2319
                                _sizeAutoObserverElement.hide();
2320
                            if (_contentGlueElement)
2321
                                _contentGlueElement.hide();
2322
                        }
2323
                    }
2324

2325
                    //if force, update all resizeObservers too
2326
                    if (force) {
2327
                        _sizeObserverElement.find('*').trigger(_strScroll);
2328
                        if (_sizeAutoObserverAdded)
2329
                            _sizeAutoObserverElement.find('*').trigger(_strScroll);
2330
                    }
2331

2332
                    //display hidden:
2333
                    displayIsHidden = displayIsHidden === undefined ? _hostElement.is(':hidden') : displayIsHidden;
2334

2335
                    //textarea AutoWrapping:
2336
                    var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false;
2337
                    var textareaAutoWrappingChanged = checkCacheAutoForce(textareaAutoWrapping, _textareaAutoWrappingCache);
2338

2339
                    //detect direction:
2340
                    var cssDirection = _hostElement.css('direction');
2341
                    var cssDirectionChanged = checkCacheAutoForce(cssDirection, _cssDirectionCache);
2342

2343
                    //detect box-sizing:
2344
                    var boxSizing = _hostElement.css('box-sizing');
2345
                    var boxSizingChanged = checkCacheAutoForce(boxSizing, _cssBoxSizingCache);
2346

2347
                    //detect padding:
2348
                    var padding = getTopRightBottomLeftHost(_strPaddingMinus);
2349

2350
                    //width + height auto detecting var:
2351
                    var sizeAutoObserverElementBCRect;
2352
                    //exception occurs in IE8 sometimes (unknown exception)
2353
                    try {
2354
                        sizeAutoObserverElementBCRect = _sizeAutoObserverAdded ? _sizeAutoObserverElementNative[LEXICON.bCR]() : null;
2355
                    } catch (ex) {
2356
                        return;
2357
                    }
2358

2359
                    _isRTL = cssDirection === 'rtl';
2360
                    _isBorderBox = (boxSizing === 'border-box');
2361
                    var isRTLLeft = _isRTL ? _strLeft : _strRight;
2362
                    var isRTLRight = _isRTL ? _strRight : _strLeft;
2363

2364
                    //detect width auto:
2365
                    var widthAutoResizeDetection = false;
2366
                    var widthAutoObserverDetection = (_sizeAutoObserverAdded && (_hostElement.css(_strFloat) !== 'none' /*|| _isTextarea */)) ? (MATH.round(sizeAutoObserverElementBCRect.right - sizeAutoObserverElementBCRect.left) === 0) && (!paddingAbsolute ? (_hostElementNative[LEXICON.cW] - _paddingX) > 0 : true) : false;
2367
                    if (sizeAutoCapable && !widthAutoObserverDetection) {
2368
                        var tmpCurrHostWidth = _hostElementNative[LEXICON.oW];
2369
                        var tmpCurrContentGlueWidth = _contentGlueElement.css(_strWidth);
2370
                        _contentGlueElement.css(_strWidth, _strAuto);
2371

2372
                        var tmpNewHostWidth = _hostElementNative[LEXICON.oW];
2373
                        _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
2374
                        widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
2375
                        if (!widthAutoResizeDetection) {
2376
                            _contentGlueElement.css(_strWidth, tmpCurrHostWidth + 1);
2377
                            tmpNewHostWidth = _hostElementNative[LEXICON.oW];
2378
                            _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
2379
                            widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
2380
                        }
2381
                    }
2382
                    var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden;
2383
                    var widthAutoChanged = checkCacheAutoForce(widthAuto, _widthAutoCache);
2384
                    var wasWidthAuto = !widthAuto && _widthAutoCache;
2385

2386
                    //detect height auto:
2387
                    var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false;
2388
                    var heightAutoChanged = checkCacheAutoForce(heightAuto, _heightAutoCache);
2389
                    var wasHeightAuto = !heightAuto && _heightAutoCache;
2390

2391
                    //detect border:
2392
                    //we need the border only if border box and auto size
2393
                    var updateBorderX = (widthAuto && _isBorderBox) || !_isBorderBox;
2394
                    var updateBorderY = (heightAuto && _isBorderBox) || !_isBorderBox;
2395
                    var border = getTopRightBottomLeftHost(_strBorderMinus, '-' + _strWidth, !updateBorderX, !updateBorderY)
2396

2397
                    //detect margin:
2398
                    var margin = getTopRightBottomLeftHost(_strMarginMinus);
2399

2400
                    //vars to apply correct css
2401
                    var contentElementCSS = {};
2402
                    var contentGlueElementCSS = {};
2403

2404
                    //funcs
2405
                    var getHostSize = function () {
2406
                        //has to be clientSize because offsetSize respect borders
2407
                        return {
2408
                            w: _hostElementNative[LEXICON.cW],
2409
                            h: _hostElementNative[LEXICON.cH]
2410
                        };
2411
                    };
2412
                    var getViewportSize = function () {
2413
                        //viewport size is padding container because it never has padding, margin and a border
2414
                        //determine zoom rounding error -> sometimes scrollWidth/Height is smaller than clientWidth/Height
2415
                        //if this happens add the difference to the viewportSize to compensate the rounding error
2416
                        return {
2417
                            w: _paddingElementNative[LEXICON.oW] + MATH.max(0, _contentElementNative[LEXICON.cW] - _contentElementNative[LEXICON.sW]),
2418
                            h: _paddingElementNative[LEXICON.oH] + MATH.max(0, _contentElementNative[LEXICON.cH] - _contentElementNative[LEXICON.sH])
2419
                        };
2420
                    };
2421

2422
                    //set info for padding
2423
                    var paddingAbsoluteX = _paddingX = padding.l + padding.r;
2424
                    var paddingAbsoluteY = _paddingY = padding.t + padding.b;
2425
                    paddingAbsoluteX *= paddingAbsolute ? 1 : 0;
2426
                    paddingAbsoluteY *= paddingAbsolute ? 1 : 0;
2427
                    padding.c = checkCacheAutoForce(padding, _cssPaddingCache);
2428

2429
                    //set info for border
2430
                    _borderX = border.l + border.r;
2431
                    _borderY = border.t + border.b;
2432
                    border.c = checkCacheAutoForce(border, _cssBorderCache);
2433

2434
                    //set info for margin
2435
                    _marginX = margin.l + margin.r;
2436
                    _marginY = margin.t + margin.b;
2437
                    margin.c = checkCacheAutoForce(margin, _cssMarginCache);
2438

2439
                    //refresh cache
2440
                    _textareaAutoWrappingCache = textareaAutoWrapping;
2441
                    _cssDirectionCache = cssDirection;
2442
                    _cssBoxSizingCache = boxSizing;
2443
                    _widthAutoCache = widthAuto;
2444
                    _heightAutoCache = heightAuto;
2445
                    _cssPaddingCache = padding;
2446
                    _cssBorderCache = border;
2447
                    _cssMarginCache = margin;
2448

2449
                    //IEFix direction changed
2450
                    if (cssDirectionChanged && _sizeAutoObserverAdded)
2451
                        _sizeAutoObserverElement.css(_strFloat, isRTLRight);
2452

2453
                    //apply padding:
2454
                    if (padding.c || cssDirectionChanged || paddingAbsoluteChanged || widthAutoChanged || heightAutoChanged || boxSizingChanged || sizeAutoCapableChanged) {
2455
                        var paddingElementCSS = {};
2456
                        var textareaCSS = {};
2457
                        var paddingValues = [padding.t, padding.r, padding.b, padding.l];
2458

2459
                        setTopRightBottomLeft(contentGlueElementCSS, _strMarginMinus, [-padding.t, -padding.r, -padding.b, -padding.l]);
2460
                        if (paddingAbsolute) {
2461
                            setTopRightBottomLeft(paddingElementCSS, _strEmpty, paddingValues);
2462
                            setTopRightBottomLeft(_isTextarea ? textareaCSS : contentElementCSS, _strPaddingMinus);
2463
                        }
2464
                        else {
2465
                            setTopRightBottomLeft(paddingElementCSS, _strEmpty);
2466
                            setTopRightBottomLeft(_isTextarea ? textareaCSS : contentElementCSS, _strPaddingMinus, paddingValues);
2467
                        }
2468

2469
                        _paddingElement.css(paddingElementCSS);
2470
                        _targetElement.css(textareaCSS);
2471
                    }
2472

2473
                    //viewport size is padding container because it never has padding, margin and a border.
2474
                    _viewportSize = getViewportSize();
2475

2476
                    //update Textarea
2477
                    var textareaSize = _isTextarea ? textareaUpdate() : false;
2478
                    var textareaSizeChanged = _isTextarea && checkCacheAutoForce(textareaSize, _textareaSizeCache);
2479
                    var textareaDynOrigSize = _isTextarea && textareaSize ? {
2480
                        w: textareaDynWidth ? textareaSize._dynamicWidth : textareaSize._originalWidth,
2481
                        h: textareaDynHeight ? textareaSize._dynamicHeight : textareaSize._originalHeight
2482
                    } : {};
2483
                    _textareaSizeCache = textareaSize;
2484

2485
                    //fix height auto / width auto in cooperation with current padding & boxSizing behavior:
2486
                    if (heightAuto && (heightAutoChanged || paddingAbsoluteChanged || boxSizingChanged || padding.c || border.c)) {
2487
                        contentElementCSS[_strHeight] = _strAuto;
2488
                    }
2489
                    else if (heightAutoChanged || paddingAbsoluteChanged) {
2490
                        contentElementCSS[_strHeight] = _strHundredPercent;
2491
                    }
2492
                    if (widthAuto && (widthAutoChanged || paddingAbsoluteChanged || boxSizingChanged || padding.c || border.c || cssDirectionChanged)) {
2493
                        contentElementCSS[_strWidth] = _strAuto;
2494
                        contentGlueElementCSS[_strMaxMinus + _strWidth] = _strHundredPercent; //IE Fix
2495
                    }
2496
                    else if (widthAutoChanged || paddingAbsoluteChanged) {
2497
                        contentElementCSS[_strWidth] = _strHundredPercent;
2498
                        contentElementCSS[_strFloat] = _strEmpty;
2499
                        contentGlueElementCSS[_strMaxMinus + _strWidth] = _strEmpty; //IE Fix
2500
                    }
2501
                    if (widthAuto) {
2502
                        //textareaDynOrigSize.w || _strAuto :: doesnt works because applied margin will shift width
2503
                        contentGlueElementCSS[_strWidth] = _strAuto;
2504

2505
                        contentElementCSS[_strWidth] = VENDORS._cssPropertyValue(_strWidth, 'max-content intrinsic') || _strAuto;
2506
                        contentElementCSS[_strFloat] = isRTLRight;
2507
                    }
2508
                    else {
2509
                        contentGlueElementCSS[_strWidth] = _strEmpty;
2510
                    }
2511
                    if (heightAuto) {
2512
                        //textareaDynOrigSize.h || _contentElementNative[LEXICON.cH] :: use for anti scroll jumping
2513
                        contentGlueElementCSS[_strHeight] = textareaDynOrigSize.h || _contentElementNative[LEXICON.cH];
2514
                    }
2515
                    else {
2516
                        contentGlueElementCSS[_strHeight] = _strEmpty;
2517
                    }
2518
                    if (sizeAutoCapable)
2519
                        _contentGlueElement.css(contentGlueElementCSS);
2520
                    _contentElement.css(contentElementCSS);
2521

2522
                    //CHECKPOINT HERE ~
2523
                    contentElementCSS = {};
2524
                    contentGlueElementCSS = {};
2525

2526
                    //if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true
2527
                    if (hostSizeChanged || contentSizeChanged || textareaSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged) {
2528
                        var strOverflow = 'overflow';
2529
                        var strOverflowX = strOverflow + '-x';
2530
                        var strOverflowY = strOverflow + '-y';
2531
                        var strHidden = 'hidden';
2532
                        var strVisible = 'visible';
2533

2534
                        //Reset the viewport (very important for natively overlaid scrollbars and zoom change
2535
                        //don't change the overflow prop as it is very expensive and affects performance !A LOT!
2536
                        if (!_nativeScrollbarStyling) {
2537
                            var viewportElementResetCSS = {};
2538
                            var resetXTmp = _hasOverflowCache.y && _hideOverflowCache.ys && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.y ? _viewportElement.css(isRTLLeft) : -_nativeScrollbarSize.y) : 0;
2539
                            var resetBottomTmp = _hasOverflowCache.x && _hideOverflowCache.xs && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.x ? _viewportElement.css(_strBottom) : -_nativeScrollbarSize.x) : 0;
2540
                            setTopRightBottomLeft(viewportElementResetCSS, _strEmpty);
2541
                            _viewportElement.css(viewportElementResetCSS);
2542
                        }
2543

2544
                        //measure several sizes:
2545
                        var contentMeasureElement = getContentMeasureElement();
2546
                        //in Firefox content element has to have overflow hidden, else element margins aren't calculated properly, this element prevents this bug, but only if scrollbars aren't overlaid
2547
                        var contentSize = {
2548
                            //use clientSize because natively overlaidScrollbars add borders
2549
                            w: textareaDynOrigSize.w || contentMeasureElement[LEXICON.cW],
2550
                            h: textareaDynOrigSize.h || contentMeasureElement[LEXICON.cH]
2551
                        };
2552
                        var scrollSize = {
2553
                            w: contentMeasureElement[LEXICON.sW],
2554
                            h: contentMeasureElement[LEXICON.sH]
2555
                        };
2556

2557
                        //apply the correct viewport style and measure viewport size
2558
                        if (!_nativeScrollbarStyling) {
2559
                            viewportElementResetCSS[_strBottom] = wasHeightAuto ? _strEmpty : resetBottomTmp;
2560
                            viewportElementResetCSS[isRTLLeft] = wasWidthAuto ? _strEmpty : resetXTmp;
2561
                            _viewportElement.css(viewportElementResetCSS);
2562
                        }
2563
                        _viewportSize = getViewportSize();
2564

2565
                        //measure and correct several sizes
2566
                        var hostSize = getHostSize();
2567
                        var hostAbsoluteRectSize = {
2568
                            w: hostSize.w - _marginX - _borderX - (_isBorderBox ? 0 : _paddingX),
2569
                            h: hostSize.h - _marginY - _borderY - (_isBorderBox ? 0 : _paddingY)
2570
                        };
2571
                        var contentGlueSize = {
2572
                            //client/scrollSize + AbsolutePadding -> because padding is only applied to the paddingElement if its absolute, so you have to add it manually
2573
                            //hostSize is clientSize -> so padding should be added manually, right? FALSE! Because content glue is inside hostElement, so we don't have to worry about padding
2574
                            w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostAbsoluteRectSize.w),
2575
                            h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostAbsoluteRectSize.h)
2576
                        };
2577
                        contentGlueSize.c = checkCacheAutoForce(contentGlueSize, _contentGlueSizeCache);
2578
                        _contentGlueSizeCache = contentGlueSize;
2579

2580
                        //apply correct contentGlue size
2581
                        if (sizeAutoCapable) {
2582
                            //size contentGlue correctly to make sure the element has correct size if the sizing switches to auto
2583
                            if (contentGlueSize.c || (heightAuto || widthAuto)) {
2584
                                contentGlueElementCSS[_strWidth] = contentGlueSize.w;
2585
                                contentGlueElementCSS[_strHeight] = contentGlueSize.h;
2586

2587
                                //textarea-sizes are already calculated correctly at this point
2588
                                if (!_isTextarea) {
2589
                                    contentSize = {
2590
                                        //use clientSize because natively overlaidScrollbars add borders
2591
                                        w: contentMeasureElement[LEXICON.cW],
2592
                                        h: contentMeasureElement[LEXICON.cH]
2593
                                    };
2594
                                }
2595
                            }
2596
                            var textareaCoverCSS = {};
2597
                            var setContentGlueElementCSSfunction = function (horizontal) {
2598
                                var scrollbarVars = getScrollbarVars(horizontal);
2599
                                var wh = scrollbarVars._w_h;
2600
                                var strWH = scrollbarVars._width_height;
2601
                                var autoSize = horizontal ? widthAuto : heightAuto;
2602
                                var borderSize = horizontal ? _borderX : _borderY;
2603
                                var paddingSize = horizontal ? _paddingX : _paddingY;
2604
                                var marginSize = horizontal ? _marginX : _marginY;
2605
                                var viewportSize = _viewportSize[wh] - borderSize - marginSize - (_isBorderBox ? 0 : paddingSize);
2606

2607
                                //make contentGlue size -1 if element is not auto sized, to make sure that a resize event happens when the element shrinks
2608
                                if (!autoSize || (!autoSize && border.c))
2609
                                    contentGlueElementCSS[strWH] = hostAbsoluteRectSize[wh] - 1;
2610

2611
                                //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)
2612
                                if (autoSize && (contentSize[wh] < viewportSize) && (horizontal && _isTextarea ? !textareaAutoWrapping : true)) {
2613
                                    if (_isTextarea)
2614
                                        textareaCoverCSS[strWH] = parseToZeroOrNumber(_textareaCoverElement.css(strWH)) - 1;
2615
                                    contentGlueElementCSS[strWH] -= 1;
2616
                                }
2617

2618
                                //make sure content glue size is at least 1
2619
                                if (contentSize[wh] > 0)
2620
                                    contentGlueElementCSS[strWH] = MATH.max(1, contentGlueElementCSS[strWH]);
2621
                            };
2622
                            setContentGlueElementCSSfunction(true);
2623
                            setContentGlueElementCSSfunction(false);
2624

2625
                            if (_isTextarea)
2626
                                _textareaCoverElement.css(textareaCoverCSS);
2627
                            _contentGlueElement.css(contentGlueElementCSS);
2628
                        }
2629
                        if (widthAuto)
2630
                            contentElementCSS[_strWidth] = _strHundredPercent;
2631
                        if (widthAuto && !_isBorderBox && !_mutationObserversConnected)
2632
                            contentElementCSS[_strFloat] = 'none';
2633

2634
                        //apply and reset content style
2635
                        _contentElement.css(contentElementCSS);
2636
                        contentElementCSS = {};
2637

2638
                        //measure again, but this time all correct sizes:
2639
                        var contentScrollSize = {
2640
                            w: contentMeasureElement[LEXICON.sW],
2641
                            h: contentMeasureElement[LEXICON.sH],
2642
                        };
2643
                        contentScrollSize.c = contentSizeChanged = checkCacheAutoForce(contentScrollSize, _contentScrollSizeCache);
2644
                        _contentScrollSizeCache = contentScrollSize;
2645

2646
                        //refresh viewport size after correct measuring
2647
                        _viewportSize = getViewportSize();
2648

2649
                        hostSize = getHostSize();
2650
                        hostSizeChanged = checkCacheAutoForce(hostSize, _hostSizeCache);
2651
                        _hostSizeCache = hostSize;
2652

2653
                        var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0);
2654
                        var previousOverflowAmount = _overflowAmountCache;
2655
                        var overflowBehaviorIsVS = {};
2656
                        var overflowBehaviorIsVH = {};
2657
                        var overflowBehaviorIsS = {};
2658
                        var overflowAmount = {};
2659
                        var hasOverflow = {};
2660
                        var hideOverflow = {};
2661
                        var canScroll = {};
2662
                        var viewportRect = _paddingElementNative[LEXICON.bCR]();
2663
                        var setOverflowVariables = function (horizontal) {
2664
                            var scrollbarVars = getScrollbarVars(horizontal);
2665
                            var scrollbarVarsInverted = getScrollbarVars(!horizontal);
2666
                            var xyI = scrollbarVarsInverted._x_y;
2667
                            var xy = scrollbarVars._x_y;
2668
                            var wh = scrollbarVars._w_h;
2669
                            var widthHeight = scrollbarVars._width_height;
2670
                            var scrollMax = _strScroll + scrollbarVars._Left_Top + 'Max';
2671
                            var fractionalOverflowAmount = viewportRect[widthHeight] ? MATH.abs(viewportRect[widthHeight] - _viewportSize[wh]) : 0;
2672
                            var checkFractionalOverflowAmount = previousOverflowAmount && previousOverflowAmount[xy] > 0 && _viewportElementNative[scrollMax] === 0;
2673
                            overflowBehaviorIsVS[xy] = overflowBehavior[xy] === 'v-s';
2674
                            overflowBehaviorIsVH[xy] = overflowBehavior[xy] === 'v-h';
2675
                            overflowBehaviorIsS[xy] = overflowBehavior[xy] === 's';
2676
                            overflowAmount[xy] = MATH.max(0, MATH.round((contentScrollSize[wh] - _viewportSize[wh]) * 100) / 100);
2677
                            overflowAmount[xy] *= (hideOverflowForceTextarea || (checkFractionalOverflowAmount && fractionalOverflowAmount > 0 && fractionalOverflowAmount < 1)) ? 0 : 1;
2678
                            hasOverflow[xy] = overflowAmount[xy] > 0;
2679

2680
                            //hideOverflow:
2681
                            //x || y : true === overflow is hidden by "overflow: scroll" OR "overflow: hidden"
2682
                            //xs || ys : true === overflow is hidden by "overflow: scroll"
2683
                            hideOverflow[xy] = overflowBehaviorIsVS[xy] || overflowBehaviorIsVH[xy] ? (hasOverflow[xyI] && !overflowBehaviorIsVS[xyI] && !overflowBehaviorIsVH[xyI]) : hasOverflow[xy];
2684
                            hideOverflow[xy + 's'] = hideOverflow[xy] ? (overflowBehaviorIsS[xy] || overflowBehaviorIsVS[xy]) : false;
2685

2686
                            canScroll[xy] = hasOverflow[xy] && hideOverflow[xy + 's'];
2687
                        };
2688
                        setOverflowVariables(true);
2689
                        setOverflowVariables(false);
2690

2691
                        overflowAmount.c = checkCacheAutoForce(overflowAmount, _overflowAmountCache);
2692
                        _overflowAmountCache = overflowAmount;
2693
                        hasOverflow.c = checkCacheAutoForce(hasOverflow, _hasOverflowCache);
2694
                        _hasOverflowCache = hasOverflow;
2695
                        hideOverflow.c = checkCacheAutoForce(hideOverflow, _hideOverflowCache);
2696
                        _hideOverflowCache = hideOverflow;
2697

2698
                        //if native scrollbar is overlay at x OR y axis, prepare DOM
2699
                        if (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) {
2700
                            var borderDesign = 'px solid transparent';
2701
                            var contentArrangeElementCSS = {};
2702
                            var arrangeContent = {};
2703
                            var arrangeChanged = force;
2704
                            var setContentElementCSS;
2705

2706
                            if (hasOverflow.x || hasOverflow.y) {
2707
                                arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty;
2708
                                arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty;
2709
                                arrangeChanged = checkCacheAutoForce(arrangeContent, _arrangeContentSizeCache);
2710
                                _arrangeContentSizeCache = arrangeContent;
2711
                            }
2712

2713
                            if (hasOverflow.c || hideOverflow.c || contentScrollSize.c || cssDirectionChanged || widthAutoChanged || heightAutoChanged || widthAuto || heightAuto || ignoreOverlayScrollbarHidingChanged) {
2714
                                contentElementCSS[_strMarginMinus + isRTLRight] = contentElementCSS[_strBorderMinus + isRTLRight] = _strEmpty;
2715
                                setContentElementCSS = function (horizontal) {
2716
                                    var scrollbarVars = getScrollbarVars(horizontal);
2717
                                    var scrollbarVarsInverted = getScrollbarVars(!horizontal);
2718
                                    var xy = scrollbarVars._x_y;
2719
                                    var strDirection = horizontal ? _strBottom : isRTLLeft;
2720
                                    var invertedAutoSize = horizontal ? heightAuto : widthAuto;
2721

2722
                                    if (_nativeScrollbarIsOverlaid[xy] && hasOverflow[xy] && hideOverflow[xy + 's']) {
2723
                                        contentElementCSS[_strMarginMinus + strDirection] = invertedAutoSize ? (ignoreOverlayScrollbarHiding ? _strEmpty : _overlayScrollbarDummySize[xy]) : _strEmpty;
2724
                                        contentElementCSS[_strBorderMinus + strDirection] = ((horizontal ? !invertedAutoSize : true) && !ignoreOverlayScrollbarHiding) ? (_overlayScrollbarDummySize[xy] + borderDesign) : _strEmpty;
2725
                                    }
2726
                                    else {
2727
                                        arrangeContent[scrollbarVarsInverted._w_h] =
2728
                                            contentElementCSS[_strMarginMinus + strDirection] =
2729
                                            contentElementCSS[_strBorderMinus + strDirection] = _strEmpty;
2730
                                        arrangeChanged = true;
2731
                                    }
2732
                                };
2733

2734
                                if (_nativeScrollbarStyling) {
2735
                                    addRemoveClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible, !ignoreOverlayScrollbarHiding)
2736
                                }
2737
                                else {
2738
                                    setContentElementCSS(true);
2739
                                    setContentElementCSS(false);
2740
                                }
2741
                            }
2742
                            if (ignoreOverlayScrollbarHiding) {
2743
                                arrangeContent.w = arrangeContent.h = _strEmpty;
2744
                                arrangeChanged = true;
2745
                            }
2746
                            if (arrangeChanged && !_nativeScrollbarStyling) {
2747
                                contentArrangeElementCSS[_strWidth] = hideOverflow.y ? arrangeContent.w : _strEmpty;
2748
                                contentArrangeElementCSS[_strHeight] = hideOverflow.x ? arrangeContent.h : _strEmpty;
2749

2750
                                if (!_contentArrangeElement) {
2751
                                    _contentArrangeElement = FRAMEWORK(generateDiv(_classNameContentArrangeElement));
2752
                                    _viewportElement.prepend(_contentArrangeElement);
2753
                                }
2754
                                _contentArrangeElement.css(contentArrangeElementCSS);
2755
                            }
2756
                            _contentElement.css(contentElementCSS);
2757
                        }
2758

2759
                        var viewportElementCSS = {};
2760
                        var paddingElementCSS = {};
2761
                        var setViewportCSS;
2762
                        if (hostSizeChanged || hasOverflow.c || hideOverflow.c || contentScrollSize.c || overflowBehaviorChanged || boxSizingChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged || clipAlwaysChanged || heightAutoChanged) {
2763
                            viewportElementCSS[isRTLRight] = _strEmpty;
2764
                            setViewportCSS = function (horizontal) {
2765
                                var scrollbarVars = getScrollbarVars(horizontal);
2766
                                var scrollbarVarsInverted = getScrollbarVars(!horizontal);
2767
                                var xy = scrollbarVars._x_y;
2768
                                var XY = scrollbarVars._X_Y;
2769
                                var strDirection = horizontal ? _strBottom : isRTLLeft;
2770

2771
                                var reset = function () {
2772
                                    viewportElementCSS[strDirection] = _strEmpty;
2773
                                    _contentBorderSize[scrollbarVarsInverted._w_h] = 0;
2774
                                };
2775
                                if (hasOverflow[xy] && hideOverflow[xy + 's']) {
2776
                                    viewportElementCSS[strOverflow + XY] = _strScroll;
2777
                                    if (ignoreOverlayScrollbarHiding || _nativeScrollbarStyling) {
2778
                                        reset();
2779
                                    }
2780
                                    else {
2781
                                        viewportElementCSS[strDirection] = -(_nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[xy] : _nativeScrollbarSize[xy]);
2782
                                        _contentBorderSize[scrollbarVarsInverted._w_h] = _nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[scrollbarVarsInverted._x_y] : 0;
2783
                                    }
2784
                                } else {
2785
                                    viewportElementCSS[strOverflow + XY] = _strEmpty;
2786
                                    reset();
2787
                                }
2788
                            };
2789
                            setViewportCSS(true);
2790
                            setViewportCSS(false);
2791

2792
                            // if the scroll container is too small and if there is any overflow with no overlay scrollbar (and scrollbar styling isn't possible), 
2793
                            // make viewport element greater in size (Firefox hide Scrollbars fix)
2794
                            // because firefox starts hiding scrollbars on too small elements
2795
                            // with this behavior the overflow calculation may be incorrect or the scrollbars would appear suddenly
2796
                            // https://bugzilla.mozilla.org/show_bug.cgi?id=292284
2797
                            if (!_nativeScrollbarStyling
2798
                                && (_viewportSize.h < _nativeScrollbarMinSize.x || _viewportSize.w < _nativeScrollbarMinSize.y)
2799
                                && ((hasOverflow.x && hideOverflow.x && !_nativeScrollbarIsOverlaid.x) || (hasOverflow.y && hideOverflow.y && !_nativeScrollbarIsOverlaid.y))) {
2800
                                viewportElementCSS[_strPaddingMinus + _strTop] = _nativeScrollbarMinSize.x;
2801
                                viewportElementCSS[_strMarginMinus + _strTop] = -_nativeScrollbarMinSize.x;
2802

2803
                                viewportElementCSS[_strPaddingMinus + isRTLRight] = _nativeScrollbarMinSize.y;
2804
                                viewportElementCSS[_strMarginMinus + isRTLRight] = -_nativeScrollbarMinSize.y;
2805
                            }
2806
                            else {
2807
                                viewportElementCSS[_strPaddingMinus + _strTop] =
2808
                                    viewportElementCSS[_strMarginMinus + _strTop] =
2809
                                    viewportElementCSS[_strPaddingMinus + isRTLRight] =
2810
                                    viewportElementCSS[_strMarginMinus + isRTLRight] = _strEmpty;
2811
                            }
2812
                            viewportElementCSS[_strPaddingMinus + isRTLLeft] =
2813
                                viewportElementCSS[_strMarginMinus + isRTLLeft] = _strEmpty;
2814

2815
                            //if there is any overflow (x OR y axis) and this overflow shall be hidden, make overflow hidden, else overflow visible
2816
                            if ((hasOverflow.x && hideOverflow.x) || (hasOverflow.y && hideOverflow.y) || hideOverflowForceTextarea) {
2817
                                //only hide if is Textarea
2818
                                if (_isTextarea && hideOverflowForceTextarea) {
2819
                                    paddingElementCSS[strOverflowX] =
2820
                                        paddingElementCSS[strOverflowY] = strHidden;
2821
                                }
2822
                            }
2823
                            else {
2824
                                if (!clipAlways || (overflowBehaviorIsVH.x || overflowBehaviorIsVS.x || overflowBehaviorIsVH.y || overflowBehaviorIsVS.y)) {
2825
                                    //only un-hide if Textarea
2826
                                    if (_isTextarea) {
2827
                                        paddingElementCSS[strOverflowX] =
2828
                                            paddingElementCSS[strOverflowY] = _strEmpty;
2829
                                    }
2830
                                    viewportElementCSS[strOverflowX] =
2831
                                        viewportElementCSS[strOverflowY] = strVisible;
2832
                                }
2833
                            }
2834

2835
                            _paddingElement.css(paddingElementCSS);
2836
                            _viewportElement.css(viewportElementCSS);
2837
                            viewportElementCSS = {};
2838

2839
                            //force soft redraw in webkit because without the scrollbars will may appear because DOM wont be redrawn under special conditions
2840
                            if ((hasOverflow.c || boxSizingChanged || widthAutoChanged || heightAutoChanged) && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
2841
                                var elementStyle = _contentElementNative[LEXICON.s];
2842
                                var dump;
2843
                                elementStyle.webkitTransform = 'scale(1)';
2844
                                elementStyle.display = 'run-in';
2845
                                dump = _contentElementNative[LEXICON.oH];
2846
                                elementStyle.display = _strEmpty; //|| dump; //use dump to prevent it from deletion if minify
2847
                                elementStyle.webkitTransform = _strEmpty;
2848
                            }
2849
                            /*
2850
                            //force hard redraw in webkit if native overlaid scrollbars shall appear
2851
                            if (ignoreOverlayScrollbarHidingChanged && ignoreOverlayScrollbarHiding) {
2852
                                _hostElement.hide();
2853
                                var dump = _hostElementNative[LEXICON.oH];
2854
                                _hostElement.show();
2855
                            }
2856
                            */
2857
                        }
2858

2859
                        //change to direction RTL and width auto Bugfix in Webkit
2860
                        //without this fix, the DOM still thinks the scrollbar is LTR and thus the content is shifted to the left
2861
                        contentElementCSS = {};
2862
                        if (cssDirectionChanged || widthAutoChanged || heightAutoChanged) {
2863
                            if (_isRTL && widthAuto) {
2864
                                var floatTmp = _contentElement.css(_strFloat);
2865
                                var posLeftWithoutFloat = MATH.round(_contentElement.css(_strFloat, _strEmpty).css(_strLeft, _strEmpty).position().left);
2866
                                _contentElement.css(_strFloat, floatTmp);
2867
                                var posLeftWithFloat = MATH.round(_contentElement.position().left);
2868

2869
                                if (posLeftWithoutFloat !== posLeftWithFloat)
2870
                                    contentElementCSS[_strLeft] = posLeftWithoutFloat;
2871
                            }
2872
                            else {
2873
                                contentElementCSS[_strLeft] = _strEmpty;
2874
                            }
2875
                        }
2876
                        _contentElement.css(contentElementCSS);
2877

2878
                        //handle scroll position
2879
                        if (_isTextarea && contentSizeChanged) {
2880
                            var textareaInfo = getTextareaInfo();
2881
                            if (textareaInfo) {
2882
                                var textareaRowsChanged = _textareaInfoCache === undefined ? true : textareaInfo._rows !== _textareaInfoCache._rows;
2883
                                var cursorRow = textareaInfo._cursorRow;
2884
                                var cursorCol = textareaInfo._cursorColumn;
2885
                                var widestRow = textareaInfo._widestRow;
2886
                                var lastRow = textareaInfo._rows;
2887
                                var lastCol = textareaInfo._columns;
2888
                                var cursorPos = textareaInfo._cursorPosition;
2889
                                var cursorMax = textareaInfo._cursorMax;
2890
                                var cursorIsLastPosition = (cursorPos >= cursorMax && _textareaHasFocus);
2891
                                var textareaScrollAmount = {
2892
                                    x: (!textareaAutoWrapping && (cursorCol === lastCol && cursorRow === widestRow)) ? _overflowAmountCache.x : -1,
2893
                                    y: (textareaAutoWrapping ? cursorIsLastPosition || textareaRowsChanged && (previousOverflowAmount ? (currScroll.y === previousOverflowAmount.y) : false) : (cursorIsLastPosition || textareaRowsChanged) && cursorRow === lastRow) ? _overflowAmountCache.y : -1
2894
                                };
2895
                                currScroll.x = textareaScrollAmount.x > -1 ? (_isRTL && _normalizeRTLCache && _rtlScrollBehavior.i ? 0 : textareaScrollAmount.x) : currScroll.x; //if inverted, scroll to 0 -> normalized this means to max scroll offset.
2896
                                currScroll.y = textareaScrollAmount.y > -1 ? textareaScrollAmount.y : currScroll.y;
2897
                            }
2898
                            _textareaInfoCache = textareaInfo;
2899
                        }
2900
                        if (_isRTL && _rtlScrollBehavior.i && _nativeScrollbarIsOverlaid.y && hasOverflow.x && _normalizeRTLCache)
2901
                            currScroll.x += _contentBorderSize.w || 0;
2902
                        if (widthAuto)
2903
                            _hostElement[_strScrollLeft](0);
2904
                        if (heightAuto)
2905
                            _hostElement[_strScrollTop](0);
2906
                        _viewportElement[_strScrollLeft](currScroll.x)[_strScrollTop](currScroll.y);
2907

2908
                        //scrollbars management:
2909
                        var scrollbarsVisibilityVisible = scrollbarsVisibility === 'v';
2910
                        var scrollbarsVisibilityHidden = scrollbarsVisibility === 'h';
2911
                        var scrollbarsVisibilityAuto = scrollbarsVisibility === 'a';
2912
                        var refreshScrollbarsVisibility = function (showX, showY) {
2913
                            showY = showY === undefined ? showX : showY;
2914
                            refreshScrollbarAppearance(true, showX, canScroll.x)
2915
                            refreshScrollbarAppearance(false, showY, canScroll.y)
2916
                        };
2917

2918
                        //manage class name which indicates scrollable overflow
2919
                        addRemoveClass(_hostElement, _classNameHostOverflow, hideOverflow.x || hideOverflow.y);
2920
                        addRemoveClass(_hostElement, _classNameHostOverflowX, hideOverflow.x);
2921
                        addRemoveClass(_hostElement, _classNameHostOverflowY, hideOverflow.y);
2922

2923
                        //add or remove rtl class name for styling purposes except when its body, then the scrollbar stays
2924
                        if (cssDirectionChanged && !_isBody) {
2925
                            addRemoveClass(_hostElement, _classNameHostRTL, _isRTL);
2926
                        }
2927

2928
                        //manage the resize feature (CSS3 resize "polyfill" for this plugin)
2929
                        if (_isBody)
2930
                            addClass(_hostElement, _classNameHostResizeDisabled);
2931
                        if (resizeChanged) {
2932
                            addRemoveClass(_hostElement, _classNameHostResizeDisabled, _resizeNone);
2933
                            addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResize, !_resizeNone);
2934
                            addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeB, _resizeBoth);
2935
                            addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeH, _resizeHorizontal);
2936
                            addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV, _resizeVertical);
2937
                        }
2938

2939
                        //manage the scrollbars general visibility + the scrollbar interactivity (unusable class name)
2940
                        if (scrollbarsVisibilityChanged || overflowBehaviorChanged || hideOverflow.c || hasOverflow.c || ignoreOverlayScrollbarHidingChanged) {
2941
                            if (ignoreOverlayScrollbarHiding) {
2942
                                if (ignoreOverlayScrollbarHidingChanged) {
2943
                                    removeClass(_hostElement, _classNameHostScrolling);
2944
                                    if (ignoreOverlayScrollbarHiding) {
2945
                                        refreshScrollbarsVisibility(false);
2946
                                    }
2947
                                }
2948
                            }
2949
                            else if (scrollbarsVisibilityAuto) {
2950
                                refreshScrollbarsVisibility(canScroll.x, canScroll.y);
2951
                            }
2952
                            else if (scrollbarsVisibilityVisible) {
2953
                                refreshScrollbarsVisibility(true);
2954
                            }
2955
                            else if (scrollbarsVisibilityHidden) {
2956
                                refreshScrollbarsVisibility(false);
2957
                            }
2958
                        }
2959

2960
                        //manage the scrollbars auto hide feature (auto hide them after specific actions)
2961
                        if (scrollbarsAutoHideChanged || ignoreOverlayScrollbarHidingChanged) {
2962
                            setupHostMouseTouchEvents(!_scrollbarsAutoHideLeave && !_scrollbarsAutoHideMove);
2963
                            refreshScrollbarsAutoHide(_scrollbarsAutoHideNever, !_scrollbarsAutoHideNever);
2964
                        }
2965

2966
                        //manage scrollbars handle length & offset - don't remove!
2967
                        if (hostSizeChanged || overflowAmount.c || heightAutoChanged || widthAutoChanged || resizeChanged || boxSizingChanged || paddingAbsoluteChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged) {
2968
                            refreshScrollbarHandleLength(true);
2969
                            refreshScrollbarHandleOffset(true);
2970
                            refreshScrollbarHandleLength(false);
2971
                            refreshScrollbarHandleOffset(false);
2972
                        }
2973

2974
                        //manage interactivity
2975
                        if (scrollbarsClickScrollingChanged)
2976
                            refreshScrollbarsInteractive(true, scrollbarsClickScrolling);
2977
                        if (scrollbarsDragScrollingChanged)
2978
                            refreshScrollbarsInteractive(false, scrollbarsDragScrolling);
2979

2980
                        //callbacks:
2981
                        dispatchCallback('onDirectionChanged', {
2982
                            isRTL: _isRTL,
2983
                            dir: cssDirection
2984
                        }, cssDirectionChanged);
2985
                        dispatchCallback('onHostSizeChanged', {
2986
                            width: _hostSizeCache.w,
2987
                            height: _hostSizeCache.h
2988
                        }, hostSizeChanged);
2989
                        dispatchCallback('onContentSizeChanged', {
2990
                            width: _contentScrollSizeCache.w,
2991
                            height: _contentScrollSizeCache.h
2992
                        }, contentSizeChanged);
2993
                        dispatchCallback('onOverflowChanged', {
2994
                            x: hasOverflow.x,
2995
                            y: hasOverflow.y,
2996
                            xScrollable: hideOverflow.xs,
2997
                            yScrollable: hideOverflow.ys,
2998
                            clipped: hideOverflow.x || hideOverflow.y
2999
                        }, hasOverflow.c || hideOverflow.c);
3000
                        dispatchCallback('onOverflowAmountChanged', {
3001
                            x: overflowAmount.x,
3002
                            y: overflowAmount.y
3003
                        }, overflowAmount.c);
3004
                    }
3005

3006
                    //fix body min size
3007
                    if (_isBody && _bodyMinSizeCache && (_hasOverflowCache.c || _bodyMinSizeCache.c)) {
3008
                        //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.
3009
                        if (!_bodyMinSizeCache.f)
3010
                            bodyMinSizeChanged();
3011
                        if (_nativeScrollbarIsOverlaid.y && _hasOverflowCache.x)
3012
                            _contentElement.css(_strMinMinus + _strWidth, _bodyMinSizeCache.w + _overlayScrollbarDummySize.y);
3013
                        if (_nativeScrollbarIsOverlaid.x && _hasOverflowCache.y)
3014
                            _contentElement.css(_strMinMinus + _strHeight, _bodyMinSizeCache.h + _overlayScrollbarDummySize.x);
3015
                        _bodyMinSizeCache.c = false;
3016
                    }
3017

3018
                    if (_initialized && changedOptions.updateOnLoad) {
3019
                        updateElementsOnLoad();
3020
                    }
3021

3022
                    //freezeResizeObserver(_sizeObserverElement, false);
3023
                    //freezeResizeObserver(_sizeAutoObserverElement, false);
3024

3025
                    dispatchCallback('onUpdated', { forced: force });
3026
                }
3027

3028
                /**
3029
                 * Updates the found elements of which the load event shall be handled.
3030
                 */
3031
                function updateElementsOnLoad() {
3032
                    if (!_isTextarea) {
3033
                        eachUpdateOnLoad(function (i, updateOnLoadSelector) {
3034
                            _contentElement.find(updateOnLoadSelector).each(function (i, el) {
3035
                                // if element doesn't have a updateOnLoadCallback applied
3036
                                if (COMPATIBILITY.inA(el, _updateOnLoadElms) < 0) {
3037
                                    _updateOnLoadElms.push(el);
3038
                                    FRAMEWORK(el)
3039
                                        .off(_updateOnLoadEventName, updateOnLoadCallback)
3040
                                        .on(_updateOnLoadEventName, updateOnLoadCallback);
3041
                                }
3042
                            });
3043
                        });
3044
                    }
3045
                }
3046

3047
                //==== Options ====//
3048

3049
                /**
3050
                 * Sets new options but doesn't call the update method.
3051
                 * @param newOptions The object which contains the new options.
3052
                 * @returns {*} A object which contains the changed options.
3053
                 */
3054
                function setOptions(newOptions) {
3055
                    var validatedOpts = _pluginsOptions._validate(newOptions, _pluginsOptions._template, true, _currentOptions)
3056

3057
                    _currentOptions = extendDeep({}, _currentOptions, validatedOpts._default);
3058
                    _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, validatedOpts._prepared);
3059

3060
                    return validatedOpts._prepared;
3061
                }
3062

3063

3064
                //==== Structure ====//
3065

3066
                /**
3067
                 * Builds or destroys the wrapper and helper DOM elements.
3068
                 * @param destroy Indicates whether the DOM shall be build or destroyed.
3069
                 */
3070
                /**
3071
                 * Builds or destroys the wrapper and helper DOM elements.
3072
                 * @param destroy Indicates whether the DOM shall be build or destroyed.
3073
                 */
3074
                function setupStructureDOM(destroy) {
3075
                    var strParent = 'parent';
3076
                    var classNameResizeObserverHost = 'os-resize-observer-host';
3077
                    var classNameTextareaElementFull = _classNameTextareaElement + _strSpace + _classNameTextInherit;
3078
                    var textareaClass = _isTextarea ? _strSpace + _classNameTextInherit : _strEmpty;
3079
                    var adoptAttrs = _currentPreparedOptions.textarea.inheritedAttrs;
3080
                    var adoptAttrsMap = {};
3081
                    var applyAdoptedAttrs = function () {
3082
                        var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement;
3083
                        each(adoptAttrsMap, function (key, value) {
3084
                            if (type(value) == TYPES.s) {
3085
                                if (key == LEXICON.c)
3086
                                    applyAdoptedAttrsElm.addClass(value);
3087
                                else
3088
                                    applyAdoptedAttrsElm.attr(key, value);
3089
                            }
3090
                        });
3091
                    };
3092
                    var hostElementClassNames = [
3093
                        _classNameHostElement,
3094
                        _classNameHostElementForeign,
3095
                        _classNameHostTextareaElement,
3096
                        _classNameHostResizeDisabled,
3097
                        _classNameHostRTL,
3098
                        _classNameHostScrollbarHorizontalHidden,
3099
                        _classNameHostScrollbarVerticalHidden,
3100
                        _classNameHostTransition,
3101
                        _classNameHostScrolling,
3102
                        _classNameHostOverflow,
3103
                        _classNameHostOverflowX,
3104
                        _classNameHostOverflowY,
3105
                        _classNameThemeNone,
3106
                        _classNameTextareaElement,
3107
                        _classNameTextInherit,
3108
                        _classNameCache].join(_strSpace);
3109
                    var hostElementCSS = {};
3110

3111
                    //get host element as first element, because that's the most upper element and required for the other elements
3112
                    _hostElement = _hostElement || (_isTextarea ? (_domExists ? _targetElement[strParent]()[strParent]()[strParent]()[strParent]() : FRAMEWORK(generateDiv(_classNameHostTextareaElement))) : _targetElement);
3113
                    _contentElement = _contentElement || selectOrGenerateDivByClass(_classNameContentElement + textareaClass);
3114
                    _viewportElement = _viewportElement || selectOrGenerateDivByClass(_classNameViewportElement + textareaClass);
3115
                    _paddingElement = _paddingElement || selectOrGenerateDivByClass(_classNamePaddingElement + textareaClass);
3116
                    _sizeObserverElement = _sizeObserverElement || selectOrGenerateDivByClass(classNameResizeObserverHost);
3117
                    _textareaCoverElement = _textareaCoverElement || (_isTextarea ? selectOrGenerateDivByClass(_classNameTextareaCoverElement) : undefined);
3118

3119
                    //add this class to workaround class changing issues with UI frameworks especially Vue
3120
                    if (_domExists)
3121
                        addClass(_hostElement, _classNameHostElementForeign);
3122

3123
                    //on destroy, remove all generated class names from the host element before collecting the adopted attributes 
3124
                    //to prevent adopting generated class names
3125
                    if (destroy)
3126
                        removeClass(_hostElement, hostElementClassNames);
3127

3128
                    //collect all adopted attributes
3129
                    adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(_strSpace) : adoptAttrs;
3130
                    if (COMPATIBILITY.isA(adoptAttrs) && _isTextarea) {
3131
                        each(adoptAttrs, function (i, v) {
3132
                            if (type(v) == TYPES.s) {
3133
                                adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v);
3134
                            }
3135
                        });
3136
                    }
3137

3138
                    if (!destroy) {
3139
                        if (_isTextarea) {
3140
                            if (!_currentPreparedOptions.sizeAutoCapable) {
3141
                                hostElementCSS[_strWidth] = _targetElement.css(_strWidth);
3142
                                hostElementCSS[_strHeight] = _targetElement.css(_strHeight);
3143
                            }
3144

3145
                            if (!_domExists)
3146
                                _targetElement.addClass(_classNameTextInherit).wrap(_hostElement);
3147

3148
                            //jQuery clones elements in wrap functions, so we have to select them again
3149
                            _hostElement = _targetElement[strParent]().css(hostElementCSS);
3150
                        }
3151

3152
                        if (!_domExists) {
3153
                            //add the correct class to the target element
3154
                            addClass(_targetElement, _isTextarea ? classNameTextareaElementFull : _classNameHostElement);
3155

3156
                            //wrap the content into the generated elements to create the required DOM
3157
                            _hostElement.wrapInner(_contentElement)
3158
                                .wrapInner(_viewportElement)
3159
                                .wrapInner(_paddingElement)
3160
                                .prepend(_sizeObserverElement);
3161

3162
                            //jQuery clones elements in wrap functions, so we have to select them again
3163
                            _contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);
3164
                            _viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);
3165
                            _paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);
3166

3167
                            if (_isTextarea) {
3168
                                _contentElement.prepend(_textareaCoverElement);
3169
                                applyAdoptedAttrs();
3170
                            }
3171
                        }
3172

3173
                        if (_nativeScrollbarStyling)
3174
                            addClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
3175
                        if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)
3176
                            addClass(_viewportElement, _classNameViewportNativeScrollbarsOverlaid);
3177
                        if (_isBody)
3178
                            addClass(_htmlElement, _classNameHTMLElement);
3179

3180
                        _sizeObserverElementNative = _sizeObserverElement[0];
3181
                        _hostElementNative = _hostElement[0];
3182
                        _paddingElementNative = _paddingElement[0];
3183
                        _viewportElementNative = _viewportElement[0];
3184
                        _contentElementNative = _contentElement[0];
3185

3186
                        updateViewportAttrsFromTarget();
3187
                    }
3188
                    else {
3189
                        if (_domExists && _initialized) {
3190
                            //clear size observer
3191
                            _sizeObserverElement.children().remove();
3192

3193
                            //remove the style property and classes from already generated elements
3194
                            each([_paddingElement, _viewportElement, _contentElement, _textareaCoverElement], function (i, elm) {
3195
                                if (elm) {
3196
                                    removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
3197
                                }
3198
                            });
3199

3200
                            //add classes to the host element which was removed previously to match the expected DOM
3201
                            addClass(_hostElement, _isTextarea ? _classNameHostTextareaElement : _classNameHostElement);
3202
                        }
3203
                        else {
3204
                            //remove size observer
3205
                            remove(_sizeObserverElement);
3206

3207
                            //unwrap the content to restore DOM
3208
                            _contentElement.contents()
3209
                                .unwrap()
3210
                                .unwrap()
3211
                                .unwrap();
3212

3213
                            if (_isTextarea) {
3214
                                _targetElement.unwrap();
3215
                                remove(_hostElement);
3216
                                remove(_textareaCoverElement);
3217
                                applyAdoptedAttrs();
3218
                            }
3219
                        }
3220

3221
                        if (_isTextarea)
3222
                            _targetElement.removeAttr(LEXICON.s);
3223

3224
                        if (_isBody)
3225
                            removeClass(_htmlElement, _classNameHTMLElement);
3226
                    }
3227
                }
3228

3229
                /**
3230
                 * Adds or removes all wrapper elements interactivity events.
3231
                 * @param destroy Indicates whether the Events shall be added or removed.
3232
                 */
3233
                function setupStructureEvents() {
3234
                    var textareaKeyDownRestrictedKeyCodes = [
3235
                        112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123,    //F1 to F12
3236
                        33, 34,                                                   //page up, page down
3237
                        37, 38, 39, 40,                                           //left, up, right, down arrows
3238
                        16, 17, 18, 19, 20, 144                                   //Shift, Ctrl, Alt, Pause, CapsLock, NumLock
3239
                    ];
3240
                    var textareaKeyDownKeyCodesList = [];
3241
                    var textareaUpdateIntervalID;
3242
                    var scrollStopTimeoutId;
3243
                    var scrollStopDelay = 175;
3244
                    var strFocus = 'focus';
3245

3246
                    function updateTextarea(doClearInterval) {
3247
                        textareaUpdate();
3248
                        _base.update(_strAuto);
3249
                        if (doClearInterval && _autoUpdateRecommended)
3250
                            clearInterval(textareaUpdateIntervalID);
3251
                    }
3252
                    function textareaOnScroll(event) {
3253
                        _targetElement[_strScrollLeft](_rtlScrollBehavior.i && _normalizeRTLCache ? 9999999 : 0);
3254
                        _targetElement[_strScrollTop](0);
3255
                        COMPATIBILITY.prvD(event);
3256
                        COMPATIBILITY.stpP(event);
3257
                        return false;
3258
                    }
3259
                    function textareaOnDrop(event) {
3260
                        setTimeout(function () {
3261
                            if (!_destroyed)
3262
                                updateTextarea();
3263
                        }, 50);
3264
                    }
3265
                    function textareaOnFocus() {
3266
                        _textareaHasFocus = true;
3267
                        addClass(_hostElement, strFocus);
3268
                    }
3269
                    function textareaOnFocusout() {
3270
                        _textareaHasFocus = false;
3271
                        textareaKeyDownKeyCodesList = [];
3272
                        removeClass(_hostElement, strFocus);
3273
                        updateTextarea(true);
3274
                    }
3275
                    function textareaOnKeyDown(event) {
3276
                        var keyCode = event.keyCode;
3277

3278
                        if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {
3279
                            if (!textareaKeyDownKeyCodesList[LEXICON.l]) {
3280
                                updateTextarea();
3281
                                textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60);
3282
                            }
3283
                            if (inArray(keyCode, textareaKeyDownKeyCodesList) < 0)
3284
                                textareaKeyDownKeyCodesList.push(keyCode);
3285
                        }
3286
                    }
3287
                    function textareaOnKeyUp(event) {
3288
                        var keyCode = event.keyCode;
3289
                        var index = inArray(keyCode, textareaKeyDownKeyCodesList);
3290

3291
                        if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {
3292
                            if (index > -1)
3293
                                textareaKeyDownKeyCodesList.splice(index, 1);
3294
                            if (!textareaKeyDownKeyCodesList[LEXICON.l])
3295
                                updateTextarea(true);
3296
                        }
3297
                    }
3298
                    function contentOnTransitionEnd(event) {
3299
                        if (_autoUpdateCache === true)
3300
                            return;
3301
                        event = event.originalEvent || event;
3302
                        if (isSizeAffectingCSSProperty(event.propertyName))
3303
                            _base.update(_strAuto);
3304
                    }
3305
                    function viewportOnScroll(event) {
3306
                        if (!_sleeping) {
3307
                            if (scrollStopTimeoutId !== undefined)
3308
                                clearTimeout(scrollStopTimeoutId);
3309
                            else {
3310
                                if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
3311
                                    refreshScrollbarsAutoHide(true);
3312

3313
                                if (!nativeOverlayScrollbarsAreActive())
3314
                                    addClass(_hostElement, _classNameHostScrolling);
3315

3316
                                dispatchCallback('onScrollStart', event);
3317
                            }
3318

3319
                            //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset
3320
                            //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point
3321
                            //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove
3322
                            if (!_scrollbarsHandlesDefineScrollPos) {
3323
                                refreshScrollbarHandleOffset(true);
3324
                                refreshScrollbarHandleOffset(false);
3325
                            }
3326
                            dispatchCallback('onScroll', event);
3327

3328
                            scrollStopTimeoutId = setTimeout(function () {
3329
                                if (!_destroyed) {
3330
                                    //OnScrollStop:
3331
                                    clearTimeout(scrollStopTimeoutId);
3332
                                    scrollStopTimeoutId = undefined;
3333

3334
                                    if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
3335
                                        refreshScrollbarsAutoHide(false);
3336

3337
                                    if (!nativeOverlayScrollbarsAreActive())
3338
                                        removeClass(_hostElement, _classNameHostScrolling);
3339

3340
                                    dispatchCallback('onScrollStop', event);
3341
                                }
3342
                            }, scrollStopDelay);
3343
                        }
3344
                    }
3345

3346

3347
                    if (_isTextarea) {
3348
                        if (_msieVersion > 9 || !_autoUpdateRecommended) {
3349
                            addDestroyEventListener(_targetElement, 'input', updateTextarea);
3350
                        }
3351
                        else {
3352
                            addDestroyEventListener(_targetElement,
3353
                                [_strKeyDownEvent, _strKeyUpEvent],
3354
                                [textareaOnKeyDown, textareaOnKeyUp]);
3355
                        }
3356

3357
                        addDestroyEventListener(_targetElement,
3358
                            [_strScroll, 'drop', strFocus, strFocus + 'out'],
3359
                            [textareaOnScroll, textareaOnDrop, textareaOnFocus, textareaOnFocusout]);
3360
                    }
3361
                    else {
3362
                        addDestroyEventListener(_contentElement, _strTransitionEndEvent, contentOnTransitionEnd);
3363
                    }
3364
                    addDestroyEventListener(_viewportElement, _strScroll, viewportOnScroll, true);
3365
                }
3366

3367

3368
                //==== Scrollbars ====//
3369

3370
                /**
3371
                 * Builds or destroys all scrollbar DOM elements (scrollbar, track, handle)
3372
                 * @param destroy Indicates whether the DOM shall be build or destroyed.
3373
                 */
3374
                function setupScrollbarsDOM(destroy) {
3375
                    var selectOrGenerateScrollbarDOM = function (isHorizontal) {
3376
                        var scrollbarClassName = isHorizontal ? _classNameScrollbarHorizontal : _classNameScrollbarVertical;
3377
                        var scrollbar = selectOrGenerateDivByClass(_classNameScrollbar + _strSpace + scrollbarClassName, true);
3378
                        var track = selectOrGenerateDivByClass(_classNameScrollbarTrack, scrollbar);
3379
                        var handle = selectOrGenerateDivByClass(_classNameScrollbarHandle, scrollbar);
3380

3381
                        if (!_domExists && !destroy) {
3382
                            scrollbar.append(track);
3383
                            track.append(handle);
3384
                        }
3385

3386
                        return {
3387
                            _scrollbar: scrollbar,
3388
                            _track: track,
3389
                            _handle: handle
3390
                        };
3391
                    };
3392
                    function resetScrollbarDOM(isHorizontal) {
3393
                        var scrollbarVars = getScrollbarVars(isHorizontal);
3394
                        var scrollbar = scrollbarVars._scrollbar;
3395
                        var track = scrollbarVars._track;
3396
                        var handle = scrollbarVars._handle;
3397

3398
                        if (_domExists && _initialized) {
3399
                            each([scrollbar, track, handle], function (i, elm) {
3400
                                removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
3401
                            });
3402
                        }
3403
                        else {
3404
                            remove(scrollbar || selectOrGenerateScrollbarDOM(isHorizontal)._scrollbar);
3405
                        }
3406
                    }
3407
                    var horizontalElements;
3408
                    var verticalElements;
3409

3410
                    if (!destroy) {
3411
                        horizontalElements = selectOrGenerateScrollbarDOM(true);
3412
                        verticalElements = selectOrGenerateScrollbarDOM();
3413

3414
                        _scrollbarHorizontalElement = horizontalElements._scrollbar;
3415
                        _scrollbarHorizontalTrackElement = horizontalElements._track;
3416
                        _scrollbarHorizontalHandleElement = horizontalElements._handle;
3417
                        _scrollbarVerticalElement = verticalElements._scrollbar;
3418
                        _scrollbarVerticalTrackElement = verticalElements._track;
3419
                        _scrollbarVerticalHandleElement = verticalElements._handle;
3420

3421
                        if (!_domExists) {
3422
                            _paddingElement.after(_scrollbarVerticalElement);
3423
                            _paddingElement.after(_scrollbarHorizontalElement);
3424
                        }
3425
                    }
3426
                    else {
3427
                        resetScrollbarDOM(true);
3428
                        resetScrollbarDOM();
3429
                    }
3430
                }
3431

3432
                /**
3433
                 * Initializes all scrollbar interactivity events. (track and handle dragging, clicking, scrolling)
3434
                 * @param isHorizontal True if the target scrollbar is the horizontal scrollbar, false if the target scrollbar is the vertical scrollbar.
3435
                 */
3436
                function setupScrollbarEvents(isHorizontal) {
3437
                    var scrollbarVars = getScrollbarVars(isHorizontal);
3438
                    var scrollbarVarsInfo = scrollbarVars._info;
3439
                    var insideIFrame = _windowElementNative.top !== _windowElementNative;
3440
                    var xy = scrollbarVars._x_y;
3441
                    var XY = scrollbarVars._X_Y;
3442
                    var scroll = _strScroll + scrollbarVars._Left_Top;
3443
                    var strActive = 'active';
3444
                    var strSnapHandle = 'snapHandle';
3445
                    var strClickEvent = 'click';
3446
                    var scrollDurationFactor = 1;
3447
                    var increaseDecreaseScrollAmountKeyCodes = [16, 17]; //shift, ctrl
3448
                    var trackTimeout;
3449
                    var mouseDownScroll;
3450
                    var mouseDownOffset;
3451
                    var mouseDownInvertedScale;
3452

3453
                    function getPointerPosition(event) {
3454
                        return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames.
3455
                    }
3456
                    function getPreparedScrollbarsOption(name) {
3457
                        return _currentPreparedOptions.scrollbars[name];
3458
                    }
3459
                    function increaseTrackScrollAmount() {
3460
                        scrollDurationFactor = 0.5;
3461
                    }
3462
                    function decreaseTrackScrollAmount() {
3463
                        scrollDurationFactor = 1;
3464
                    }
3465
                    function stopClickEventPropagation(event) {
3466
                        COMPATIBILITY.stpP(event);
3467
                    }
3468
                    function documentKeyDown(event) {
3469
                        if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
3470
                            increaseTrackScrollAmount();
3471
                    }
3472
                    function documentKeyUp(event) {
3473
                        if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
3474
                            decreaseTrackScrollAmount();
3475
                    }
3476
                    function onMouseTouchDownContinue(event) {
3477
                        var originalEvent = event.originalEvent || event;
3478
                        var isTouchEvent = originalEvent.touches !== undefined;
3479
                        return _sleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
3480
                    }
3481
                    function documentDragMove(event) {
3482
                        if (onMouseTouchDownContinue(event)) {
3483
                            var trackLength = scrollbarVarsInfo._trackLength;
3484
                            var handleLength = scrollbarVarsInfo._handleLength;
3485
                            var scrollRange = scrollbarVarsInfo._maxScroll;
3486
                            var scrollRaw = (getPointerPosition(event) - mouseDownOffset) * mouseDownInvertedScale;
3487
                            var scrollDeltaPercent = scrollRaw / (trackLength - handleLength);
3488
                            var scrollDelta = (scrollRange * scrollDeltaPercent);
3489
                            scrollDelta = isFinite(scrollDelta) ? scrollDelta : 0;
3490
                            if (_isRTL && isHorizontal && !_rtlScrollBehavior.i)
3491
                                scrollDelta *= -1;
3492

3493
                            _viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta));
3494

3495
                            if (_scrollbarsHandlesDefineScrollPos)
3496
                                refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta);
3497

3498
                            if (!_supportPassiveEvents)
3499
                                COMPATIBILITY.prvD(event);
3500
                        }
3501
                        else
3502
                            documentMouseTouchUp(event);
3503
                    }
3504
                    function documentMouseTouchUp(event) {
3505
                        event = event || event.originalEvent;
3506

3507
                        setupResponsiveEventListener(_documentElement,
3508
                            [_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],
3509
                            [documentDragMove, documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart],
3510
                            true);
3511
                        COMPATIBILITY.rAF()(function() {
3512
                            setupResponsiveEventListener(_documentElement, strClickEvent, stopClickEventPropagation, true, { _capture: true });
3513
                        });
3514
                        
3515
                            
3516
                        if (_scrollbarsHandlesDefineScrollPos)
3517
                            refreshScrollbarHandleOffset(isHorizontal, true);
3518

3519
                        _scrollbarsHandlesDefineScrollPos = false;
3520
                        removeClass(_bodyElement, _classNameDragging);
3521
                        removeClass(scrollbarVars._handle, strActive);
3522
                        removeClass(scrollbarVars._track, strActive);
3523
                        removeClass(scrollbarVars._scrollbar, strActive);
3524

3525
                        mouseDownScroll = undefined;
3526
                        mouseDownOffset = undefined;
3527
                        mouseDownInvertedScale = 1;
3528

3529
                        decreaseTrackScrollAmount();
3530

3531
                        if (trackTimeout !== undefined) {
3532
                            _base.scrollStop();
3533
                            clearTimeout(trackTimeout);
3534
                            trackTimeout = undefined;
3535
                        }
3536

3537
                        if (event) {
3538
                            var rect = _hostElementNative[LEXICON.bCR]();
3539
                            var mouseInsideHost = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
3540

3541
                            //if mouse is outside host element
3542
                            if (!mouseInsideHost)
3543
                                hostOnMouseLeave();
3544

3545
                            if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
3546
                                refreshScrollbarsAutoHide(false);
3547
                        }
3548
                    }
3549
                    function onHandleMouseTouchDown(event) {
3550
                        if (onMouseTouchDownContinue(event))
3551
                            onHandleMouseTouchDownAction(event);
3552
                    }
3553
                    function onHandleMouseTouchDownAction(event) {
3554
                        mouseDownScroll = _viewportElement[scroll]();
3555
                        mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll;
3556
                        if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL)
3557
                            mouseDownScroll = mouseDownScroll < 0 ? 0 : mouseDownScroll;
3558

3559
                        mouseDownInvertedScale = getHostElementInvertedScale()[xy];
3560
                        mouseDownOffset = getPointerPosition(event);
3561

3562
                        _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);
3563
                        addClass(_bodyElement, _classNameDragging);
3564
                        addClass(scrollbarVars._handle, strActive);
3565
                        addClass(scrollbarVars._scrollbar, strActive);
3566

3567
                        setupResponsiveEventListener(_documentElement,
3568
                            [_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strSelectStartEvent],
3569
                            [documentDragMove, documentMouseTouchUp, documentOnSelectStart]);
3570
                        COMPATIBILITY.rAF()(function() {
3571
                            setupResponsiveEventListener(_documentElement, strClickEvent, stopClickEventPropagation, false, { _capture: true });
3572
                        });
3573
                        
3574

3575
                        if (_msieVersion || !_documentMixed)
3576
                            COMPATIBILITY.prvD(event);
3577
                        COMPATIBILITY.stpP(event);
3578
                    }
3579
                    function onTrackMouseTouchDown(event) {
3580
                        if (onMouseTouchDownContinue(event)) {
3581
                            var handleToViewportRatio = scrollbarVars._info._handleLength / Math.round(MATH.min(1, _viewportSize[scrollbarVars._w_h] / _contentScrollSizeCache[scrollbarVars._w_h]) * scrollbarVars._info._trackLength);
3582
                            var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h] * handleToViewportRatio);
3583
                            var scrollBaseDuration = 270 * handleToViewportRatio;
3584
                            var scrollFirstIterationDelay = 400 * handleToViewportRatio;
3585
                            var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top];
3586
                            var ctrlKey = event.ctrlKey;
3587
                            var instantScroll = event.shiftKey;
3588
                            var instantScrollTransition = instantScroll && ctrlKey;
3589
                            var isFirstIteration = true;
3590
                            var easing = 'linear';
3591
                            var decreaseScroll;
3592
                            var finishedCondition;
3593
                            var scrollActionFinsished = function (transition) {
3594
                                if (_scrollbarsHandlesDefineScrollPos)
3595
                                    refreshScrollbarHandleOffset(isHorizontal, transition);
3596
                            };
3597
                            var scrollActionInstantFinished = function () {
3598
                                scrollActionFinsished();
3599
                                onHandleMouseTouchDownAction(event);
3600
                            };
3601
                            var scrollAction = function () {
3602
                                if (!_destroyed) {
3603
                                    var mouseOffset = (mouseDownOffset - trackOffset) * mouseDownInvertedScale;
3604
                                    var handleOffset = scrollbarVarsInfo._handleOffset;
3605
                                    var trackLength = scrollbarVarsInfo._trackLength;
3606
                                    var handleLength = scrollbarVarsInfo._handleLength;
3607
                                    var scrollRange = scrollbarVarsInfo._maxScroll;
3608
                                    var currScroll = scrollbarVarsInfo._currentScroll;
3609
                                    var scrollDuration = scrollBaseDuration * scrollDurationFactor;
3610
                                    var timeoutDelay = isFirstIteration ? MATH.max(scrollFirstIterationDelay, scrollDuration) : scrollDuration;
3611
                                    var instantScrollPosition = scrollRange * ((mouseOffset - (handleLength / 2)) / (trackLength - handleLength)); // 100% * positionPercent
3612
                                    var rtlIsNormal = _isRTL && isHorizontal && ((!_rtlScrollBehavior.i && !_rtlScrollBehavior.n) || _normalizeRTLCache);
3613
                                    var decreaseScrollCondition = rtlIsNormal ? handleOffset < mouseOffset : handleOffset > mouseOffset;
3614
                                    var scrollObj = {};
3615
                                    var animationObj = {
3616
                                        easing: easing,
3617
                                        step: function (now) {
3618
                                            if (_scrollbarsHandlesDefineScrollPos) {
3619
                                                _viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/4340
3620
                                                refreshScrollbarHandleOffset(isHorizontal, now);
3621
                                            }
3622
                                        }
3623
                                    };
3624
                                    instantScrollPosition = isFinite(instantScrollPosition) ? instantScrollPosition : 0;
3625
                                    instantScrollPosition = _isRTL && isHorizontal && !_rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
3626

3627
                                    //_base.scrollStop();
3628

3629
                                    if (instantScroll) {
3630
                                        _viewportElement[scroll](instantScrollPosition); //scroll instantly to new position
3631
                                        if (instantScrollTransition) {
3632
                                            //get the scroll position after instant scroll (in case CSS Snap Points are used) to get the correct snapped scroll position
3633
                                            //and the animation stops at the correct point
3634
                                            instantScrollPosition = _viewportElement[scroll]();
3635
                                            //scroll back to the position before instant scrolling so animation can be performed
3636
                                            _viewportElement[scroll](currScroll);
3637

3638
                                            instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
3639
                                            instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.n ? -instantScrollPosition : instantScrollPosition;
3640

3641
                                            scrollObj[xy] = instantScrollPosition;
3642
                                            _base.scroll(scrollObj, extendDeep(animationObj, {
3643
                                                duration: 130,
3644
                                                complete: scrollActionInstantFinished
3645
                                            }));
3646
                                        }
3647
                                        else
3648
                                            scrollActionInstantFinished();
3649
                                    }
3650
                                    else {
3651
                                        decreaseScroll = isFirstIteration ? decreaseScrollCondition : decreaseScroll;
3652
                                        finishedCondition = rtlIsNormal
3653
                                            ? (decreaseScroll ? handleOffset + handleLength >= mouseOffset : handleOffset <= mouseOffset)
3654
                                            : (decreaseScroll ? handleOffset <= mouseOffset : handleOffset + handleLength >= mouseOffset);
3655

3656
                                        if (finishedCondition) {
3657
                                            clearTimeout(trackTimeout);
3658
                                            _base.scrollStop();
3659
                                            trackTimeout = undefined;
3660
                                            scrollActionFinsished(true);
3661
                                        }
3662
                                        else {
3663
                                            trackTimeout = setTimeout(scrollAction, timeoutDelay);
3664

3665
                                            scrollObj[xy] = (decreaseScroll ? '-=' : '+=') + scrollDistance;
3666
                                            _base.scroll(scrollObj, extendDeep(animationObj, {
3667
                                                duration: scrollDuration
3668
                                            }));
3669
                                        }
3670
                                        isFirstIteration = false;
3671
                                    }
3672
                                }
3673
                            };
3674
                            if (ctrlKey)
3675
                                increaseTrackScrollAmount();
3676

3677
                            mouseDownInvertedScale = getHostElementInvertedScale()[xy];
3678
                            mouseDownOffset = COMPATIBILITY.page(event)[xy];
3679

3680
                            _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);
3681
                            addClass(_bodyElement, _classNameDragging);
3682
                            addClass(scrollbarVars._track, strActive);
3683
                            addClass(scrollbarVars._scrollbar, strActive);
3684

3685
                            setupResponsiveEventListener(_documentElement,
3686
                                [_strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],
3687
                                [documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart]);
3688

3689
                            scrollAction();
3690
                            COMPATIBILITY.prvD(event);
3691
                            COMPATIBILITY.stpP(event);
3692
                        }
3693
                    }
3694
                    function onTrackMouseTouchEnter(event) {
3695
                        //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move".
3696
                        _scrollbarsHandleHovered = true;
3697
                        if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
3698
                            refreshScrollbarsAutoHide(true);
3699
                    }
3700
                    function onTrackMouseTouchLeave(event) {
3701
                        _scrollbarsHandleHovered = false;
3702
                        if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
3703
                            refreshScrollbarsAutoHide(false);
3704
                    }
3705
                    function onScrollbarMouseTouchDown(event) {
3706
                        COMPATIBILITY.stpP(event);
3707
                    }
3708

3709
                    addDestroyEventListener(scrollbarVars._handle,
3710
                        _strMouseTouchDownEvent,
3711
                        onHandleMouseTouchDown);
3712
                    addDestroyEventListener(scrollbarVars._track,
3713
                        [_strMouseTouchDownEvent, _strMouseEnter, _strMouseLeave],
3714
                        [onTrackMouseTouchDown, onTrackMouseTouchEnter, onTrackMouseTouchLeave]);
3715
                    addDestroyEventListener(scrollbarVars._scrollbar,
3716
                        _strMouseTouchDownEvent,
3717
                        onScrollbarMouseTouchDown);
3718

3719
                    if (_supportTransition) {
3720
                        addDestroyEventListener(scrollbarVars._scrollbar, _strTransitionEndEvent, function (event) {
3721
                            if (event.target !== scrollbarVars._scrollbar[0])
3722
                                return;
3723
                            refreshScrollbarHandleLength(isHorizontal);
3724
                            refreshScrollbarHandleOffset(isHorizontal);
3725
                        });
3726
                    }
3727
                }
3728

3729
                /**
3730
                 * Shows or hides the given scrollbar and applied a class name which indicates if the scrollbar is scrollable or not.
3731
                 * @param isHorizontal True if the horizontal scrollbar is the target, false if the vertical scrollbar is the target.
3732
                 * @param shallBeVisible True if the scrollbar shall be shown, false if hidden.
3733
                 * @param canScroll True if the scrollbar is scrollable, false otherwise.
3734
                 */
3735
                function refreshScrollbarAppearance(isHorizontal, shallBeVisible, canScroll) {
3736
                    var scrollbarHiddenClassName = isHorizontal ? _classNameHostScrollbarHorizontalHidden : _classNameHostScrollbarVerticalHidden;
3737
                    var scrollbarElement = isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement;
3738

3739
                    addRemoveClass(_hostElement, scrollbarHiddenClassName, !shallBeVisible);
3740
                    addRemoveClass(scrollbarElement, _classNameScrollbarUnusable, !canScroll);
3741
                }
3742

3743
                /**
3744
                 * Autoshows / autohides both scrollbars with.
3745
                 * @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.
3746
                 * @param delayfree True if the scrollbars shall be hidden without a delay, false or undefined otherwise.
3747
                 */
3748
                function refreshScrollbarsAutoHide(shallBeVisible, delayfree) {
3749
                    clearTimeout(_scrollbarsAutoHideTimeoutId);
3750
                    if (shallBeVisible) {
3751
                        //if(_hasOverflowCache.x && _hideOverflowCache.xs)
3752
                        removeClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
3753
                        //if(_hasOverflowCache.y && _hideOverflowCache.ys)
3754
                        removeClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
3755
                    }
3756
                    else {
3757
                        var anyActive;
3758
                        var strActive = 'active';
3759
                        var hide = function () {
3760
                            if (!_scrollbarsHandleHovered && !_destroyed) {
3761
                                anyActive = _scrollbarHorizontalHandleElement.hasClass(strActive) || _scrollbarVerticalHandleElement.hasClass(strActive);
3762
                                if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
3763
                                    addClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
3764
                                if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
3765
                                    addClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
3766
                            }
3767
                        };
3768
                        if (_scrollbarsAutoHideDelay > 0 && delayfree !== true)
3769
                            _scrollbarsAutoHideTimeoutId = setTimeout(hide, _scrollbarsAutoHideDelay);
3770
                        else
3771
                            hide();
3772
                    }
3773
                }
3774

3775
                /**
3776
                 * Refreshes the handle length of the given scrollbar.
3777
                 * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
3778
                 */
3779
                function refreshScrollbarHandleLength(isHorizontal) {
3780
                    var handleCSS = {};
3781
                    var scrollbarVars = getScrollbarVars(isHorizontal);
3782
                    var scrollbarVarsInfo = scrollbarVars._info;
3783
                    var digit = 1000000;
3784
                    //get and apply intended handle length
3785
                    var handleRatio = MATH.min(1, _viewportSize[scrollbarVars._w_h] / _contentScrollSizeCache[scrollbarVars._w_h]);
3786
                    handleCSS[scrollbarVars._width_height] = (MATH.floor(handleRatio * 100 * digit) / digit) + '%'; //the last * digit / digit is for flooring to the 4th digit
3787

3788
                    if (!nativeOverlayScrollbarsAreActive())
3789
                        scrollbarVars._handle.css(handleCSS);
3790

3791
                    //measure the handle length to respect min & max length
3792
                    scrollbarVarsInfo._handleLength = scrollbarVars._handle[0]['offset' + scrollbarVars._Width_Height];
3793
                    scrollbarVarsInfo._handleLengthRatio = handleRatio;
3794
                }
3795

3796
                /**
3797
                 * Refreshes the handle offset of the given scrollbar.
3798
                 * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
3799
                 * @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)
3800
                 */
3801
                function refreshScrollbarHandleOffset(isHorizontal, scrollOrTransition) {
3802
                    var transition = type(scrollOrTransition) == TYPES.b;
3803
                    var transitionDuration = 250;
3804
                    var isRTLisHorizontal = _isRTL && isHorizontal;
3805
                    var scrollbarVars = getScrollbarVars(isHorizontal);
3806
                    var scrollbarVarsInfo = scrollbarVars._info;
3807
                    var strTranslateBrace = 'translate(';
3808
                    var strTransform = VENDORS._cssProperty('transform');
3809
                    var strTransition = VENDORS._cssProperty('transition');
3810
                    var nativeScroll = isHorizontal ? _viewportElement[_strScrollLeft]() : _viewportElement[_strScrollTop]();
3811
                    var currentScroll = scrollOrTransition === undefined || transition ? nativeScroll : scrollOrTransition;
3812

3813
                    //measure the handle length to respect min & max length
3814
                    var handleLength = scrollbarVarsInfo._handleLength;
3815
                    var trackLength = scrollbarVars._track[0]['offset' + scrollbarVars._Width_Height];
3816
                    var handleTrackDiff = trackLength - handleLength;
3817
                    var handleCSS = {};
3818
                    var transformOffset;
3819
                    var translateValue;
3820

3821
                    //DONT use the variable '_contentScrollSizeCache[scrollbarVars._w_h]' instead of '_viewportElement[0]['scroll' + scrollbarVars._Width_Height]'
3822
                    // because its a bit behind during the small delay when content size updates
3823
                    //(delay = mutationObserverContentLag, if its 0 then this var could be used)
3824
                    var maxScroll = (_viewportElementNative[_strScroll + scrollbarVars._Width_Height] - _viewportElementNative['client' + scrollbarVars._Width_Height]) * (_rtlScrollBehavior.n && isRTLisHorizontal ? -1 : 1); //* -1 if rtl scroll max is negative
3825
                    var getScrollRatio = function (base) {
3826
                        return isNaN(base / maxScroll) ? 0 : MATH.max(0, MATH.min(1, base / maxScroll));
3827
                    };
3828
                    var getHandleOffset = function (scrollRatio) {
3829
                        var offset = handleTrackDiff * scrollRatio;
3830
                        offset = isNaN(offset) ? 0 : offset;
3831
                        offset = (isRTLisHorizontal && !_rtlScrollBehavior.i) ? (trackLength - handleLength - offset) : offset;
3832
                        offset = MATH.max(0, offset);
3833
                        return offset;
3834
                    };
3835
                    var scrollRatio = getScrollRatio(nativeScroll);
3836
                    var unsnappedScrollRatio = getScrollRatio(currentScroll);
3837
                    var handleOffset = getHandleOffset(unsnappedScrollRatio);
3838
                    var snappedHandleOffset = getHandleOffset(scrollRatio);
3839

3840
                    scrollbarVarsInfo._maxScroll = maxScroll;
3841
                    scrollbarVarsInfo._currentScroll = nativeScroll;
3842
                    scrollbarVarsInfo._currentScrollRatio = scrollRatio;
3843

3844
                    if (_supportTransform) {
3845
                        transformOffset = isRTLisHorizontal ? -(trackLength - handleLength - handleOffset) : handleOffset; //in px
3846
                        //transformOffset = (transformOffset / trackLength * 100) * (trackLength / handleLength); //in %
3847
                        translateValue = isHorizontal ? strTranslateBrace + transformOffset + 'px, 0)' : strTranslateBrace + '0, ' + transformOffset + 'px)';
3848

3849
                        handleCSS[strTransform] = translateValue;
3850

3851
                        //apply or clear up transition
3852
                        if (_supportTransition)
3853
                            handleCSS[strTransition] = transition && MATH.abs(handleOffset - scrollbarVarsInfo._handleOffset) > 1 ? getCSSTransitionString(scrollbarVars._handle) + ', ' + (strTransform + _strSpace + transitionDuration + 'ms') : _strEmpty;
3854
                    }
3855
                    else
3856
                        handleCSS[scrollbarVars._left_top] = handleOffset;
3857

3858

3859
                    //only apply css if offset has changed and overflow exists.
3860
                    if (!nativeOverlayScrollbarsAreActive()) {
3861
                        scrollbarVars._handle.css(handleCSS);
3862

3863
                        //clear up transition
3864
                        if (_supportTransform && _supportTransition && transition) {
3865
                            scrollbarVars._handle.one(_strTransitionEndEvent, function () {
3866
                                if (!_destroyed)
3867
                                    scrollbarVars._handle.css(strTransition, _strEmpty);
3868
                            });
3869
                        }
3870
                    }
3871

3872
                    scrollbarVarsInfo._handleOffset = handleOffset;
3873
                    scrollbarVarsInfo._snappedHandleOffset = snappedHandleOffset;
3874
                    scrollbarVarsInfo._trackLength = trackLength;
3875
                }
3876

3877
                /**
3878
                 * Refreshes the interactivity of the given scrollbar element.
3879
                 * @param isTrack True if the track element is the target, false if the handle element is the target.
3880
                 * @param value True for interactivity false for no interactivity.
3881
                 */
3882
                function refreshScrollbarsInteractive(isTrack, value) {
3883
                    var action = value ? 'removeClass' : 'addClass';
3884
                    var element1 = isTrack ? _scrollbarHorizontalTrackElement : _scrollbarHorizontalHandleElement;
3885
                    var element2 = isTrack ? _scrollbarVerticalTrackElement : _scrollbarVerticalHandleElement;
3886
                    var className = isTrack ? _classNameScrollbarTrackOff : _classNameScrollbarHandleOff;
3887

3888
                    element1[action](className);
3889
                    element2[action](className);
3890
                }
3891

3892
                /**
3893
                 * Returns a object which is used for fast access for specific variables.
3894
                 * @param isHorizontal True if the horizontal scrollbar vars shall be accessed, false if the vertical scrollbar vars shall be accessed.
3895
                 * @returns {{wh: string, WH: string, lt: string, _wh: string, _lt: string, t: *, h: *, c: {}, s: *}}
3896
                 */
3897
                function getScrollbarVars(isHorizontal) {
3898
                    return {
3899
                        _width_height: isHorizontal ? _strWidth : _strHeight,
3900
                        _Width_Height: isHorizontal ? 'Width' : 'Height',
3901
                        _left_top: isHorizontal ? _strLeft : _strTop,
3902
                        _Left_Top: isHorizontal ? 'Left' : 'Top',
3903
                        _x_y: isHorizontal ? _strX : _strY,
3904
                        _X_Y: isHorizontal ? 'X' : 'Y',
3905
                        _w_h: isHorizontal ? 'w' : 'h',
3906
                        _l_t: isHorizontal ? 'l' : 't',
3907
                        _track: isHorizontal ? _scrollbarHorizontalTrackElement : _scrollbarVerticalTrackElement,
3908
                        _handle: isHorizontal ? _scrollbarHorizontalHandleElement : _scrollbarVerticalHandleElement,
3909
                        _scrollbar: isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement,
3910
                        _info: isHorizontal ? _scrollHorizontalInfo : _scrollVerticalInfo
3911
                    };
3912
                }
3913

3914

3915
                //==== Scrollbar Corner ====//
3916

3917
                /**
3918
                 * Builds or destroys the scrollbar corner DOM element.
3919
                 * @param destroy Indicates whether the DOM shall be build or destroyed.
3920
                 */
3921
                function setupScrollbarCornerDOM(destroy) {
3922
                    _scrollbarCornerElement = _scrollbarCornerElement || selectOrGenerateDivByClass(_classNameScrollbarCorner, true);
3923

3924
                    if (!destroy) {
3925
                        if (!_domExists) {
3926
                            _hostElement.append(_scrollbarCornerElement);
3927
                        }
3928
                    }
3929
                    else {
3930
                        if (_domExists && _initialized) {
3931
                            removeClass(_scrollbarCornerElement.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
3932
                        }
3933
                        else {
3934
                            remove(_scrollbarCornerElement);
3935
                        }
3936
                    }
3937
                }
3938

3939
                /**
3940
                 * Initializes all scrollbar corner interactivity events.
3941
                 */
3942
                function setupScrollbarCornerEvents() {
3943
                    var insideIFrame = _windowElementNative.top !== _windowElementNative;
3944
                    var mouseDownPosition = {};
3945
                    var mouseDownSize = {};
3946
                    var mouseDownInvertedScale = {};
3947
                    var reconnectMutationObserver;
3948

3949
                    function documentDragMove(event) {
3950
                        if (onMouseTouchDownContinue(event)) {
3951
                            var pageOffset = getCoordinates(event);
3952
                            var hostElementCSS = {};
3953
                            if (_resizeHorizontal || _resizeBoth)
3954
                                hostElementCSS[_strWidth] = (mouseDownSize.w + (pageOffset.x - mouseDownPosition.x) * mouseDownInvertedScale.x);
3955
                            if (_resizeVertical || _resizeBoth)
3956
                                hostElementCSS[_strHeight] = (mouseDownSize.h + (pageOffset.y - mouseDownPosition.y) * mouseDownInvertedScale.y);
3957
                            _hostElement.css(hostElementCSS);
3958
                            COMPATIBILITY.stpP(event);
3959
                        }
3960
                        else {
3961
                            documentMouseTouchUp(event);
3962
                        }
3963
                    }
3964
                    function documentMouseTouchUp(event) {
3965
                        var eventIsTrusted = event !== undefined;
3966

3967
                        setupResponsiveEventListener(_documentElement,
3968
                            [_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],
3969
                            [documentOnSelectStart, documentDragMove, documentMouseTouchUp],
3970
                            true);
3971

3972
                        removeClass(_bodyElement, _classNameDragging);
3973
                        if (_scrollbarCornerElement.releaseCapture)
3974
                            _scrollbarCornerElement.releaseCapture();
3975

3976
                        if (eventIsTrusted) {
3977
                            if (reconnectMutationObserver)
3978
                                connectMutationObservers();
3979
                            _base.update(_strAuto);
3980
                        }
3981
                        reconnectMutationObserver = false;
3982
                    }
3983
                    function onMouseTouchDownContinue(event) {
3984
                        var originalEvent = event.originalEvent || event;
3985
                        var isTouchEvent = originalEvent.touches !== undefined;
3986
                        return _sleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
3987
                    }
3988
                    function getCoordinates(event) {
3989
                        return _msieVersion && insideIFrame ? { x: event.screenX, y: event.screenY } : COMPATIBILITY.page(event);
3990
                    }
3991

3992
                    addDestroyEventListener(_scrollbarCornerElement, _strMouseTouchDownEvent, function (event) {
3993
                        if (onMouseTouchDownContinue(event) && !_resizeNone) {
3994
                            if (_mutationObserversConnected) {
3995
                                reconnectMutationObserver = true;
3996
                                disconnectMutationObservers();
3997
                            }
3998

3999
                            mouseDownPosition = getCoordinates(event);
4000

4001
                            mouseDownSize.w = _hostElementNative[LEXICON.oW] - (!_isBorderBox ? _paddingX : 0);
4002
                            mouseDownSize.h = _hostElementNative[LEXICON.oH] - (!_isBorderBox ? _paddingY : 0);
4003
                            mouseDownInvertedScale = getHostElementInvertedScale();
4004

4005
                            setupResponsiveEventListener(_documentElement,
4006
                                [_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],
4007
                                [documentOnSelectStart, documentDragMove, documentMouseTouchUp]);
4008

4009
                            addClass(_bodyElement, _classNameDragging);
4010
                            if (_scrollbarCornerElement.setCapture)
4011
                                _scrollbarCornerElement.setCapture();
4012

4013
                            COMPATIBILITY.prvD(event);
4014
                            COMPATIBILITY.stpP(event);
4015
                        }
4016
                    });
4017
                }
4018

4019

4020
                //==== Utils ====//
4021

4022
                /**
4023
                 * Calls the callback with the given name. The Context of this callback is always _base (this).
4024
                 * @param name The name of the target which shall be called.
4025
                 * @param args The args with which the callback shall be called.
4026
                 * @param dependent Boolean which decides whether the callback shall be fired, undefined is like a "true" value.
4027
                 */
4028
                function dispatchCallback(name, args, dependent) {
4029
                    if (dependent === false)
4030
                        return;
4031
                    if (_initialized) {
4032
                        var callback = _currentPreparedOptions.callbacks[name];
4033
                        var extensionOnName = name;
4034
                        var ext;
4035

4036
                        if (extensionOnName.substr(0, 2) === 'on')
4037
                            extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3);
4038

4039
                        if (type(callback) == TYPES.f)
4040
                            callback.call(_base, args);
4041

4042
                        each(_extensions, function () {
4043
                            ext = this;
4044
                            if (type(ext.on) == TYPES.f)
4045
                                ext.on(extensionOnName, args);
4046
                        });
4047
                    }
4048
                    else if (!_destroyed)
4049
                        _callbacksInitQeueue.push({ n: name, a: args });
4050
                }
4051

4052
                /**
4053
                 * Sets the "top, right, bottom, left" properties, with a given prefix, of the given css object.
4054
                 * @param targetCSSObject The css object to which the values shall be applied.
4055
                 * @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
4056
                 * @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].
4057
                 * If this argument is undefined the value '' (empty string) will be applied to all properties.
4058
                 */
4059
                function setTopRightBottomLeft(targetCSSObject, prefix, values) {
4060
                    prefix = prefix || _strEmpty;
4061
                    values = values || [_strEmpty, _strEmpty, _strEmpty, _strEmpty];
4062

4063
                    targetCSSObject[prefix + _strTop] = values[0];
4064
                    targetCSSObject[prefix + _strRight] = values[1];
4065
                    targetCSSObject[prefix + _strBottom] = values[2];
4066
                    targetCSSObject[prefix + _strLeft] = values[3];
4067
                }
4068

4069
                /**
4070
                 * Gets the "top, right, bottom, left" CSS properties of the CSS property with the given prefix from the host element.
4071
                 * @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
4072
                 * @param suffix The suffix of the "top, right, bottom, left" css properties. (example: 'border-' is a valid prefix with '-width' is a valid suffix)
4073
                 * @param zeroX True if the x axis shall be 0.
4074
                 * @param zeroY True if the y axis shall be 0.
4075
                 * @returns {{}} The object which contains the numbers of the read CSS properties.
4076
                 */
4077
                function getTopRightBottomLeftHost(prefix, suffix, zeroX, zeroY) {
4078
                    suffix = suffix || _strEmpty;
4079
                    prefix = prefix || _strEmpty;
4080
                    return {
4081
                        t: zeroY ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strTop + suffix)),
4082
                        r: zeroX ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strRight + suffix)),
4083
                        b: zeroY ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strBottom + suffix)),
4084
                        l: zeroX ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strLeft + suffix))
4085
                    };
4086
                }
4087

4088
                /**
4089
                 * Returns the computed CSS transition string from the given element.
4090
                 * @param element The element from which the transition string shall be returned.
4091
                 * @returns {string} The CSS transition string from the given element.
4092
                 */
4093
                function getCSSTransitionString(element) {
4094
                    var transitionStr = VENDORS._cssProperty('transition');
4095
                    var assembledValue = element.css(transitionStr);
4096
                    if (assembledValue)
4097
                        return assembledValue;
4098
                    var regExpString = '\\s*(' + '([^,(]+(\\(.+?\\))?)+' + ')[\\s,]*';
4099
                    var regExpMain = new RegExp(regExpString);
4100
                    var regExpValidate = new RegExp('^(' + regExpString + ')+$');
4101
                    var properties = 'property duration timing-function delay'.split(' ');
4102
                    var result = [];
4103
                    var strResult;
4104
                    var valueArray;
4105
                    var i = 0;
4106
                    var j;
4107
                    var splitCssStyleByComma = function (str) {
4108
                        strResult = [];
4109
                        if (!str.match(regExpValidate))
4110
                            return str;
4111
                        while (str.match(regExpMain)) {
4112
                            strResult.push(RegExp.$1);
4113
                            str = str.replace(regExpMain, _strEmpty);
4114
                        }
4115

4116
                        return strResult;
4117
                    };
4118
                    for (; i < properties[LEXICON.l]; i++) {
4119
                        valueArray = splitCssStyleByComma(element.css(transitionStr + '-' + properties[i]));
4120
                        for (j = 0; j < valueArray[LEXICON.l]; j++)
4121
                            result[j] = (result[j] ? result[j] + _strSpace : _strEmpty) + valueArray[j];
4122
                    }
4123
                    return result.join(', ');
4124
                }
4125

4126
                /**
4127
                 * Generates a Regular Expression which matches with a string which starts with 'os-host'.
4128
                 * @param {boolean} withCurrClassNameOption The Regular Expression also matches if the string is the current ClassName option (multiple values splitted by space possible).
4129
                 * @param {boolean} withOldClassNameOption The Regular Expression also matches if the string is the old ClassName option (multiple values splitted by space possible).
4130
                 */
4131
                function createHostClassNameRegExp(withCurrClassNameOption, withOldClassNameOption) {
4132
                    var i;
4133
                    var split;
4134
                    var appendix;
4135
                    var appendClasses = function (classes, condition) {
4136
                        appendix = '';
4137
                        if (condition && typeof classes == TYPES.s) {
4138
                            split = classes.split(_strSpace);
4139
                            for (i = 0; i < split[LEXICON.l]; i++)
4140
                                appendix += '|' + split[i] + '$';
4141
                            // split[i].replace(/[.*+?^${}()|[\]\\]/g, '\\$&') for escaping regex characters
4142
                        }
4143
                        return appendix;
4144
                    };
4145

4146
                    return new RegExp(
4147
                        '(^' + _classNameHostElement + '([-_].+|)$)' +
4148
                        appendClasses(_classNameCache, withCurrClassNameOption) +
4149
                        appendClasses(_oldClassName, withOldClassNameOption), 'g');
4150
                }
4151

4152
                /**
4153
                 * Calculates the host-elements inverted scale. (invertedScale = 1 / scale)
4154
                 * @returns {{x: number, y: number}} The scale of the host-element.
4155
                 */
4156
                function getHostElementInvertedScale() {
4157
                    var rect = _paddingElementNative[LEXICON.bCR]();
4158
                    return {
4159
                        x: _supportTransform ? 1 / (MATH.round(rect.width) / _paddingElementNative[LEXICON.oW]) || 1 : 1,
4160
                        y: _supportTransform ? 1 / (MATH.round(rect.height) / _paddingElementNative[LEXICON.oH]) || 1 : 1
4161
                    };
4162
                }
4163

4164
                /**
4165
                 * Checks whether the given object is a HTMLElement.
4166
                 * @param o The object which shall be checked.
4167
                 * @returns {boolean} True the given object is a HTMLElement, false otherwise.
4168
                 */
4169
                function isHTMLElement(o) {
4170
                    var strOwnerDocument = 'ownerDocument';
4171
                    var strHTMLElement = 'HTMLElement';
4172
                    var wnd = o && o[strOwnerDocument] ? (o[strOwnerDocument].parentWindow || window) : window;
4173
                    return (
4174
                        typeof wnd[strHTMLElement] == TYPES.o ? o instanceof wnd[strHTMLElement] : //DOM2
4175
                            o && typeof o == TYPES.o && o !== null && o.nodeType === 1 && typeof o.nodeName == TYPES.s
4176
                    );
4177
                }
4178

4179
                /**
4180
                 * Compares 2 arrays and returns the differences between them as a array.
4181
                 * @param a1 The first array which shall be compared.
4182
                 * @param a2 The second array which shall be compared.
4183
                 * @returns {Array} The differences between the two arrays.
4184
                 */
4185
                function getArrayDifferences(a1, a2) {
4186
                    var a = [];
4187
                    var diff = [];
4188
                    var i;
4189
                    var k;
4190
                    for (i = 0; i < a1.length; i++)
4191
                        a[a1[i]] = true;
4192
                    for (i = 0; i < a2.length; i++) {
4193
                        if (a[a2[i]])
4194
                            delete a[a2[i]];
4195
                        else
4196
                            a[a2[i]] = true;
4197
                    }
4198
                    for (k in a)
4199
                        diff.push(k);
4200
                    return diff;
4201
                }
4202

4203
                /**
4204
                 * Returns Zero or the number to which the value can be parsed.
4205
                 * @param value The value which shall be parsed.
4206
                 * @param toFloat Indicates whether the number shall be parsed to a float.
4207
                 */
4208
                function parseToZeroOrNumber(value, toFloat) {
4209
                    var num = toFloat ? parseFloat(value) : parseInt(value, 10);
4210
                    return isNaN(num) ? 0 : num;
4211
                }
4212

4213
                /**
4214
                 * Gets several information of the textarea and returns them as a object or undefined if the browser doesn't support it.
4215
                 * @returns {{cursorRow: Number, cursorCol, rows: Number, cols: number, wRow: number, pos: number, max : number}} or undefined if not supported.
4216
                 */
4217
                function getTextareaInfo() {
4218
                    //read needed values
4219
                    var textareaCursorPosition = _targetElementNative.selectionStart;
4220
                    if (textareaCursorPosition === undefined)
4221
                        return;
4222

4223
                    var textareaValue = _targetElement.val();
4224
                    var textareaLength = textareaValue[LEXICON.l];
4225
                    var textareaRowSplit = textareaValue.split('\n');
4226
                    var textareaLastRow = textareaRowSplit[LEXICON.l];
4227
                    var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split('\n');
4228
                    var widestRow = 0;
4229
                    var textareaLastCol = 0;
4230
                    var cursorRow = textareaCurrentCursorRowSplit[LEXICON.l];
4231
                    var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[LEXICON.l] - 1][LEXICON.l];
4232
                    var rowCols;
4233
                    var i;
4234

4235
                    //get widest Row and the last column of the textarea
4236
                    for (i = 0; i < textareaRowSplit[LEXICON.l]; i++) {
4237
                        rowCols = textareaRowSplit[i][LEXICON.l];
4238
                        if (rowCols > textareaLastCol) {
4239
                            widestRow = i + 1;
4240
                            textareaLastCol = rowCols;
4241
                        }
4242
                    }
4243

4244
                    return {
4245
                        _cursorRow: cursorRow, //cursorRow
4246
                        _cursorColumn: cursorCol, //cursorCol
4247
                        _rows: textareaLastRow, //rows
4248
                        _columns: textareaLastCol, //cols
4249
                        _widestRow: widestRow, //wRow
4250
                        _cursorPosition: textareaCursorPosition, //pos
4251
                        _cursorMax: textareaLength //max
4252
                    };
4253
                }
4254

4255
                /**
4256
                 * Determines whether native overlay scrollbars are active.
4257
                 * @returns {boolean} True if native overlay scrollbars are active, false otherwise.
4258
                 */
4259
                function nativeOverlayScrollbarsAreActive() {
4260
                    return (_ignoreOverlayScrollbarHidingCache && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y));
4261
                }
4262

4263
                /**
4264
                 * Gets the element which is used to measure the content size.
4265
                 * @returns {*} TextareaCover if target element is textarea else the ContentElement.
4266
                 */
4267
                function getContentMeasureElement() {
4268
                    return _isTextarea ? _textareaCoverElement[0] : _contentElementNative;
4269
                }
4270

4271
                /**
4272
                 * Generates a string which represents a HTML div with the given classes or attributes.
4273
                 * @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".)
4274
                 * @param content The content of the div as string.
4275
                 * @returns {string} The concated string which represents a HTML div and its content.
4276
                 */
4277
                function generateDiv(classesOrAttrs, content) {
4278
                    return '<div ' + (classesOrAttrs ? type(classesOrAttrs) == TYPES.s ?
4279
                        'class="' + classesOrAttrs + '"' :
4280
                        (function () {
4281
                            var key;
4282
                            var attrs = _strEmpty;
4283
                            if (FRAMEWORK.isPlainObject(classesOrAttrs)) {
4284
                                for (key in classesOrAttrs)
4285
                                    attrs += (key === 'c' ? 'class' : key) + '="' + classesOrAttrs[key] + '" ';
4286
                            }
4287
                            return attrs;
4288
                        })() :
4289
                        _strEmpty) +
4290
                        '>' +
4291
                        (content || _strEmpty) +
4292
                        '</div>';
4293
                }
4294

4295
                /**
4296
                 * Selects or generates a div with the given class attribute.
4297
                 * @param className The class names (divided by spaces) of the div which shall be selected or generated.
4298
                 * @param selectParentOrOnlyChildren The parent element from which of the element shall be selected. (if undefined or boolean its hostElement)
4299
                 * If its a boolean it decides whether only the children of the host element shall be selected.
4300
                 * @returns {*} The generated or selected element.
4301
                 */
4302
                function selectOrGenerateDivByClass(className, selectParentOrOnlyChildren) {
4303
                    var onlyChildren = type(selectParentOrOnlyChildren) == TYPES.b;
4304
                    var selectParent = onlyChildren ? _hostElement : (selectParentOrOnlyChildren || _hostElement);
4305

4306
                    return (_domExists && !selectParent[LEXICON.l])
4307
                        ? null
4308
                        : _domExists
4309
                            ? selectParent[onlyChildren ? 'children' : 'find'](_strDot + className.replace(/\s/g, _strDot)).eq(0)
4310
                            : FRAMEWORK(generateDiv(className))
4311
                }
4312

4313
                /**
4314
                 * Gets the value of the given property from the given object.
4315
                 * @param obj The object from which the property value shall be got.
4316
                 * @param path The property of which the value shall be got.
4317
                 * @returns {*} Returns the value of the searched property or undefined of the property wasn't found.
4318
                 */
4319
                function getObjectPropVal(obj, path) {
4320
                    var splits = path.split(_strDot);
4321
                    var i = 0;
4322
                    var val;
4323
                    for (; i < splits.length; i++) {
4324
                        if (!obj[LEXICON.hOP](splits[i]))
4325
                            return;
4326
                        val = obj[splits[i]];
4327
                        if (i < splits.length && type(val) == TYPES.o)
4328
                            obj = val;
4329
                    }
4330
                    return val;
4331
                }
4332

4333
                /**
4334
                 * Sets the value of the given property from the given object.
4335
                 * @param obj The object from which the property value shall be set.
4336
                 * @param path The property of which the value shall be set.
4337
                 * @param val The value of the property which shall be set.
4338
                 */
4339
                function setObjectPropVal(obj, path, val) {
4340
                    var splits = path.split(_strDot);
4341
                    var splitsLength = splits.length;
4342
                    var i = 0;
4343
                    var extendObj = {};
4344
                    var extendObjRoot = extendObj;
4345
                    for (; i < splitsLength; i++)
4346
                        extendObj = extendObj[splits[i]] = i + 1 < splitsLength ? {} : val;
4347
                    FRAMEWORK.extend(obj, extendObjRoot, true);
4348
                }
4349

4350
                /**	
4351
                 * Runs a action for each selector inside the updateOnLoad option.	
4352
                 * @param {Function} action The action for each updateOnLoad selector, the arguments the function takes is the index and the value (the selector).	
4353
                 */
4354
                function eachUpdateOnLoad(action) {
4355
                    var updateOnLoad = _currentPreparedOptions.updateOnLoad;
4356
                    updateOnLoad = type(updateOnLoad) == TYPES.s ? updateOnLoad.split(_strSpace) : updateOnLoad;
4357

4358
                    if (COMPATIBILITY.isA(updateOnLoad) && !_destroyed) {
4359
                        each(updateOnLoad, action);
4360
                    }
4361
                }
4362

4363

4364
                //==== Utils Cache ====//
4365

4366
                /**
4367
                 * Compares two values or objects and returns true if they aren't equal.
4368
                 * @param current The first value or object which shall be compared.
4369
                 * @param cache The second value or object which shall be compared.
4370
                 * @param force If true the returned value is always true.
4371
                 * @returns {boolean} True if both values or objects aren't equal or force is true, false otherwise.
4372
                 */
4373
                function checkCache(current, cache, force) {
4374
                    if (force)
4375
                        return force;
4376
                    if (type(current) == TYPES.o && type(cache) == TYPES.o) {
4377
                        for (var prop in current) {
4378
                            if (prop !== 'c') {
4379
                                if (current[LEXICON.hOP](prop) && cache[LEXICON.hOP](prop)) {
4380
                                    if (checkCache(current[prop], cache[prop]))
4381
                                        return true;
4382
                                }
4383
                                else {
4384
                                    return true;
4385
                                }
4386
                            }
4387
                        }
4388
                    }
4389
                    else {
4390
                        return current !== cache;
4391
                    }
4392
                    return false;
4393
                }
4394

4395

4396
                //==== Shortcuts ====//
4397

4398
                /**
4399
                 * jQuery extend method shortcut with a appended "true" as first argument.
4400
                 */
4401
                function extendDeep() {
4402
                    return FRAMEWORK.extend.apply(this, [true].concat([].slice.call(arguments)));
4403
                }
4404

4405
                /**
4406
                 * jQuery addClass method shortcut.
4407
                 */
4408
                function addClass(el, classes) {
4409
                    return _frameworkProto.addClass.call(el, classes);
4410
                }
4411

4412
                /**
4413
                 * jQuery removeClass method shortcut.
4414
                 */
4415
                function removeClass(el, classes) {
4416
                    return _frameworkProto.removeClass.call(el, classes);
4417
                }
4418

4419
                /**
4420
                 * Adds or removes the given classes dependent on the boolean value. True for add, false for remove.
4421
                 */
4422
                function addRemoveClass(el, classes, doAdd) {
4423
                    return doAdd ? addClass(el, classes) : removeClass(el, classes);
4424
                }
4425

4426
                /**
4427
                 * jQuery remove method shortcut.
4428
                 */
4429
                function remove(el) {
4430
                    return _frameworkProto.remove.call(el);
4431
                }
4432

4433
                /**
4434
                 * Finds the first child element with the given selector of the given element.
4435
                 * @param el The root element from which the selector shall be valid.
4436
                 * @param selector The selector of the searched element.
4437
                 * @returns {*} The first element which is a child of the given element and matches the givens selector.
4438
                 */
4439
                function findFirst(el, selector) {
4440
                    return _frameworkProto.find.call(el, selector).eq(0);
4441
                }
4442

4443

4444
                //==== API ====//
4445

4446
                /**
4447
                 * 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.
4448
                 * This behavior can be reset by calling the update method.
4449
                 */
4450
                _base.sleep = function () {
4451
                    _sleeping = true;
4452
                };
4453

4454
                /**
4455
                 * Updates the plugin and DOM to the current options.
4456
                 * This method should only be called if a update is 100% required.
4457
                 * @param force True if every property shall be updated and the cache shall be ignored.
4458
                 * !INTERNAL USAGE! : force can be a string "auto", "sync" or "zoom" too
4459
                 * 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.
4460
                 * 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.
4461
                 * if "zoom" then a update takes place where it's assumed that content and host size changed
4462
                 * @returns {boolean|undefined} 
4463
                 * If force is "sync" then a boolean is returned which indicates whether a update was needed due to pending changes.
4464
                 * If force is "auto" then a boolean is returned whether a update was needed due to attribute or size changes.
4465
                 * undefined otherwise.
4466
                 */
4467
                _base.update = function (force) {
4468
                    if (_destroyed)
4469
                        return;
4470

4471
                    var attrsChanged;
4472
                    var contentSizeC;
4473
                    var isString = type(force) == TYPES.s;
4474
                    var doUpdateAuto;
4475
                    var mutHost;
4476
                    var mutContent;
4477

4478
                    if (isString) {
4479
                        if (force === _strAuto) {
4480
                            attrsChanged = meaningfulAttrsChanged();
4481
                            contentSizeC = updateAutoContentSizeChanged();
4482
                            doUpdateAuto = attrsChanged || contentSizeC;
4483
                            if (doUpdateAuto) {
4484
                                update({
4485
                                    _contentSizeChanged: contentSizeC,
4486
                                    _changedOptions: _initialized ? undefined : _currentPreparedOptions
4487
                                });
4488
                            }
4489
                        }
4490
                        else if (force === _strSync) {
4491
                            if (_mutationObserversConnected) {
4492
                                mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords());
4493
                                mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords());
4494
                            }
4495
                            else {
4496
                                mutHost = _base.update(_strAuto);
4497
                            }
4498
                        }
4499
                        else if (force === 'zoom') {
4500
                            update({
4501
                                _hostSizeChanged: true,
4502
                                _contentSizeChanged: true
4503
                            });
4504
                        }
4505
                    }
4506
                    else {
4507
                        force = _sleeping || force;
4508
                        _sleeping = false;
4509
                        if (!_base.update(_strSync) || force)
4510
                            update({ _force: force });
4511
                    }
4512

4513
                    updateElementsOnLoad();
4514

4515
                    return doUpdateAuto || mutHost || mutContent;
4516
                };
4517

4518
                /**
4519
                 Gets or sets the current options. The update method will be called automatically if new options were set.
4520
                 * @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.
4521
                 * @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.
4522
                 * @returns {*}
4523
                 */
4524
                _base.options = function (newOptions, value) {
4525
                    var option = {};
4526
                    var changedOps;
4527

4528
                    //return current options if newOptions are undefined or empty
4529
                    if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) {
4530
                        if (type(newOptions) == TYPES.s) {
4531
                            if (arguments.length > 1) {
4532
                                setObjectPropVal(option, newOptions, value);
4533
                                changedOps = setOptions(option);
4534
                            }
4535
                            else
4536
                                return getObjectPropVal(_currentOptions, newOptions);
4537
                        }
4538
                        else
4539
                            return _currentOptions;
4540
                    }
4541
                    else {
4542
                        changedOps = setOptions(newOptions);
4543
                    }
4544

4545
                    if (!FRAMEWORK.isEmptyObject(changedOps)) {
4546
                        update({ _changedOptions: changedOps });
4547
                    }
4548
                };
4549

4550
                /**
4551
                 * Restore the DOM, disconnects all observers, remove all resize observers and put the instance to sleep.
4552
                 */
4553
                _base.destroy = function () {
4554
                    if (_destroyed)
4555
                        return;
4556

4557
                    //remove this instance from auto update loop
4558
                    autoUpdateLoop.remove(_base);
4559

4560
                    //disconnect all mutation observers
4561
                    disconnectMutationObservers();
4562

4563
                    //remove all resize observers
4564
                    setupResizeObserver(_sizeObserverElement);
4565
                    setupResizeObserver(_sizeAutoObserverElement);
4566

4567
                    //remove all extensions
4568
                    for (var extName in _extensions)
4569
                        _base.removeExt(extName);
4570

4571
                    //remove all 'destroy' events
4572
                    while (_destroyEvents[LEXICON.l] > 0)
4573
                        _destroyEvents.pop()();
4574

4575
                    //remove all events from host element
4576
                    setupHostMouseTouchEvents(true);
4577

4578
                    //remove all helper / detection elements
4579
                    if (_contentGlueElement)
4580
                        remove(_contentGlueElement);
4581
                    if (_contentArrangeElement)
4582
                        remove(_contentArrangeElement);
4583
                    if (_sizeAutoObserverAdded)
4584
                        remove(_sizeAutoObserverElement);
4585

4586
                    //remove all generated DOM
4587
                    setupScrollbarsDOM(true);
4588
                    setupScrollbarCornerDOM(true);
4589
                    setupStructureDOM(true);
4590

4591
                    //remove all generated image load events
4592
                    for (var i = 0; i < _updateOnLoadElms[LEXICON.l]; i++)
4593
                        FRAMEWORK(_updateOnLoadElms[i]).off(_updateOnLoadEventName, updateOnLoadCallback);
4594
                    _updateOnLoadElms = undefined;
4595

4596
                    _destroyed = true;
4597
                    _sleeping = true;
4598

4599
                    //remove this instance from the instances list
4600
                    INSTANCES(pluginTargetElement, 0);
4601
                    dispatchCallback('onDestroyed');
4602

4603
                    //remove all properties and methods
4604
                    //for (var property in _base)
4605
                    //    delete _base[property];
4606
                    //_base = undefined;
4607
                };
4608

4609
                /**
4610
                 * Scrolls to a given position or element.
4611
                 * @param coordinates
4612
                 * 1. Can be "coordinates" which looks like:
4613
                 *    { x : ?, y : ? } OR          Object with x and y properties
4614
                 *    { left : ?, top : ? } OR     Object with left and top properties
4615
                 *    { l : ?, t : ? } OR          Object with l and t properties
4616
                 *    [ ?, ? ] OR                  Array where the first two element are the coordinates (first is x, second is y)
4617
                 *    ?                            A single value which stays for both axis
4618
                 *    A value can be a number, a string or a calculation.
4619
                 *
4620
                 *    Operators:
4621
                 *    [NONE]  The current scroll will be overwritten by the value.
4622
                 *    '+='    The value will be added to the current scroll offset
4623
                 *    '-='    The value will be subtracted from the current scroll offset
4624
                 *    '*='    The current scroll wil be multiplicated by the value.
4625
                 *    '/='    The current scroll wil be divided by the value.
4626
                 *
4627
                 *    Units:
4628
                 *    [NONE]  The value is the final scroll amount.                   final = (value * 1)
4629
                 *    'px'    Same as none
4630
                 *    '%'     The value is dependent on the current scroll value.     final = ((currentScrollValue / 100) * value)
4631
                 *    'vw'    The value is multiplicated by the viewport width.       final = (value * viewportWidth)
4632
                 *    'vh'    The value is multiplicated by the viewport height.      final = (value * viewportHeight)
4633
                 *
4634
                 *    example final values:
4635
                 *    200, '200px', '50%', '1vw', '1vh', '+=200', '/=1vw', '*=2px', '-=5vh', '+=33%', '+= 50% - 2px', '-= 1vw - 50%'
4636
                 *
4637
                 * 2. Can be a HTML or jQuery element:
4638
                 *    The final scroll offset is the offset (without margin) of the given HTML / jQuery element.
4639
                 *
4640
                 * 3. Can be a object with a HTML or jQuery element with additional settings:
4641
                 *    {
4642
                 *      el : [HTMLElement, jQuery element],             MUST be specified, else this object isn't valid.
4643
                 *      scroll : [string, array, object],               Default value is 'always'.
4644
                 *      block : [string, array, object],                Default value is 'begin'.
4645
                 *      margin : [number, boolean, array, object]       Default value is false.
4646
                 *    }
4647
                 *
4648
                 *    Possible scroll settings are:
4649
                 *    'always'      Scrolls always.
4650
                 *    'ifneeded'    Scrolls only if the element isnt fully in view.
4651
                 *    'never'       Scrolls never.
4652
                 *
4653
                 *    Possible block settings are:
4654
                 *    'begin'   Both axis shall be docked to the "begin" edge. - The element will be docked to the top and left edge of the viewport.
4655
                 *    '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.)
4656
                 *    'center'  Both axis shall be docked to "center". - The element will be centered in the viewport.
4657
                 *    'nearest' The element will be docked to the nearest edge(s).
4658
                 *
4659
                 *    Possible margin settings are: -- The actual margin of the element wont be affect, this option affects only the final scroll offset.
4660
                 *    [BOOLEAN]                                         If true the css margin of the element will be used, if false no margin will be used.
4661
                 *    [NUMBER]                                          The margin will be used for all edges.
4662
                 *
4663
                 * @param duration The duration of the scroll animation, OR a jQuery animation configuration object.
4664
                 * @param easing The animation easing.
4665
                 * @param complete The animation complete callback.
4666
                 * @returns {{
4667
                 *   position: {x: number, y: number},
4668
                 *   ratio: {x: number, y: number},
4669
                 *   max: {x: number, y: number},
4670
                 *   handleOffset: {x: number, y: number},
4671
                 *   handleLength: {x: number, y: number},
4672
                 *   handleLengthRatio: {x: number, y: number}, t
4673
                 *   rackLength: {x: number, y: number},
4674
                 *   isRTL: boolean,
4675
                 *   isRTLNormalized: boolean
4676
                 *  }}
4677
                 */
4678
                _base.scroll = function (coordinates, duration, easing, complete) {
4679
                    if (arguments.length === 0 || coordinates === undefined) {
4680
                        var infoX = _scrollHorizontalInfo;
4681
                        var infoY = _scrollVerticalInfo;
4682
                        var normalizeInvert = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.i;
4683
                        var normalizeNegate = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.n;
4684
                        var scrollX = infoX._currentScroll;
4685
                        var scrollXRatio = infoX._currentScrollRatio;
4686
                        var maxScrollX = infoX._maxScroll;
4687
                        scrollXRatio = normalizeInvert ? 1 - scrollXRatio : scrollXRatio;
4688
                        scrollX = normalizeInvert ? maxScrollX - scrollX : scrollX;
4689
                        scrollX *= normalizeNegate ? -1 : 1;
4690
                        maxScrollX *= normalizeNegate ? -1 : 1;
4691

4692
                        return {
4693
                            position: {
4694
                                x: scrollX,
4695
                                y: infoY._currentScroll
4696
                            },
4697
                            ratio: {
4698
                                x: scrollXRatio,
4699
                                y: infoY._currentScrollRatio
4700
                            },
4701
                            max: {
4702
                                x: maxScrollX,
4703
                                y: infoY._maxScroll
4704
                            },
4705
                            handleOffset: {
4706
                                x: infoX._handleOffset,
4707
                                y: infoY._handleOffset
4708
                            },
4709
                            handleLength: {
4710
                                x: infoX._handleLength,
4711
                                y: infoY._handleLength
4712
                            },
4713
                            handleLengthRatio: {
4714
                                x: infoX._handleLengthRatio,
4715
                                y: infoY._handleLengthRatio
4716
                            },
4717
                            trackLength: {
4718
                                x: infoX._trackLength,
4719
                                y: infoY._trackLength
4720
                            },
4721
                            snappedHandleOffset: {
4722
                                x: infoX._snappedHandleOffset,
4723
                                y: infoY._snappedHandleOffset
4724
                            },
4725
                            isRTL: _isRTL,
4726
                            isRTLNormalized: _normalizeRTLCache
4727
                        };
4728
                    }
4729

4730
                    _base.update(_strSync);
4731

4732
                    var normalizeRTL = _normalizeRTLCache;
4733
                    var coordinatesXAxisProps = [_strX, _strLeft, 'l'];
4734
                    var coordinatesYAxisProps = [_strY, _strTop, 't'];
4735
                    var coordinatesOperators = ['+=', '-=', '*=', '/='];
4736
                    var durationIsObject = type(duration) == TYPES.o;
4737
                    var completeCallback = durationIsObject ? duration.complete : complete;
4738
                    var i;
4739
                    var finalScroll = {};
4740
                    var specialEasing = {};
4741
                    var doScrollLeft;
4742
                    var doScrollTop;
4743
                    var animationOptions;
4744
                    var strEnd = 'end';
4745
                    var strBegin = 'begin';
4746
                    var strCenter = 'center';
4747
                    var strNearest = 'nearest';
4748
                    var strAlways = 'always';
4749
                    var strNever = 'never';
4750
                    var strIfNeeded = 'ifneeded';
4751
                    var strLength = LEXICON.l;
4752
                    var settingsAxis;
4753
                    var settingsScroll;
4754
                    var settingsBlock;
4755
                    var settingsMargin;
4756
                    var finalElement;
4757
                    var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx'];
4758
                    var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest];
4759
                    var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded];
4760
                    var coordinatesIsElementObj = coordinates[LEXICON.hOP]('el');
4761
                    var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates;
4762
                    var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false;
4763
                    var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement);
4764
                    var updateScrollbarInfos = function () {
4765
                        if (doScrollLeft)
4766
                            refreshScrollbarHandleOffset(true);
4767
                        if (doScrollTop)
4768
                            refreshScrollbarHandleOffset(false);
4769
                    };
4770
                    var proxyCompleteCallback = type(completeCallback) != TYPES.f ? undefined : function () {
4771
                        updateScrollbarInfos();
4772
                        completeCallback();
4773
                    };
4774
                    function checkSettingsStringValue(currValue, allowedValues) {
4775
                        for (i = 0; i < allowedValues[strLength]; i++) {
4776
                            if (currValue === allowedValues[i])
4777
                                return true;
4778
                        }
4779
                        return false;
4780
                    }
4781
                    function getRawScroll(isX, coordinates) {
4782
                        var coordinateProps = isX ? coordinatesXAxisProps : coordinatesYAxisProps;
4783
                        coordinates = type(coordinates) == TYPES.s || type(coordinates) == TYPES.n ? [coordinates, coordinates] : coordinates;
4784

4785
                        if (COMPATIBILITY.isA(coordinates))
4786
                            return isX ? coordinates[0] : coordinates[1];
4787
                        else if (type(coordinates) == TYPES.o) {
4788
                            //decides RTL normalization "hack" with .n
4789
                            //normalizeRTL = type(coordinates.n) == TYPES.b ? coordinates.n : normalizeRTL; 
4790
                            for (i = 0; i < coordinateProps[strLength]; i++)
4791
                                if (coordinateProps[i] in coordinates)
4792
                                    return coordinates[coordinateProps[i]];
4793
                        }
4794
                    }
4795
                    function getFinalScroll(isX, rawScroll) {
4796
                        var isString = type(rawScroll) == TYPES.s;
4797
                        var operator;
4798
                        var amount;
4799
                        var scrollInfo = isX ? _scrollHorizontalInfo : _scrollVerticalInfo;
4800
                        var currScroll = scrollInfo._currentScroll;
4801
                        var maxScroll = scrollInfo._maxScroll;
4802
                        var mult = ' * ';
4803
                        var finalValue;
4804
                        var isRTLisX = _isRTL && isX;
4805
                        var normalizeShortcuts = isRTLisX && _rtlScrollBehavior.n && !normalizeRTL;
4806
                        var strReplace = 'replace';
4807
                        var evalFunc = eval;
4808
                        var possibleOperator;
4809
                        if (isString) {
4810
                            //check operator
4811
                            if (rawScroll[strLength] > 2) {
4812
                                possibleOperator = rawScroll.substr(0, 2);
4813
                                if (inArray(possibleOperator, coordinatesOperators) > -1)
4814
                                    operator = possibleOperator;
4815
                            }
4816

4817
                            //calculate units and shortcuts
4818
                            rawScroll = operator ? rawScroll.substr(2) : rawScroll;
4819
                            rawScroll = rawScroll
4820
                            [strReplace](/min/g, 0) //'min' = 0%
4821
                            [strReplace](/</g, 0)   //'<'   = 0%
4822
                            [strReplace](/max/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent)    //'max' = 100%
4823
                            [strReplace](/>/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent)      //'>'   = 100%
4824
                            [strReplace](/px/g, _strEmpty)
4825
                            [strReplace](/%/g, mult + (maxScroll * (isRTLisX && _rtlScrollBehavior.n ? -1 : 1) / 100.0))
4826
                            [strReplace](/vw/g, mult + _viewportSize.w)
4827
                            [strReplace](/vh/g, mult + _viewportSize.h);
4828
                            amount = parseToZeroOrNumber(isNaN(rawScroll) ? parseToZeroOrNumber(evalFunc(rawScroll), true).toFixed() : rawScroll);
4829
                        }
4830
                        else {
4831
                            amount = rawScroll;
4832
                        }
4833

4834
                        if (amount !== undefined && !isNaN(amount) && type(amount) == TYPES.n) {
4835
                            var normalizeIsRTLisX = normalizeRTL && isRTLisX;
4836
                            var operatorCurrScroll = currScroll * (normalizeIsRTLisX && _rtlScrollBehavior.n ? -1 : 1);
4837
                            var invert = normalizeIsRTLisX && _rtlScrollBehavior.i;
4838
                            var negate = normalizeIsRTLisX && _rtlScrollBehavior.n;
4839
                            operatorCurrScroll = invert ? (maxScroll - operatorCurrScroll) : operatorCurrScroll;
4840
                            switch (operator) {
4841
                                case '+=':
4842
                                    finalValue = operatorCurrScroll + amount;
4843
                                    break;
4844
                                case '-=':
4845
                                    finalValue = operatorCurrScroll - amount;
4846
                                    break;
4847
                                case '*=':
4848
                                    finalValue = operatorCurrScroll * amount;
4849
                                    break;
4850
                                case '/=':
4851
                                    finalValue = operatorCurrScroll / amount;
4852
                                    break;
4853
                                default:
4854
                                    finalValue = amount;
4855
                                    break;
4856
                            }
4857
                            finalValue = invert ? maxScroll - finalValue : finalValue;
4858
                            finalValue *= negate ? -1 : 1;
4859
                            finalValue = isRTLisX && _rtlScrollBehavior.n ? MATH.min(0, MATH.max(maxScroll, finalValue)) : MATH.max(0, MATH.min(maxScroll, finalValue));
4860
                        }
4861
                        return finalValue === currScroll ? undefined : finalValue;
4862
                    }
4863
                    function getPerAxisValue(value, valueInternalType, defaultValue, allowedValues) {
4864
                        var resultDefault = [defaultValue, defaultValue];
4865
                        var valueType = type(value);
4866
                        var valueArrLength;
4867
                        var valueArrItem;
4868

4869
                        //value can be [ string, or array of two strings ]
4870
                        if (valueType == valueInternalType) {
4871
                            value = [value, value];
4872
                        }
4873
                        else if (valueType == TYPES.a) {
4874
                            valueArrLength = value[strLength];
4875
                            if (valueArrLength > 2 || valueArrLength < 1)
4876
                                value = resultDefault;
4877
                            else {
4878
                                if (valueArrLength === 1)
4879
                                    value[1] = defaultValue;
4880
                                for (i = 0; i < valueArrLength; i++) {
4881
                                    valueArrItem = value[i];
4882
                                    if (type(valueArrItem) != valueInternalType || !checkSettingsStringValue(valueArrItem, allowedValues)) {
4883
                                        value = resultDefault;
4884
                                        break;
4885
                                    }
4886
                                }
4887
                            }
4888
                        }
4889
                        else if (valueType == TYPES.o)
4890
                            value = [value[_strX] || defaultValue, value[_strY] || defaultValue];
4891
                        else
4892
                            value = resultDefault;
4893
                        return { x: value[0], y: value[1] };
4894
                    }
4895
                    function generateMargin(marginTopRightBottomLeftArray) {
4896
                        var result = [];
4897
                        var currValue;
4898
                        var currValueType;
4899
                        var valueDirections = [_strTop, _strRight, _strBottom, _strLeft];
4900
                        for (i = 0; i < marginTopRightBottomLeftArray[strLength]; i++) {
4901
                            if (i === valueDirections[strLength])
4902
                                break;
4903
                            currValue = marginTopRightBottomLeftArray[i];
4904
                            currValueType = type(currValue);
4905
                            if (currValueType == TYPES.b)
4906
                                result.push(currValue ? parseToZeroOrNumber(finalElement.css(_strMarginMinus + valueDirections[i])) : 0);
4907
                            else
4908
                                result.push(currValueType == TYPES.n ? currValue : 0);
4909
                        }
4910
                        return result;
4911
                    }
4912

4913
                    if (possibleElementIsJQuery || possibleElementIsHTMLElement) {
4914
                        //get settings
4915
                        var margin = coordinatesIsElementObj ? coordinates.margin : 0;
4916
                        var axis = coordinatesIsElementObj ? coordinates.axis : 0;
4917
                        var scroll = coordinatesIsElementObj ? coordinates.scroll : 0;
4918
                        var block = coordinatesIsElementObj ? coordinates.block : 0;
4919
                        var marginDefault = [0, 0, 0, 0];
4920
                        var marginType = type(margin);
4921
                        var marginLength;
4922
                        finalElement = possibleElementIsJQuery ? possibleElement : FRAMEWORK(possibleElement);
4923

4924
                        if (finalElement[strLength] > 0) {
4925
                            //margin can be [ boolean, number, array of 2, array of 4, object ]
4926
                            if (marginType == TYPES.n || marginType == TYPES.b)
4927
                                margin = generateMargin([margin, margin, margin, margin]);
4928
                            else if (marginType == TYPES.a) {
4929
                                marginLength = margin[strLength];
4930
                                if (marginLength === 2)
4931
                                    margin = generateMargin([margin[0], margin[1], margin[0], margin[1]]);
4932
                                else if (marginLength >= 4)
4933
                                    margin = generateMargin(margin);
4934
                                else
4935
                                    margin = marginDefault;
4936
                            }
4937
                            else if (marginType == TYPES.o)
4938
                                margin = generateMargin([margin[_strTop], margin[_strRight], margin[_strBottom], margin[_strLeft]]);
4939
                            else
4940
                                margin = marginDefault;
4941

4942
                            //block = type(block) === TYPES.b ? block ? [ strNearest, strBegin ] : [ strNearest, strEnd ] : block;
4943
                            settingsAxis = checkSettingsStringValue(axis, elementObjSettingsAxisValues) ? axis : 'xy';
4944
                            settingsScroll = getPerAxisValue(scroll, TYPES.s, strAlways, elementObjSettingsScrollValues);
4945
                            settingsBlock = getPerAxisValue(block, TYPES.s, strBegin, elementObjSettingsBlockValues);
4946
                            settingsMargin = margin;
4947

4948
                            var viewportScroll = {
4949
                                l: _scrollHorizontalInfo._currentScroll,
4950
                                t: _scrollVerticalInfo._currentScroll
4951
                            };
4952
                            // use padding element instead of viewport element because padding element has never padding, margin or position applied.
4953
                            var viewportOffset = _paddingElement.offset();
4954

4955
                            //get coordinates
4956
                            var elementOffset = finalElement.offset();
4957
                            var doNotScroll = {
4958
                                x: settingsScroll.x == strNever || settingsAxis == _strY,
4959
                                y: settingsScroll.y == strNever || settingsAxis == _strX
4960
                            };
4961
                            elementOffset[_strTop] -= settingsMargin[0];
4962
                            elementOffset[_strLeft] -= settingsMargin[3];
4963
                            var elementScrollCoordinates = {
4964
                                x: MATH.round(elementOffset[_strLeft] - viewportOffset[_strLeft] + viewportScroll.l),
4965
                                y: MATH.round(elementOffset[_strTop] - viewportOffset[_strTop] + viewportScroll.t)
4966
                            };
4967
                            if (_isRTL) {
4968
                                if (!_rtlScrollBehavior.n && !_rtlScrollBehavior.i)
4969
                                    elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + viewportScroll.l);
4970
                                if (_rtlScrollBehavior.n && normalizeRTL)
4971
                                    elementScrollCoordinates.x *= -1;
4972
                                if (_rtlScrollBehavior.i && normalizeRTL)
4973
                                    elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + (_scrollHorizontalInfo._maxScroll - viewportScroll.l));
4974
                            }
4975

4976
                            //measuring is required
4977
                            if (settingsBlock.x != strBegin || settingsBlock.y != strBegin || settingsScroll.x == strIfNeeded || settingsScroll.y == strIfNeeded || _isRTL) {
4978
                                var measuringElm = finalElement[0];
4979
                                var rawElementSize = _supportTransform ? measuringElm[LEXICON.bCR]() : {
4980
                                    width: measuringElm[LEXICON.oW],
4981
                                    height: measuringElm[LEXICON.oH]
4982
                                };
4983
                                var elementSize = {
4984
                                    w: rawElementSize[_strWidth] + settingsMargin[3] + settingsMargin[1],
4985
                                    h: rawElementSize[_strHeight] + settingsMargin[0] + settingsMargin[2]
4986
                                };
4987
                                var finalizeBlock = function (isX) {
4988
                                    var vars = getScrollbarVars(isX);
4989
                                    var wh = vars._w_h;
4990
                                    var lt = vars._left_top;
4991
                                    var xy = vars._x_y;
4992
                                    var blockIsEnd = settingsBlock[xy] == (isX ? _isRTL ? strBegin : strEnd : strEnd);
4993
                                    var blockIsCenter = settingsBlock[xy] == strCenter;
4994
                                    var blockIsNearest = settingsBlock[xy] == strNearest;
4995
                                    var scrollNever = settingsScroll[xy] == strNever;
4996
                                    var scrollIfNeeded = settingsScroll[xy] == strIfNeeded;
4997
                                    var vpSize = _viewportSize[wh];
4998
                                    var vpOffset = viewportOffset[lt];
4999
                                    var elSize = elementSize[wh];
5000
                                    var elOffset = elementOffset[lt];
5001
                                    var divide = blockIsCenter ? 2 : 1;
5002
                                    var elementCenterOffset = elOffset + (elSize / 2);
5003
                                    var viewportCenterOffset = vpOffset + (vpSize / 2);
5004
                                    var isInView =
5005
                                        elSize <= vpSize
5006
                                        && elOffset >= vpOffset
5007
                                        && elOffset + elSize <= vpOffset + vpSize;
5008

5009
                                    if (scrollNever)
5010
                                        doNotScroll[xy] = true;
5011
                                    else if (!doNotScroll[xy]) {
5012
                                        if (blockIsNearest || scrollIfNeeded) {
5013
                                            doNotScroll[xy] = scrollIfNeeded ? isInView : false;
5014
                                            blockIsEnd = elSize < vpSize ? elementCenterOffset > viewportCenterOffset : elementCenterOffset < viewportCenterOffset;
5015
                                        }
5016
                                        elementScrollCoordinates[xy] -= blockIsEnd || blockIsCenter ? ((vpSize / divide) - (elSize / divide)) * (isX && _isRTL && normalizeRTL ? -1 : 1) : 0;
5017
                                    }
5018
                                };
5019
                                finalizeBlock(true);
5020
                                finalizeBlock(false);
5021
                            }
5022

5023
                            if (doNotScroll.y)
5024
                                delete elementScrollCoordinates.y;
5025
                            if (doNotScroll.x)
5026
                                delete elementScrollCoordinates.x;
5027

5028
                            coordinates = elementScrollCoordinates;
5029
                        }
5030
                    }
5031

5032
                    finalScroll[_strScrollLeft] = getFinalScroll(true, getRawScroll(true, coordinates));
5033
                    finalScroll[_strScrollTop] = getFinalScroll(false, getRawScroll(false, coordinates));
5034
                    doScrollLeft = finalScroll[_strScrollLeft] !== undefined;
5035
                    doScrollTop = finalScroll[_strScrollTop] !== undefined;
5036

5037
                    if ((doScrollLeft || doScrollTop) && (duration > 0 || durationIsObject)) {
5038
                        if (durationIsObject) {
5039
                            duration.complete = proxyCompleteCallback;
5040
                            _viewportElement.animate(finalScroll, duration);
5041
                        }
5042
                        else {
5043
                            animationOptions = {
5044
                                duration: duration,
5045
                                complete: proxyCompleteCallback
5046
                            };
5047
                            if (COMPATIBILITY.isA(easing) || FRAMEWORK.isPlainObject(easing)) {
5048
                                specialEasing[_strScrollLeft] = easing[0] || easing.x;
5049
                                specialEasing[_strScrollTop] = easing[1] || easing.y;
5050
                                animationOptions.specialEasing = specialEasing;
5051
                            }
5052
                            else {
5053
                                animationOptions.easing = easing;
5054
                            }
5055
                            _viewportElement.animate(finalScroll, animationOptions);
5056
                        }
5057
                    }
5058
                    else {
5059
                        if (doScrollLeft)
5060
                            _viewportElement[_strScrollLeft](finalScroll[_strScrollLeft]);
5061
                        if (doScrollTop)
5062
                            _viewportElement[_strScrollTop](finalScroll[_strScrollTop]);
5063
                        updateScrollbarInfos();
5064
                    }
5065
                };
5066

5067
                /**
5068
                 * Stops all scroll animations.
5069
                 * @returns {*} The current OverlayScrollbars instance (for chaining).
5070
                 */
5071
                _base.scrollStop = function (param1, param2, param3) {
5072
                    _viewportElement.stop(param1, param2, param3);
5073
                    return _base;
5074
                };
5075

5076
                /**
5077
                 * Returns all relevant elements.
5078
                 * @param elementName The name of the element which shall be returned.
5079
                 * @returns {{target: *, host: *, padding: *, viewport: *, content: *, scrollbarHorizontal: {scrollbar: *, track: *, handle: *}, scrollbarVertical: {scrollbar: *, track: *, handle: *}, scrollbarCorner: *} | *}
5080
                 */
5081
                _base.getElements = function (elementName) {
5082
                    var obj = {
5083
                        target: _targetElementNative,
5084
                        host: _hostElementNative,
5085
                        padding: _paddingElementNative,
5086
                        viewport: _viewportElementNative,
5087
                        content: _contentElementNative,
5088
                        scrollbarHorizontal: {
5089
                            scrollbar: _scrollbarHorizontalElement[0],
5090
                            track: _scrollbarHorizontalTrackElement[0],
5091
                            handle: _scrollbarHorizontalHandleElement[0]
5092
                        },
5093
                        scrollbarVertical: {
5094
                            scrollbar: _scrollbarVerticalElement[0],
5095
                            track: _scrollbarVerticalTrackElement[0],
5096
                            handle: _scrollbarVerticalHandleElement[0]
5097
                        },
5098
                        scrollbarCorner: _scrollbarCornerElement[0]
5099
                    };
5100
                    return type(elementName) == TYPES.s ? getObjectPropVal(obj, elementName) : obj;
5101
                };
5102

5103
                /**
5104
                 * Returns a object which describes the current state of this instance.
5105
                 * @param stateProperty A specific property from the state object which shall be returned.
5106
                 * @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *}
5107
                 */
5108
                _base.getState = function (stateProperty) {
5109
                    function prepare(obj) {
5110
                        if (!FRAMEWORK.isPlainObject(obj))
5111
                            return obj;
5112
                        var extended = extendDeep({}, obj);
5113
                        var changePropertyName = function (from, to) {
5114
                            if (extended[LEXICON.hOP](from)) {
5115
                                extended[to] = extended[from];
5116
                                delete extended[from];
5117
                            }
5118
                        };
5119
                        changePropertyName('w', _strWidth); //change w to width
5120
                        changePropertyName('h', _strHeight); //change h to height
5121
                        delete extended.c; //delete c (the 'changed' prop)
5122
                        return extended;
5123
                    };
5124
                    var obj = {
5125
                        destroyed: !!prepare(_destroyed),
5126
                        sleeping: !!prepare(_sleeping),
5127
                        autoUpdate: prepare(!_mutationObserversConnected),
5128
                        widthAuto: prepare(_widthAutoCache),
5129
                        heightAuto: prepare(_heightAutoCache),
5130
                        padding: prepare(_cssPaddingCache),
5131
                        overflowAmount: prepare(_overflowAmountCache),
5132
                        hideOverflow: prepare(_hideOverflowCache),
5133
                        hasOverflow: prepare(_hasOverflowCache),
5134
                        contentScrollSize: prepare(_contentScrollSizeCache),
5135
                        viewportSize: prepare(_viewportSize),
5136
                        hostSize: prepare(_hostSizeCache),
5137
                        documentMixed: prepare(_documentMixed)
5138
                    };
5139
                    return type(stateProperty) == TYPES.s ? getObjectPropVal(obj, stateProperty) : obj;
5140
                };
5141

5142
                /**
5143
                 * Gets all or specific extension instance.
5144
                 * @param extName The name of the extension from which the instance shall be got.
5145
                 * @returns {{}} The instance of the extension with the given name or undefined if the instance couldn't be found.
5146
                 */
5147
                _base.ext = function (extName) {
5148
                    var result;
5149
                    var privateMethods = _extensionsPrivateMethods.split(' ');
5150
                    var i = 0;
5151
                    if (type(extName) == TYPES.s) {
5152
                        if (_extensions[LEXICON.hOP](extName)) {
5153
                            result = extendDeep({}, _extensions[extName]);
5154
                            for (; i < privateMethods.length; i++)
5155
                                delete result[privateMethods[i]];
5156
                        }
5157
                    }
5158
                    else {
5159
                        result = {};
5160
                        for (i in _extensions)
5161
                            result[i] = extendDeep({}, _base.ext(i));
5162
                    }
5163
                    return result;
5164
                };
5165

5166
                /**
5167
                 * Adds a extension to this instance.
5168
                 * @param extName The name of the extension which shall be added.
5169
                 * @param extensionOptions The extension options which shall be used.
5170
                 * @returns {{}} The instance of the added extension or undefined if the extension couldn't be added properly.
5171
                 */
5172
                _base.addExt = function (extName, extensionOptions) {
5173
                    var registeredExtensionObj = _plugin.extension(extName);
5174
                    var instance;
5175
                    var instanceAdded;
5176
                    var instanceContract;
5177
                    var contractResult;
5178
                    var contractFulfilled = true;
5179
                    if (registeredExtensionObj) {
5180
                        if (!_extensions[LEXICON.hOP](extName)) {
5181
                            instance = registeredExtensionObj.extensionFactory.call(_base,
5182
                                extendDeep({}, registeredExtensionObj.defaultOptions),
5183
                                FRAMEWORK,
5184
                                COMPATIBILITY);
5185

5186
                            if (instance) {
5187
                                instanceContract = instance.contract;
5188
                                if (type(instanceContract) == TYPES.f) {
5189
                                    contractResult = instanceContract(window);
5190
                                    contractFulfilled = type(contractResult) == TYPES.b ? contractResult : contractFulfilled;
5191
                                }
5192
                                if (contractFulfilled) {
5193
                                    _extensions[extName] = instance;
5194
                                    instanceAdded = instance.added;
5195
                                    if (type(instanceAdded) == TYPES.f)
5196
                                        instanceAdded(extensionOptions);
5197

5198
                                    return _base.ext(extName);
5199
                                }
5200
                            }
5201
                        }
5202
                        else
5203
                            return _base.ext(extName);
5204
                    }
5205
                    else
5206
                        console.warn("A extension with the name \"" + extName + "\" isn't registered.");
5207
                };
5208

5209
                /**
5210
                 * Removes a extension from this instance.
5211
                 * @param extName The name of the extension which shall be removed.
5212
                 * @returns {boolean} True if the extension was removed, false otherwise e.g. if the extension wasn't added before.
5213
                 */
5214
                _base.removeExt = function (extName) {
5215
                    var instance = _extensions[extName];
5216
                    var instanceRemoved;
5217
                    if (instance) {
5218
                        delete _extensions[extName];
5219

5220
                        instanceRemoved = instance.removed;
5221
                        if (type(instanceRemoved) == TYPES.f)
5222
                            instanceRemoved();
5223

5224
                        return true;
5225
                    }
5226
                    return false;
5227
                };
5228

5229
                /**
5230
                 * Constructs the plugin.
5231
                 * @param targetElement The element to which the plugin shall be applied.
5232
                 * @param options The initial options of the plugin.
5233
                 * @param extensions The extension(s) which shall be added right after the initialization.
5234
                 * @returns {boolean} True if the plugin was successfully initialized, false otherwise.
5235
                 */
5236
                function construct(targetElement, options, extensions) {
5237
                    _defaultOptions = globals.defaultOptions;
5238
                    _nativeScrollbarStyling = globals.nativeScrollbarStyling;
5239
                    _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
5240
                    _nativeScrollbarIsOverlaid = extendDeep({}, globals.nativeScrollbarIsOverlaid);
5241
                    _overlayScrollbarDummySize = extendDeep({}, globals.overlayScrollbarDummySize);
5242
                    _rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior);
5243

5244
                    //parse & set options but don't update
5245
                    setOptions(extendDeep({}, _defaultOptions, options));
5246

5247
                    _cssCalc = globals.cssCalc;
5248
                    _msieVersion = globals.msie;
5249
                    _autoUpdateRecommended = globals.autoUpdateRecommended;
5250
                    _supportTransition = globals.supportTransition;
5251
                    _supportTransform = globals.supportTransform;
5252
                    _supportPassiveEvents = globals.supportPassiveEvents;
5253
                    _supportResizeObserver = globals.supportResizeObserver;
5254
                    _supportMutationObserver = globals.supportMutationObserver;
5255
                    _restrictedMeasuring = globals.restrictedMeasuring;
5256
                    _documentElement = FRAMEWORK(targetElement.ownerDocument);
5257
                    _documentElementNative = _documentElement[0];
5258
                    _windowElement = FRAMEWORK(_documentElementNative.defaultView || _documentElementNative.parentWindow);
5259
                    _windowElementNative = _windowElement[0];
5260
                    _htmlElement = findFirst(_documentElement, 'html');
5261
                    _bodyElement = findFirst(_htmlElement, 'body');
5262
                    _targetElement = FRAMEWORK(targetElement);
5263
                    _targetElementNative = _targetElement[0];
5264
                    _isTextarea = _targetElement.is('textarea');
5265
                    _isBody = _targetElement.is('body');
5266
                    _documentMixed = _documentElementNative !== document;
5267

5268
                    /* On a div Element The if checks only whether:
5269
                     * - the targetElement has the class "os-host"
5270
                     * - the targetElement has a a child with the class "os-padding"
5271
                     * 
5272
                     * If that's the case, its assumed the DOM has already the following structure:
5273
                     * (The ".os-host" element is the targetElement)
5274
                     *
5275
                     *  <div class="os-host">
5276
                     *      <div class="os-resize-observer-host"></div>
5277
                     *      <div class="os-padding">
5278
                     *          <div class="os-viewport">
5279
                     *              <div class="os-content"></div>
5280
                     *          </div>
5281
                     *      </div>
5282
                     *      <div class="os-scrollbar os-scrollbar-horizontal ">
5283
                     *          <div class="os-scrollbar-track">
5284
                     *              <div class="os-scrollbar-handle"></div>
5285
                     *          </div>
5286
                     *      </div>
5287
                     *      <div class="os-scrollbar os-scrollbar-vertical">
5288
                     *          <div class="os-scrollbar-track">
5289
                     *              <div class="os-scrollbar-handle"></div>
5290
                     *          </div>
5291
                     *      </div>
5292
                     *      <div class="os-scrollbar-corner"></div>
5293
                     *  </div>
5294
                     *
5295
                     * =====================================================================================
5296
                     * 
5297
                     * On a Textarea Element The if checks only whether:
5298
                     * - the targetElement has the class "os-textarea" 
5299
                     * - the targetElement is inside a element with the class "os-content" 
5300
                     * 
5301
                     * If that's the case, its assumed the DOM has already the following structure:
5302
                     * (The ".os-textarea" (textarea) element is the targetElement)
5303
                     *
5304
                     *  <div class="os-host-textarea">
5305
                     *      <div class="os-resize-observer-host"></div>
5306
                     *      <div class="os-padding os-text-inherit">
5307
                     *          <div class="os-viewport os-text-inherit">
5308
                     *              <div class="os-content os-text-inherit">
5309
                     *                  <div class="os-textarea-cover"></div>
5310
                     *                  <textarea class="os-textarea os-text-inherit"></textarea>
5311
                     *              </div>
5312
                     *          </div>
5313
                     *      </div>
5314
                     *      <div class="os-scrollbar os-scrollbar-horizontal ">
5315
                     *          <div class="os-scrollbar-track">
5316
                     *              <div class="os-scrollbar-handle"></div>
5317
                     *          </div>
5318
                     *      </div>
5319
                     *      <div class="os-scrollbar os-scrollbar-vertical">
5320
                     *          <div class="os-scrollbar-track">
5321
                     *              <div class="os-scrollbar-handle"></div>
5322
                     *          </div>
5323
                     *      </div>
5324
                     *      <div class="os-scrollbar-corner"></div>
5325
                     *  </div>
5326
                     */
5327
                    _domExists = _isTextarea
5328
                        ? _targetElement.hasClass(_classNameTextareaElement) && _targetElement.parent().hasClass(_classNameContentElement)
5329
                        : _targetElement.hasClass(_classNameHostElement) && _targetElement.children(_strDot + _classNamePaddingElement)[LEXICON.l];
5330

5331
                    var initBodyScroll;
5332
                    var bodyMouseTouchDownListener;
5333

5334
                    //check if the plugin hasn't to be initialized
5335
                    if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) {
5336
                        dispatchCallback('onInitializationWithdrawn');
5337
                        if (_domExists) {
5338
                            setupStructureDOM(true);
5339
                            setupScrollbarsDOM(true);
5340
                            setupScrollbarCornerDOM(true);
5341
                        }
5342

5343
                        _destroyed = true;
5344
                        _sleeping = true;
5345

5346
                        return _base;
5347
                    }
5348

5349
                    if (_isBody) {
5350
                        initBodyScroll = {};
5351
                        initBodyScroll.l = MATH.max(_targetElement[_strScrollLeft](), _htmlElement[_strScrollLeft](), _windowElement[_strScrollLeft]());
5352
                        initBodyScroll.t = MATH.max(_targetElement[_strScrollTop](), _htmlElement[_strScrollTop](), _windowElement[_strScrollTop]());
5353

5354
                        bodyMouseTouchDownListener = function () {
5355
                            _viewportElement.removeAttr(LEXICON.ti);
5356
                            setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, true, true);
5357
                        }
5358
                    }
5359

5360
                    //build OverlayScrollbars DOM
5361
                    setupStructureDOM();
5362
                    setupScrollbarsDOM();
5363
                    setupScrollbarCornerDOM();
5364

5365
                    //create OverlayScrollbars events
5366
                    setupStructureEvents();
5367
                    setupScrollbarEvents(true);
5368
                    setupScrollbarEvents(false);
5369
                    setupScrollbarCornerEvents();
5370

5371
                    //create mutation observers
5372
                    createMutationObservers();
5373

5374
                    //build resize observer for the host element
5375
                    setupResizeObserver(_sizeObserverElement, hostOnResized);
5376

5377
                    if (_isBody) {
5378
                        //apply the body scroll to handle it right in the update method
5379
                        _viewportElement[_strScrollLeft](initBodyScroll.l)[_strScrollTop](initBodyScroll.t);
5380

5381
                        //set the focus on the viewport element so you dont have to click on the page to use keyboard keys (up / down / space) for scrolling
5382
                        if (document.activeElement == targetElement && _viewportElementNative.focus) {
5383
                            //set a tabindex to make the viewportElement focusable
5384
                            _viewportElement.attr(LEXICON.ti, '-1');
5385
                            _viewportElementNative.focus();
5386

5387
                            /* the tabindex has to be removed due to;
5388
                             * 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
5389
                             * https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
5390
                             */
5391
                            setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, false, true);
5392
                        }
5393
                    }
5394

5395
                    //update for the first time & initialize cache
5396
                    _base.update(_strAuto);
5397

5398
                    //the plugin is initialized now!
5399
                    _initialized = true;
5400
                    dispatchCallback('onInitialized');
5401

5402
                    //call all callbacks which would fire before the initialized was complete
5403
                    each(_callbacksInitQeueue, function (index, value) { dispatchCallback(value.n, value.a); });
5404
                    _callbacksInitQeueue = [];
5405

5406
                    //add extensions
5407
                    if (type(extensions) == TYPES.s)
5408
                        extensions = [extensions];
5409
                    if (COMPATIBILITY.isA(extensions))
5410
                        each(extensions, function (index, value) { _base.addExt(value); });
5411
                    else if (FRAMEWORK.isPlainObject(extensions))
5412
                        each(extensions, function (key, value) { _base.addExt(key, value); });
5413

5414
                    //add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions)
5415
                    setTimeout(function () {
5416
                        if (_supportTransition && !_destroyed)
5417
                            addClass(_hostElement, _classNameHostTransition);
5418
                    }, 333);
5419

5420
                    return _base;
5421
                }
5422

5423
                if (_plugin.valid(construct(pluginTargetElement, options, extensions))) {
5424
                    INSTANCES(pluginTargetElement, _base);
5425
                }
5426

5427
                return _base;
5428
            }
5429

5430
            /**
5431
             * Initializes a new OverlayScrollbarsInstance object or changes options if already initialized or returns the current instance.
5432
             * @param pluginTargetElements The elements to which the Plugin shall be initialized.
5433
             * @param options The custom options with which the plugin shall be initialized.
5434
             * @param extensions The extension(s) which shall be added right after initialization.
5435
             * @returns {*}
5436
             */
5437
            _plugin = window[PLUGINNAME] = function (pluginTargetElements, options, extensions) {
5438
                if (arguments[LEXICON.l] === 0)
5439
                    return this;
5440

5441
                var arr = [];
5442
                var optsIsPlainObj = FRAMEWORK.isPlainObject(options);
5443
                var inst;
5444
                var result;
5445

5446
                //pluginTargetElements is null or undefined
5447
                if (!pluginTargetElements)
5448
                    return optsIsPlainObj || !options ? result : arr;
5449

5450
                /*
5451
                   pluginTargetElements will be converted to:
5452
                   1. A jQueryElement Array
5453
                   2. A HTMLElement Array
5454
                   3. A Array with a single HTML Element
5455
                   so pluginTargetElements is always a array.
5456
                */
5457
                pluginTargetElements = pluginTargetElements[LEXICON.l] != undefined ? pluginTargetElements : [pluginTargetElements[0] || pluginTargetElements];
5458
                initOverlayScrollbarsStatics();
5459

5460
                if (pluginTargetElements[LEXICON.l] > 0) {
5461
                    if (optsIsPlainObj) {
5462
                        FRAMEWORK.each(pluginTargetElements, function (i, v) {
5463
                            inst = v;
5464
                            if (inst !== undefined)
5465
                                arr.push(OverlayScrollbarsInstance(inst, options, extensions, _pluginsGlobals, _pluginsAutoUpdateLoop));
5466
                        });
5467
                    }
5468
                    else {
5469
                        FRAMEWORK.each(pluginTargetElements, function (i, v) {
5470
                            inst = INSTANCES(v);
5471
                            if ((options === '!' && _plugin.valid(inst)) || (COMPATIBILITY.type(options) == TYPES.f && options(v, inst)))
5472
                                arr.push(inst);
5473
                            else if (options === undefined)
5474
                                arr.push(inst);
5475
                        });
5476
                    }
5477
                    result = arr[LEXICON.l] === 1 ? arr[0] : arr;
5478
                }
5479
                return result;
5480
            };
5481

5482
            /**
5483
             * Returns a object which contains global information about the plugin and each instance of it.
5484
             * The returned object is just a copy, that means that changes to the returned object won't have any effect to the original object.
5485
             */
5486
            _plugin.globals = function () {
5487
                initOverlayScrollbarsStatics();
5488
                var globals = FRAMEWORK.extend(true, {}, _pluginsGlobals);
5489
                delete globals['msie'];
5490
                return globals;
5491
            };
5492

5493
            /**
5494
             * Gets or Sets the default options for each new plugin initialization.
5495
             * @param newDefaultOptions The object with which the default options shall be extended.
5496
             */
5497
            _plugin.defaultOptions = function (newDefaultOptions) {
5498
                initOverlayScrollbarsStatics();
5499
                var currDefaultOptions = _pluginsGlobals.defaultOptions;
5500
                if (newDefaultOptions === undefined)
5501
                    return FRAMEWORK.extend(true, {}, currDefaultOptions);
5502

5503
                //set the new default options
5504
                _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, {}, currDefaultOptions, _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true, currDefaultOptions)._default);
5505
            };
5506

5507
            /**
5508
             * Checks whether the passed instance is a non-destroyed OverlayScrollbars instance.
5509
             * @param osInstance The potential OverlayScrollbars instance which shall be checked.
5510
             * @returns {boolean} True if the passed value is a non-destroyed OverlayScrollbars instance, false otherwise.
5511
             */
5512
            _plugin.valid = function (osInstance) {
5513
                return osInstance instanceof _plugin && !osInstance.getState().destroyed;
5514
            };
5515

5516
            /**
5517
             * Registers, Unregisters or returns a extension.
5518
             * Register: Pass the name and the extension. (defaultOptions is optional)
5519
             * Unregister: Pass the name and anything except a function as extension parameter.
5520
             * Get extension: Pass the name of the extension which shall be got.
5521
             * Get all extensions: Pass no arguments.
5522
             * @param extensionName The name of the extension which shall be registered, unregistered or returned.
5523
             * @param extension A function which generates the instance of the extension or anything other to remove a already registered extension.
5524
             * @param defaultOptions The default options which shall be used for the registered extension.
5525
             */
5526
            _plugin.extension = function (extensionName, extension, defaultOptions) {
5527
                var extNameTypeString = COMPATIBILITY.type(extensionName) == TYPES.s;
5528
                var argLen = arguments[LEXICON.l];
5529
                var i = 0;
5530
                if (argLen < 1 || !extNameTypeString) {
5531
                    //return a copy of all extension objects
5532
                    return FRAMEWORK.extend(true, { length: _pluginsExtensions[LEXICON.l] }, _pluginsExtensions);
5533
                }
5534
                else if (extNameTypeString) {
5535
                    if (COMPATIBILITY.type(extension) == TYPES.f) {
5536
                        //register extension
5537
                        _pluginsExtensions.push({
5538
                            name: extensionName,
5539
                            extensionFactory: extension,
5540
                            defaultOptions: defaultOptions
5541
                        });
5542
                    }
5543
                    else {
5544
                        for (; i < _pluginsExtensions[LEXICON.l]; i++) {
5545
                            if (_pluginsExtensions[i].name === extensionName) {
5546
                                if (argLen > 1)
5547
                                    _pluginsExtensions.splice(i, 1); //remove extension
5548
                                else
5549
                                    return FRAMEWORK.extend(true, {}, _pluginsExtensions[i]); //return extension with the given name
5550
                            }
5551
                        }
5552
                    }
5553
                }
5554
            };
5555

5556
            return _plugin;
5557
        })();
5558

5559
        if (JQUERY && JQUERY.fn) {
5560
            /**
5561
             * The jQuery initialization interface.
5562
             * @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.
5563
             * @param extensions The extension(s) which shall be added right after initialization.
5564
             * @returns {*} After initialization it returns the jQuery element array, else it returns the instance(s) of the elements which are selected.
5565
             */
5566
            JQUERY.fn.overlayScrollbars = function (options, extensions) {
5567
                var _elements = this;
5568
                if (JQUERY.isPlainObject(options)) {
5569
                    JQUERY.each(_elements, function () { PLUGIN(this, options, extensions); });
5570
                    return _elements;
5571
                }
5572
                else
5573
                    return PLUGIN(_elements, options);
5574
            };
5575
        }
5576
        return PLUGIN;
5577
    }
5578
));

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.