GPQAPP

Форк
0
/
OverlayScrollbars.js 
6661 строка · 360.7 Кб
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(function () { return factory(global, global.document, undefined); });
17
    else if (typeof module === 'object' && typeof module.exports === 'object')
18
        module.exports = factory(global, global.document, undefined);
19
    else
20
        factory(global, global.document, undefined);
21
}(typeof window !== 'undefined' ? window : this,
22
    function (window, document, undefined) {
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

348
        var MATH = Math;
349
        var JQUERY = window.jQuery;
350
        var EASING = (function () {
351
            var _easingsMath = {
352
                p: MATH.PI,
353
                c: MATH.cos,
354
                s: MATH.sin,
355
                w: MATH.pow,
356
                t: MATH.sqrt,
357
                n: MATH.asin,
358
                a: MATH.abs,
359
                o: 1.70158
360
            };
361

362
            /*
363
             x : current percent (0 - 1),
364
             t : current time (duration * percent),
365
             b : start value (from),
366
             c : end value (to),
367
             d : duration
368

369
             easingName : function(x, t, b, c, d) { return easedValue; }
370
             */
371

372
            return {
373
                swing: function (x, t, b, c, d) {
374
                    return 0.5 - _easingsMath.c(x * _easingsMath.p) / 2;
375
                },
376
                linear: function (x, t, b, c, d) {
377
                    return x;
378
                },
379
                easeInQuad: function (x, t, b, c, d) {
380
                    return c * (t /= d) * t + b;
381
                },
382
                easeOutQuad: function (x, t, b, c, d) {
383
                    return -c * (t /= d) * (t - 2) + b;
384
                },
385
                easeInOutQuad: function (x, t, b, c, d) {
386
                    return ((t /= d / 2) < 1) ? c / 2 * t * t + b : -c / 2 * ((--t) * (t - 2) - 1) + b;
387
                },
388
                easeInCubic: function (x, t, b, c, d) {
389
                    return c * (t /= d) * t * t + b;
390
                },
391
                easeOutCubic: function (x, t, b, c, d) {
392
                    return c * ((t = t / d - 1) * t * t + 1) + b;
393
                },
394
                easeInOutCubic: function (x, t, b, c, d) {
395
                    return ((t /= d / 2) < 1) ? c / 2 * t * t * t + b : c / 2 * ((t -= 2) * t * t + 2) + b;
396
                },
397
                easeInQuart: function (x, t, b, c, d) {
398
                    return c * (t /= d) * t * t * t + b;
399
                },
400
                easeOutQuart: function (x, t, b, c, d) {
401
                    return -c * ((t = t / d - 1) * t * t * t - 1) + b;
402
                },
403
                easeInOutQuart: function (x, t, b, c, d) {
404
                    return ((t /= d / 2) < 1) ? c / 2 * t * t * t * t + b : -c / 2 * ((t -= 2) * t * t * t - 2) + b;
405
                },
406
                easeInQuint: function (x, t, b, c, d) {
407
                    return c * (t /= d) * t * t * t * t + b;
408
                },
409
                easeOutQuint: function (x, t, b, c, d) {
410
                    return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
411
                },
412
                easeInOutQuint: function (x, t, b, c, d) {
413
                    return ((t /= d / 2) < 1) ? c / 2 * t * t * t * t * t + b : c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
414
                },
415
                easeInSine: function (x, t, b, c, d) {
416
                    return -c * _easingsMath.c(t / d * (_easingsMath.p / 2)) + c + b;
417
                },
418
                easeOutSine: function (x, t, b, c, d) {
419
                    return c * _easingsMath.s(t / d * (_easingsMath.p / 2)) + b;
420
                },
421
                easeInOutSine: function (x, t, b, c, d) {
422
                    return -c / 2 * (_easingsMath.c(_easingsMath.p * t / d) - 1) + b;
423
                },
424
                easeInExpo: function (x, t, b, c, d) {
425
                    return (t == 0) ? b : c * _easingsMath.w(2, 10 * (t / d - 1)) + b;
426
                },
427
                easeOutExpo: function (x, t, b, c, d) {
428
                    return (t == d) ? b + c : c * (-_easingsMath.w(2, -10 * t / d) + 1) + b;
429
                },
430
                easeInOutExpo: function (x, t, b, c, d) {
431
                    if (t == 0) return b;
432
                    if (t == d) return b + c;
433
                    if ((t /= d / 2) < 1) return c / 2 * _easingsMath.w(2, 10 * (t - 1)) + b;
434
                    return c / 2 * (-_easingsMath.w(2, -10 * --t) + 2) + b;
435
                },
436
                easeInCirc: function (x, t, b, c, d) {
437
                    return -c * (_easingsMath.t(1 - (t /= d) * t) - 1) + b;
438
                },
439
                easeOutCirc: function (x, t, b, c, d) {
440
                    return c * _easingsMath.t(1 - (t = t / d - 1) * t) + b;
441
                },
442
                easeInOutCirc: function (x, t, b, c, d) {
443
                    return ((t /= d / 2) < 1) ? -c / 2 * (_easingsMath.t(1 - t * t) - 1) + b : c / 2 * (_easingsMath.t(1 - (t -= 2) * t) + 1) + b;
444
                },
445
                easeInElastic: function (x, t, b, c, d) {
446
                    var s = _easingsMath.o; var p = 0; var a = c;
447
                    if (t == 0) return b; if ((t /= d) == 1) return b + c; if (!p) p = d * .3;
448
                    if (a < _easingsMath.a(c)) { a = c; s = p / 4; }
449
                    else s = p / (2 * _easingsMath.p) * _easingsMath.n(c / a);
450
                    return -(a * _easingsMath.w(2, 10 * (t -= 1)) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p)) + b;
451
                },
452
                easeOutElastic: function (x, t, b, c, d) {
453
                    var s = _easingsMath.o; var p = 0; var a = c;
454
                    if (t == 0) return b;
455
                    if ((t /= d) == 1) return b + c;
456
                    if (!p) p = d * .3;
457
                    if (a < _easingsMath.a(c)) { a = c; s = p / 4; }
458
                    else s = p / (2 * _easingsMath.p) * _easingsMath.n(c / a);
459
                    return a * _easingsMath.w(2, -10 * t) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p) + c + b;
460
                },
461
                easeInOutElastic: function (x, t, b, c, d) {
462
                    var s = _easingsMath.o; var p = 0; var a = c;
463
                    if (t == 0) return b;
464
                    if ((t /= d / 2) == 2) return b + c;
465
                    if (!p) p = d * (.3 * 1.5);
466
                    if (a < _easingsMath.a(c)) { a = c; s = p / 4; }
467
                    else s = p / (2 * _easingsMath.p) * _easingsMath.n(c / a);
468
                    if (t < 1) return -.5 * (a * _easingsMath.w(2, 10 * (t -= 1)) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p)) + b;
469
                    return a * _easingsMath.w(2, -10 * (t -= 1)) * _easingsMath.s((t * d - s) * (2 * _easingsMath.p) / p) * .5 + c + b;
470
                },
471
                easeInBack: function (x, t, b, c, d, s) {
472
                    s = s || _easingsMath.o;
473
                    return c * (t /= d) * t * ((s + 1) * t - s) + b;
474
                },
475
                easeOutBack: function (x, t, b, c, d, s) {
476
                    s = s || _easingsMath.o;
477
                    return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
478
                },
479
                easeInOutBack: function (x, t, b, c, d, s) {
480
                    s = s || _easingsMath.o;
481
                    return ((t /= d / 2) < 1) ? c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b : c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
482
                },
483
                easeInBounce: function (x, t, b, c, d) {
484
                    return c - this.easeOutBounce(x, d - t, 0, c, d) + b;
485
                },
486
                easeOutBounce: function (x, t, b, c, d) {
487
                    var o = 7.5625;
488
                    if ((t /= d) < (1 / 2.75)) {
489
                        return c * (o * t * t) + b;
490
                    } else if (t < (2 / 2.75)) {
491
                        return c * (o * (t -= (1.5 / 2.75)) * t + .75) + b;
492
                    } else if (t < (2.5 / 2.75)) {
493
                        return c * (o * (t -= (2.25 / 2.75)) * t + .9375) + b;
494
                    } else {
495
                        return c * (o * (t -= (2.625 / 2.75)) * t + .984375) + b;
496
                    }
497
                },
498
                easeInOutBounce: function (x, t, b, c, d) {
499
                    return (t < d / 2) ? this.easeInBounce(x, t * 2, 0, c, d) * .5 + b : this.easeOutBounce(x, t * 2 - d, 0, c, d) * .5 + c * .5 + b;
500
                }
501
            };
502
            /*
503
             *
504
             * TERMS OF USE - EASING EQUATIONS
505
             * 
506
             * Open source under the BSD License. 
507
             * 
508
             * Copyright © 2001 Robert Penner
509
             * All rights reserved.
510
             * 
511
             * Redistribution and use in source and binary forms, with or without modification, 
512
             * are permitted provided that the following conditions are met:
513
             * 
514
             * Redistributions of source code must retain the above copyright notice, this list of 
515
             * conditions and the following disclaimer.
516
             * Redistributions in binary form must reproduce the above copyright notice, this list 
517
             * of conditions and the following disclaimer in the documentation and/or other materials 
518
             * provided with the distribution.
519
             * 
520
             * Neither the name of the author nor the names of contributors may be used to endorse 
521
             * or promote products derived from this software without specific prior written permission.
522
             * 
523
             * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
524
             * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
525
             * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
526
             *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
527
             *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
528
             *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
529
             * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
530
             *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
531
             * OF THE POSSIBILITY OF SUCH DAMAGE. 
532
             *
533
             */
534
        })();
535
        var FRAMEWORK = (function () {
536
            var _rnothtmlwhite = (/[^\x20\t\r\n\f]+/g);
537
            var _strSpace = ' ';
538
            var _strEmpty = '';
539
            var _strScrollLeft = 'scrollLeft';
540
            var _strScrollTop = 'scrollTop';
541
            var _animations = [];
542
            var _type = COMPATIBILITY.type;
543
            var _cssNumber = {
544
                animationIterationCount: true,
545
                columnCount: true,
546
                fillOpacity: true,
547
                flexGrow: true,
548
                flexShrink: true,
549
                fontWeight: true,
550
                lineHeight: true,
551
                opacity: true,
552
                order: true,
553
                orphans: true,
554
                widows: true,
555
                zIndex: true,
556
                zoom: true
557
            };
558

559
            function extend() {
560
                var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {},
561
                    i = 1,
562
                    length = arguments[LEXICON.l],
563
                    deep = false;
564

565
                // Handle a deep copy situation
566
                if (_type(target) == TYPES.b) {
567
                    deep = target;
568
                    target = arguments[1] || {};
569
                    // skip the boolean and the target
570
                    i = 2;
571
                }
572

573
                // Handle case when target is a string or something (possible in deep copy)
574
                if (_type(target) != TYPES.o && !_type(target) == TYPES.f) {
575
                    target = {};
576
                }
577

578
                // extend jQuery itself if only one argument is passed
579
                if (length === i) {
580
                    target = FakejQuery;
581
                    --i;
582
                }
583

584
                for (; i < length; i++) {
585
                    // Only deal with non-null/undefined values
586
                    if ((options = arguments[i]) != null) {
587
                        // Extend the base object
588
                        for (name in options) {
589
                            src = target[name];
590
                            copy = options[name];
591

592
                            // Prevent never-ending loop
593
                            if (target === copy) {
594
                                continue;
595
                            }
596

597
                            // Recurse if we're merging plain objects or arrays
598
                            if (deep && copy && (isPlainObject(copy) || (copyIsArray = COMPATIBILITY.isA(copy)))) {
599
                                if (copyIsArray) {
600
                                    copyIsArray = false;
601
                                    clone = src && COMPATIBILITY.isA(src) ? src : [];
602

603
                                } else {
604
                                    clone = src && isPlainObject(src) ? src : {};
605
                                }
606

607
                                // Never move original objects, clone them
608
                                target[name] = extend(deep, clone, copy);
609

610
                                // Don't bring in undefined values
611
                            } else if (copy !== undefined) {
612
                                target[name] = copy;
613
                            }
614
                        }
615
                    }
616
                }
617

618
                // Return the modified object
619
                return target;
620
            };
621

622
            function inArray(item, arr, fromIndex) {
623
                for (var i = fromIndex || 0; i < arr[LEXICON.l]; i++)
624
                    if (arr[i] === item)
625
                        return i;
626
                return -1;
627
            }
628

629
            function isFunction(obj) {
630
                return _type(obj) == TYPES.f;
631
            };
632

633
            function isEmptyObject(obj) {
634
                for (var name in obj)
635
                    return false;
636
                return true;
637
            };
638

639
            function isPlainObject(obj) {
640
                if (!obj || _type(obj) != TYPES.o)
641
                    return false;
642

643
                var key;
644
                var proto = LEXICON.p;
645
                var hasOwnProperty = Object[proto].hasOwnProperty;
646
                var hasOwnConstructor = hasOwnProperty.call(obj, 'constructor');
647
                var hasIsPrototypeOf = obj.constructor && obj.constructor[proto] && hasOwnProperty.call(obj.constructor[proto], 'isPrototypeOf');
648

649
                if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
650
                    return false;
651
                }
652

653

654
                for (key in obj) { /**/ }
655

656
                return _type(key) == TYPES.u || hasOwnProperty.call(obj, key);
657
            };
658

659
            function each(obj, callback) {
660
                var i = 0;
661

662
                if (isArrayLike(obj)) {
663
                    for (; i < obj[LEXICON.l]; i++) {
664
                        if (callback.call(obj[i], i, obj[i]) === false)
665
                            break;
666
                    }
667
                }
668
                else {
669
                    for (i in obj) {
670
                        if (callback.call(obj[i], i, obj[i]) === false)
671
                            break;
672
                    }
673
                }
674

675
                return obj;
676
            };
677

678
            function isArrayLike(obj) {
679
                var length = !!obj && [LEXICON.l] in obj && obj[LEXICON.l];
680
                var t = _type(obj);
681
                return isFunction(t) ? false : (t == TYPES.a || length === 0 || _type(length) == TYPES.n && length > 0 && (length - 1) in obj);
682
            }
683

684
            function stripAndCollapse(value) {
685
                var tokens = value.match(_rnothtmlwhite) || [];
686
                return tokens.join(_strSpace);
687
            }
688

689
            function matches(elem, selector) {
690
                var nodeList = (elem.parentNode || document).querySelectorAll(selector) || [];
691
                var i = nodeList[LEXICON.l];
692

693
                while (i--)
694
                    if (nodeList[i] == elem)
695
                        return true;
696

697
                return false;
698
            }
699

700
            function insertAdjacentElement(el, strategy, child) {
701
                if (COMPATIBILITY.isA(child)) {
702
                    for (var i = 0; i < child[LEXICON.l]; i++)
703
                        insertAdjacentElement(el, strategy, child[i]);
704
                }
705
                else if (_type(child) == TYPES.s)
706
                    el.insertAdjacentHTML(strategy, child);
707
                else
708
                    el.insertAdjacentElement(strategy, child.nodeType ? child : child[0]);
709
            }
710

711
            function setCSSVal(el, prop, val) {
712
                try {
713
                    if (el[LEXICON.s][prop] !== undefined)
714
                        el[LEXICON.s][prop] = parseCSSVal(prop, val);
715
                } catch (e) { }
716
            }
717

718
            function parseCSSVal(prop, val) {
719
                if (!_cssNumber[prop.toLowerCase()] && _type(val) == TYPES.n)
720
                    val += 'px';
721
                return val;
722
            }
723

724
            function startNextAnimationInQ(animObj, removeFromQ) {
725
                var index;
726
                var nextAnim;
727
                if (removeFromQ !== false)
728
                    animObj.q.splice(0, 1);
729
                if (animObj.q[LEXICON.l] > 0) {
730
                    nextAnim = animObj.q[0];
731
                    animate(animObj.el, nextAnim.props, nextAnim.duration, nextAnim.easing, nextAnim.complete, true);
732
                }
733
                else {
734
                    index = inArray(animObj, _animations);
735
                    if (index > -1)
736
                        _animations.splice(index, 1);
737
                }
738
            }
739

740
            function setAnimationValue(el, prop, value) {
741
                if (prop === _strScrollLeft || prop === _strScrollTop)
742
                    el[prop] = value;
743
                else
744
                    setCSSVal(el, prop, value);
745
            }
746

747
            function animate(el, props, options, easing, complete, guaranteedNext) {
748
                var hasOptions = isPlainObject(options);
749
                var from = {};
750
                var to = {};
751
                var i = 0;
752
                var key;
753
                var animObj;
754
                var start;
755
                var progress;
756
                var step;
757
                var specialEasing;
758
                var duration;
759
                if (hasOptions) {
760
                    easing = options.easing;
761
                    start = options.start;
762
                    progress = options.progress;
763
                    step = options.step;
764
                    specialEasing = options.specialEasing;
765
                    complete = options.complete;
766
                    duration = options.duration;
767
                }
768
                else
769
                    duration = options;
770
                specialEasing = specialEasing || {};
771
                duration = duration || 400;
772
                easing = easing || 'swing';
773
                guaranteedNext = guaranteedNext || false;
774

775
                for (; i < _animations[LEXICON.l]; i++) {
776
                    if (_animations[i].el === el) {
777
                        animObj = _animations[i];
778
                        break;
779
                    }
780
                }
781

782
                if (!animObj) {
783
                    animObj = {
784
                        el: el,
785
                        q: []
786
                    };
787
                    _animations.push(animObj);
788
                }
789

790
                for (key in props) {
791
                    if (key === _strScrollLeft || key === _strScrollTop)
792
                        from[key] = el[key];
793
                    else
794
                        from[key] = FakejQuery(el).css(key);
795
                }
796

797
                for (key in from) {
798
                    if (from[key] !== props[key] && props[key] !== undefined)
799
                        to[key] = props[key];
800
                }
801

802
                if (!isEmptyObject(to)) {
803
                    var timeNow;
804
                    var end;
805
                    var percent;
806
                    var fromVal;
807
                    var toVal;
808
                    var easedVal;
809
                    var timeStart;
810
                    var frame;
811
                    var elapsed;
812
                    var qPos = guaranteedNext ? 0 : inArray(qObj, animObj.q);
813
                    var qObj = {
814
                        props: to,
815
                        duration: hasOptions ? options : duration,
816
                        easing: easing,
817
                        complete: complete
818
                    };
819
                    if (qPos === -1) {
820
                        qPos = animObj.q[LEXICON.l];
821
                        animObj.q.push(qObj);
822
                    }
823

824
                    if (qPos === 0) {
825
                        if (duration > 0) {
826
                            timeStart = COMPATIBILITY.now();
827
                            frame = function () {
828
                                timeNow = COMPATIBILITY.now();
829
                                elapsed = (timeNow - timeStart);
830
                                end = qObj.stop || elapsed >= duration;
831
                                percent = 1 - ((MATH.max(0, timeStart + duration - timeNow) / duration) || 0);
832

833
                                for (key in to) {
834
                                    fromVal = parseFloat(from[key]);
835
                                    toVal = parseFloat(to[key]);
836
                                    easedVal = (toVal - fromVal) * EASING[specialEasing[key] || easing](percent, percent * duration, 0, 1, duration) + fromVal;
837
                                    setAnimationValue(el, key, easedVal);
838
                                    if (isFunction(step)) {
839
                                        step(easedVal, {
840
                                            elem: el,
841
                                            prop: key,
842
                                            start: fromVal,
843
                                            now: easedVal,
844
                                            end: toVal,
845
                                            pos: percent,
846
                                            options: {
847
                                                easing: easing,
848
                                                speacialEasing: specialEasing,
849
                                                duration: duration,
850
                                                complete: complete,
851
                                                step: step
852
                                            },
853
                                            startTime: timeStart
854
                                        });
855
                                    }
856
                                }
857

858
                                if (isFunction(progress))
859
                                    progress({}, percent, MATH.max(0, duration - elapsed));
860

861
                                if (end) {
862
                                    startNextAnimationInQ(animObj);
863
                                    if (isFunction(complete))
864
                                        complete();
865
                                }
866
                                else
867
                                    qObj.frame = COMPATIBILITY.rAF()(frame);
868
                            };
869
                            qObj.frame = COMPATIBILITY.rAF()(frame);
870
                        }
871
                        else {
872
                            for (key in to)
873
                                setAnimationValue(el, key, to[key]);
874
                            startNextAnimationInQ(animObj);
875
                        }
876
                    }
877
                }
878
                else if (guaranteedNext)
879
                    startNextAnimationInQ(animObj);
880
            }
881

882
            function stop(el, clearQ, jumpToEnd) {
883
                var animObj;
884
                var qObj;
885
                var key;
886
                var i = 0;
887
                for (; i < _animations[LEXICON.l]; i++) {
888
                    animObj = _animations[i];
889
                    if (animObj.el === el) {
890
                        if (animObj.q[LEXICON.l] > 0) {
891
                            qObj = animObj.q[0];
892
                            qObj.stop = true;
893
                            COMPATIBILITY.cAF()(qObj.frame);
894
                            animObj.q.splice(0, 1);
895

896
                            if (jumpToEnd)
897
                                for (key in qObj.props)
898
                                    setAnimationValue(el, key, qObj.props[key]);
899

900
                            if (clearQ)
901
                                animObj.q = [];
902
                            else
903
                                startNextAnimationInQ(animObj, false);
904
                        }
905
                        break;
906
                    }
907
                }
908
            }
909

910
            function elementIsVisible(el) {
911
                return !!(el[LEXICON.oW] || el[LEXICON.oH] || el.getClientRects()[LEXICON.l]);
912
            }
913

914
            function FakejQuery(selector) {
915
                if (arguments[LEXICON.l] === 0)
916
                    return this;
917

918
                var base = new FakejQuery();
919
                var elements = selector;
920
                var i = 0;
921
                var elms;
922
                var el;
923

924
                if (_type(selector) == TYPES.s) {
925
                    elements = [];
926
                    if (selector.charAt(0) === '<') {
927
                        el = document.createElement('div');
928
                        el.innerHTML = selector;
929
                        elms = el.children;
930
                    }
931
                    else {
932
                        elms = document.querySelectorAll(selector);
933
                    }
934

935
                    for (; i < elms[LEXICON.l]; i++)
936
                        elements.push(elms[i]);
937
                }
938

939
                if (elements) {
940
                    if (_type(elements) != TYPES.s && (!isArrayLike(elements) || elements === window || elements === elements.self))
941
                        elements = [elements];
942

943
                    for (i = 0; i < elements[LEXICON.l]; i++)
944
                        base[i] = elements[i];
945

946
                    base[LEXICON.l] = elements[LEXICON.l];
947
                }
948

949
                return base;
950
            };
951

952
            FakejQuery[LEXICON.p] = {
953

954
                //EVENTS:
955

956
                on: function (eventName, handler) {
957
                    eventName = (eventName || _strEmpty).match(_rnothtmlwhite) || [_strEmpty];
958

959
                    var eventNameLength = eventName[LEXICON.l];
960
                    var i = 0;
961
                    var el;
962
                    return this.each(function () {
963
                        el = this;
964
                        try {
965
                            if (el.addEventListener) {
966
                                for (; i < eventNameLength; i++)
967
                                    el.addEventListener(eventName[i], handler);
968
                            }
969
                            else if (el.detachEvent) {
970
                                for (; i < eventNameLength; i++)
971
                                    el.attachEvent('on' + eventName[i], handler);
972
                            }
973
                        } catch (e) { }
974
                    });
975
                },
976

977
                off: function (eventName, handler) {
978
                    eventName = (eventName || _strEmpty).match(_rnothtmlwhite) || [_strEmpty];
979

980
                    var eventNameLength = eventName[LEXICON.l];
981
                    var i = 0;
982
                    var el;
983
                    return this.each(function () {
984
                        el = this;
985
                        try {
986
                            if (el.removeEventListener) {
987
                                for (; i < eventNameLength; i++)
988
                                    el.removeEventListener(eventName[i], handler);
989
                            }
990
                            else if (el.detachEvent) {
991
                                for (; i < eventNameLength; i++)
992
                                    el.detachEvent('on' + eventName[i], handler);
993
                            }
994
                        } catch (e) { }
995
                    });
996
                },
997

998
                one: function (eventName, handler) {
999
                    eventName = (eventName || _strEmpty).match(_rnothtmlwhite) || [_strEmpty];
1000
                    return this.each(function () {
1001
                        var el = FakejQuery(this);
1002
                        FakejQuery.each(eventName, function (i, oneEventName) {
1003
                            var oneHandler = function (e) {
1004
                                handler.call(this, e);
1005
                                el.off(oneEventName, oneHandler);
1006
                            };
1007
                            el.on(oneEventName, oneHandler);
1008
                        });
1009
                    });
1010
                },
1011

1012
                trigger: function (eventName) {
1013
                    var el;
1014
                    var event;
1015
                    return this.each(function () {
1016
                        el = this;
1017
                        if (document.createEvent) {
1018
                            event = document.createEvent('HTMLEvents');
1019
                            event.initEvent(eventName, true, false);
1020
                            el.dispatchEvent(event);
1021
                        }
1022
                        else {
1023
                            el.fireEvent('on' + eventName);
1024
                        }
1025
                    });
1026
                },
1027

1028
                //DOM NODE INSERTING / REMOVING:
1029

1030
                append: function (child) {
1031
                    return this.each(function () { insertAdjacentElement(this, 'beforeend', child); });
1032
                },
1033

1034
                prepend: function (child) {
1035
                    return this.each(function () { insertAdjacentElement(this, 'afterbegin', child); });
1036
                },
1037

1038
                before: function (child) {
1039
                    return this.each(function () { insertAdjacentElement(this, 'beforebegin', child); });
1040
                },
1041

1042
                after: function (child) {
1043
                    return this.each(function () { insertAdjacentElement(this, 'afterend', child); });
1044
                },
1045

1046
                remove: function () {
1047
                    return this.each(function () {
1048
                        var el = this;
1049
                        var parentNode = el.parentNode;
1050
                        if (parentNode != null)
1051
                            parentNode.removeChild(el);
1052
                    });
1053
                },
1054

1055
                unwrap: function () {
1056
                    var parents = [];
1057
                    var i;
1058
                    var el;
1059
                    var parent;
1060

1061
                    this.each(function () {
1062
                        parent = this.parentNode;
1063
                        if (inArray(parent, parents) === - 1)
1064
                            parents.push(parent);
1065
                    });
1066

1067
                    for (i = 0; i < parents[LEXICON.l]; i++) {
1068
                        el = parents[i];
1069
                        parent = el.parentNode;
1070
                        while (el.firstChild)
1071
                            parent.insertBefore(el.firstChild, el);
1072
                        parent.removeChild(el);
1073
                    }
1074

1075
                    return this;
1076
                },
1077

1078
                wrapAll: function (wrapperHTML) {
1079
                    var i;
1080
                    var nodes = this;
1081
                    var wrapper = FakejQuery(wrapperHTML)[0];
1082
                    var deepest = wrapper;
1083
                    var parent = nodes[0].parentNode;
1084
                    var previousSibling = nodes[0].previousSibling;
1085
                    while (deepest.childNodes[LEXICON.l] > 0)
1086
                        deepest = deepest.childNodes[0];
1087

1088
                    for (i = 0; nodes[LEXICON.l] - i; deepest.firstChild === nodes[0] && i++)
1089
                        deepest.appendChild(nodes[i]);
1090

1091
                    var nextSibling = previousSibling ? previousSibling.nextSibling : parent.firstChild;
1092
                    parent.insertBefore(wrapper, nextSibling);
1093

1094
                    return this;
1095
                },
1096

1097
                wrapInner: function (wrapperHTML) {
1098
                    return this.each(function () {
1099
                        var el = FakejQuery(this);
1100
                        var contents = el.contents();
1101

1102
                        if (contents[LEXICON.l])
1103
                            contents.wrapAll(wrapperHTML);
1104
                        else
1105
                            el.append(wrapperHTML);
1106
                    });
1107
                },
1108

1109
                wrap: function (wrapperHTML) {
1110
                    return this.each(function () { FakejQuery(this).wrapAll(wrapperHTML); });
1111
                },
1112

1113

1114
                //DOM NODE MANIPULATION / INFORMATION:
1115

1116
                css: function (styles, val) {
1117
                    var el;
1118
                    var key;
1119
                    var cptStyle;
1120
                    var getCptStyle = window.getComputedStyle;
1121
                    if (_type(styles) == TYPES.s) {
1122
                        if (val === undefined) {
1123
                            el = this[0];
1124
                            cptStyle = getCptStyle ? getCptStyle(el, null) : el.currentStyle[styles];
1125

1126
                            //https://bugzilla.mozilla.org/show_bug.cgi?id=548397 can be null sometimes if iframe with display: none (firefox only!)
1127
                            return getCptStyle ? cptStyle != null ? cptStyle.getPropertyValue(styles) : el[LEXICON.s][styles] : cptStyle;
1128
                        }
1129
                        else {
1130
                            return this.each(function () {
1131
                                setCSSVal(this, styles, val);
1132
                            });
1133
                        }
1134
                    }
1135
                    else {
1136
                        return this.each(function () {
1137
                            for (key in styles)
1138
                                setCSSVal(this, key, styles[key]);
1139
                        });
1140
                    }
1141
                },
1142

1143
                hasClass: function (className) {
1144
                    var elem, i = 0;
1145
                    var classNamePrepared = _strSpace + className + _strSpace;
1146
                    var classList;
1147

1148
                    while ((elem = this[i++])) {
1149
                        classList = elem.classList;
1150
                        if (classList && classList.contains(className))
1151
                            return true;
1152
                        else if (elem.nodeType === 1 && (_strSpace + stripAndCollapse(elem.className + _strEmpty) + _strSpace).indexOf(classNamePrepared) > -1)
1153
                            return true;
1154
                    }
1155

1156
                    return false;
1157
                },
1158

1159
                addClass: function (className) {
1160
                    var classes;
1161
                    var elem;
1162
                    var cur;
1163
                    var curValue;
1164
                    var clazz;
1165
                    var finalValue;
1166
                    var supportClassList;
1167
                    var elmClassList;
1168
                    var i = 0;
1169
                    var v = 0;
1170

1171
                    if (className) {
1172
                        classes = className.match(_rnothtmlwhite) || [];
1173

1174
                        while ((elem = this[i++])) {
1175
                            elmClassList = elem.classList;
1176
                            if (supportClassList === undefined)
1177
                                supportClassList = elmClassList !== undefined;
1178

1179
                            if (supportClassList) {
1180
                                while ((clazz = classes[v++]))
1181
                                    elmClassList.add(clazz);
1182
                            }
1183
                            else {
1184
                                curValue = elem.className + _strEmpty;
1185
                                cur = elem.nodeType === 1 && (_strSpace + stripAndCollapse(curValue) + _strSpace);
1186

1187
                                if (cur) {
1188
                                    while ((clazz = classes[v++]))
1189
                                        if (cur.indexOf(_strSpace + clazz + _strSpace) < 0)
1190
                                            cur += clazz + _strSpace;
1191

1192
                                    finalValue = stripAndCollapse(cur);
1193
                                    if (curValue !== finalValue)
1194
                                        elem.className = finalValue;
1195
                                }
1196
                            }
1197
                        }
1198
                    }
1199

1200
                    return this;
1201
                },
1202

1203
                removeClass: function (className) {
1204
                    var classes;
1205
                    var elem;
1206
                    var cur;
1207
                    var curValue;
1208
                    var clazz;
1209
                    var finalValue;
1210
                    var supportClassList;
1211
                    var elmClassList;
1212
                    var i = 0;
1213
                    var v = 0;
1214

1215
                    if (className) {
1216
                        classes = className.match(_rnothtmlwhite) || [];
1217

1218
                        while ((elem = this[i++])) {
1219
                            elmClassList = elem.classList;
1220
                            if (supportClassList === undefined)
1221
                                supportClassList = elmClassList !== undefined;
1222

1223
                            if (supportClassList) {
1224
                                while ((clazz = classes[v++]))
1225
                                    elmClassList.remove(clazz);
1226
                            }
1227
                            else {
1228
                                curValue = elem.className + _strEmpty;
1229
                                cur = elem.nodeType === 1 && (_strSpace + stripAndCollapse(curValue) + _strSpace);
1230

1231
                                if (cur) {
1232
                                    while ((clazz = classes[v++]))
1233
                                        while (cur.indexOf(_strSpace + clazz + _strSpace) > -1)
1234
                                            cur = cur.replace(_strSpace + clazz + _strSpace, _strSpace);
1235

1236
                                    finalValue = stripAndCollapse(cur);
1237
                                    if (curValue !== finalValue)
1238
                                        elem.className = finalValue;
1239
                                }
1240
                            }
1241
                        }
1242
                    }
1243

1244
                    return this;
1245
                },
1246

1247
                hide: function () {
1248
                    return this.each(function () { this[LEXICON.s].display = 'none'; });
1249
                },
1250

1251
                show: function () {
1252
                    return this.each(function () { this[LEXICON.s].display = 'block'; });
1253
                },
1254

1255
                attr: function (attrName, value) {
1256
                    var i = 0;
1257
                    var el;
1258
                    while (el = this[i++]) {
1259
                        if (value === undefined)
1260
                            return el.getAttribute(attrName);
1261
                        el.setAttribute(attrName, value);
1262
                    }
1263
                    return this;
1264
                },
1265

1266
                removeAttr: function (attrName) {
1267
                    return this.each(function () { this.removeAttribute(attrName); });
1268
                },
1269

1270
                offset: function () {
1271
                    var el = this[0];
1272
                    var rect = el[LEXICON.bCR]();
1273
                    var scrollLeft = window.pageXOffset || document.documentElement[_strScrollLeft];
1274
                    var scrollTop = window.pageYOffset || document.documentElement[_strScrollTop];
1275
                    return {
1276
                        top: rect.top + scrollTop,
1277
                        left: rect.left + scrollLeft
1278
                    };
1279
                },
1280

1281
                position: function () {
1282
                    var el = this[0];
1283
                    return {
1284
                        top: el.offsetTop,
1285
                        left: el.offsetLeft
1286
                    };
1287
                },
1288

1289
                scrollLeft: function (value) {
1290
                    var i = 0;
1291
                    var el;
1292
                    while (el = this[i++]) {
1293
                        if (value === undefined)
1294
                            return el[_strScrollLeft];
1295
                        el[_strScrollLeft] = value;
1296
                    }
1297
                    return this;
1298
                },
1299

1300
                scrollTop: function (value) {
1301
                    var i = 0;
1302
                    var el;
1303
                    while (el = this[i++]) {
1304
                        if (value === undefined)
1305
                            return el[_strScrollTop];
1306
                        el[_strScrollTop] = value;
1307
                    }
1308
                    return this;
1309
                },
1310

1311
                val: function (value) {
1312
                    var el = this[0];
1313
                    if (!value)
1314
                        return el.value;
1315
                    el.value = value;
1316
                    return this;
1317
                },
1318

1319

1320
                //DOM TRAVERSAL / FILTERING:
1321

1322
                first: function () {
1323
                    return this.eq(0);
1324
                },
1325

1326
                last: function () {
1327
                    return this.eq(-1);
1328
                },
1329

1330
                eq: function (index) {
1331
                    return FakejQuery(this[index >= 0 ? index : this[LEXICON.l] + index]);
1332
                },
1333

1334
                find: function (selector) {
1335
                    var children = [];
1336
                    var i;
1337
                    this.each(function () {
1338
                        var el = this;
1339
                        var ch = el.querySelectorAll(selector);
1340
                        for (i = 0; i < ch[LEXICON.l]; i++)
1341
                            children.push(ch[i]);
1342
                    });
1343
                    return FakejQuery(children);
1344
                },
1345

1346
                children: function (selector) {
1347
                    var children = [];
1348
                    var el;
1349
                    var ch;
1350
                    var i;
1351

1352
                    this.each(function () {
1353
                        ch = this.children;
1354
                        for (i = 0; i < ch[LEXICON.l]; i++) {
1355
                            el = ch[i];
1356
                            if (selector) {
1357
                                if ((el.matches && el.matches(selector)) || matches(el, selector))
1358
                                    children.push(el);
1359
                            }
1360
                            else
1361
                                children.push(el);
1362
                        }
1363
                    });
1364
                    return FakejQuery(children);
1365
                },
1366

1367
                parent: function (selector) {
1368
                    var parents = [];
1369
                    var parent;
1370
                    this.each(function () {
1371
                        parent = this.parentNode;
1372
                        if (selector ? FakejQuery(parent).is(selector) : true)
1373
                            parents.push(parent);
1374
                    });
1375
                    return FakejQuery(parents);
1376
                },
1377

1378
                is: function (selector) {
1379

1380
                    var el;
1381
                    var i;
1382
                    for (i = 0; i < this[LEXICON.l]; i++) {
1383
                        el = this[i];
1384
                        if (selector === ':visible')
1385
                            return elementIsVisible(el);
1386
                        if (selector === ':hidden')
1387
                            return !elementIsVisible(el);
1388
                        if ((el.matches && el.matches(selector)) || matches(el, selector))
1389
                            return true;
1390
                    }
1391
                    return false;
1392
                },
1393

1394
                contents: function () {
1395
                    var contents = [];
1396
                    var childs;
1397
                    var i;
1398

1399
                    this.each(function () {
1400
                        childs = this.childNodes;
1401
                        for (i = 0; i < childs[LEXICON.l]; i++)
1402
                            contents.push(childs[i]);
1403
                    });
1404

1405
                    return FakejQuery(contents);
1406
                },
1407

1408
                each: function (callback) {
1409
                    return each(this, callback);
1410
                },
1411

1412

1413
                //ANIMATION:
1414

1415
                animate: function (props, duration, easing, complete) {
1416
                    return this.each(function () { animate(this, props, duration, easing, complete); });
1417
                },
1418

1419
                stop: function (clearQ, jump) {
1420
                    return this.each(function () { stop(this, clearQ, jump); });
1421
                }
1422
            };
1423

1424
            extend(FakejQuery, {
1425
                extend: extend,
1426
                inArray: inArray,
1427
                isEmptyObject: isEmptyObject,
1428
                isPlainObject: isPlainObject,
1429
                each: each
1430
            });
1431

1432
            return FakejQuery;
1433
        })();
1434
        var INSTANCES = (function () {
1435
            var _targets = [];
1436
            var _instancePropertyString = '__overlayScrollbars__';
1437

1438
            /**
1439
             * Register, unregister or get a certain (or all) instances.
1440
             * Register: Pass the target and the instance.
1441
             * Unregister: Pass the target and null.
1442
             * Get Instance: Pass the target from which the instance shall be got.
1443
             * Get Targets: Pass no arguments.
1444
             * @param target The target to which the instance shall be registered / from which the instance shall be unregistered / the instance shall be got
1445
             * @param instance The instance.
1446
             * @returns {*|void} Returns the instance from the given target.
1447
             */
1448
            return function (target, instance) {
1449
                var argLen = arguments[LEXICON.l];
1450
                if (argLen < 1) {
1451
                    //return all targets
1452
                    return _targets;
1453
                }
1454
                else {
1455
                    if (instance) {
1456
                        //register instance
1457
                        target[_instancePropertyString] = instance;
1458
                        _targets.push(target);
1459
                    }
1460
                    else {
1461
                        var index = COMPATIBILITY.inA(target, _targets);
1462
                        if (index > -1) {
1463
                            if (argLen > 1) {
1464
                                //unregister instance
1465
                                delete target[_instancePropertyString];
1466
                                _targets.splice(index, 1);
1467
                            }
1468
                            else {
1469
                                //get instance from target
1470
                                return _targets[index][_instancePropertyString];
1471
                            }
1472
                        }
1473
                    }
1474
                }
1475
            }
1476
        })();
1477
        var PLUGIN = (function () {
1478
            var _plugin;
1479
            var _pluginsGlobals;
1480
            var _pluginsAutoUpdateLoop;
1481
            var _pluginsExtensions = [];
1482
            var _pluginsOptions = (function () {
1483
                var type = COMPATIBILITY.type;
1484
                var possibleTemplateTypes = [
1485
                    TYPES.b, //boolean
1486
                    TYPES.n, //number
1487
                    TYPES.s, //string
1488
                    TYPES.a, //array
1489
                    TYPES.o, //object
1490
                    TYPES.f, //function
1491
                    TYPES.z  //null
1492
                ];
1493
                var restrictedStringsSplit = ' ';
1494
                var restrictedStringsPossibilitiesSplit = ':';
1495
                var classNameAllowedValues = [TYPES.z, TYPES.s];
1496
                var numberAllowedValues = TYPES.n;
1497
                var booleanNullAllowedValues = [TYPES.z, TYPES.b];
1498
                var booleanTrueTemplate = [true, TYPES.b];
1499
                var booleanFalseTemplate = [false, TYPES.b];
1500
                var callbackTemplate = [null, [TYPES.z, TYPES.f]];
1501
                var updateOnLoadTemplate = [['img'], [TYPES.s, TYPES.a, TYPES.z]];
1502
                var inheritedAttrsTemplate = [['style', 'class'], [TYPES.s, TYPES.a, TYPES.z]];
1503
                var resizeAllowedValues = 'n:none b:both h:horizontal v:vertical';
1504
                var overflowBehaviorAllowedValues = 'v-h:visible-hidden v-s:visible-scroll s:scroll h:hidden';
1505
                var scrollbarsVisibilityAllowedValues = 'v:visible h:hidden a:auto';
1506
                var scrollbarsAutoHideAllowedValues = 'n:never s:scroll l:leave m:move';
1507
                var optionsDefaultsAndTemplate = {
1508
                    className: ['os-theme-dark', classNameAllowedValues],                //null || string
1509
                    resize: ['none', resizeAllowedValues],                               //none || both  || horizontal || vertical || n || b || h || v
1510
                    sizeAutoCapable: booleanTrueTemplate,                                //true || false
1511
                    clipAlways: booleanTrueTemplate,                                     //true || false
1512
                    normalizeRTL: booleanTrueTemplate,                                   //true || false
1513
                    paddingAbsolute: booleanFalseTemplate,                               //true || false
1514
                    autoUpdate: [null, booleanNullAllowedValues],                        //true || false || null
1515
                    autoUpdateInterval: [33, numberAllowedValues],                       //number
1516
                    updateOnLoad: updateOnLoadTemplate,                                  //string || array || null
1517
                    nativeScrollbarsOverlaid: {
1518
                        showNativeScrollbars: booleanFalseTemplate,                      //true || false
1519
                        initialize: booleanTrueTemplate                                  //true || false
1520
                    },
1521
                    overflowBehavior: {
1522
                        x: ['scroll', overflowBehaviorAllowedValues],                    //visible-hidden  || visible-scroll || hidden || scroll || v-h || v-s || h || s
1523
                        y: ['scroll', overflowBehaviorAllowedValues]                     //visible-hidden  || visible-scroll || hidden || scroll || v-h || v-s || h || s
1524
                    },
1525
                    scrollbars: {
1526
                        visibility: ['auto', scrollbarsVisibilityAllowedValues],         //visible || hidden || auto || v || h || a
1527
                        autoHide: ['never', scrollbarsAutoHideAllowedValues],            //never || scroll || leave || move || n || s || l || m
1528
                        autoHideDelay: [800, numberAllowedValues],                       //number
1529
                        dragScrolling: booleanTrueTemplate,                              //true || false
1530
                        clickScrolling: booleanFalseTemplate,                            //true || false
1531
                        touchSupport: booleanTrueTemplate,                               //true || false
1532
                        snapHandle: booleanFalseTemplate                                 //true || false
1533
                    },
1534
                    textarea: {
1535
                        dynWidth: booleanFalseTemplate,                                  //true || false
1536
                        dynHeight: booleanFalseTemplate,                                 //true || false
1537
                        inheritedAttrs: inheritedAttrsTemplate                           //string || array || null
1538
                    },
1539
                    callbacks: {
1540
                        onInitialized: callbackTemplate,                                 //null || function
1541
                        onInitializationWithdrawn: callbackTemplate,                     //null || function
1542
                        onDestroyed: callbackTemplate,                                   //null || function
1543
                        onScrollStart: callbackTemplate,                                 //null || function
1544
                        onScroll: callbackTemplate,                                      //null || function
1545
                        onScrollStop: callbackTemplate,                                  //null || function
1546
                        onOverflowChanged: callbackTemplate,                             //null || function
1547
                        onOverflowAmountChanged: callbackTemplate,                       //null || function
1548
                        onDirectionChanged: callbackTemplate,                            //null || function
1549
                        onContentSizeChanged: callbackTemplate,                          //null || function
1550
                        onHostSizeChanged: callbackTemplate,                             //null || function
1551
                        onUpdated: callbackTemplate                                      //null || function
1552
                    }
1553
                };
1554
                var convert = function (template) {
1555
                    var recursive = function (obj) {
1556
                        var key;
1557
                        var val;
1558
                        var valType;
1559
                        for (key in obj) {
1560
                            if (!obj[LEXICON.hOP](key))
1561
                                continue;
1562
                            val = obj[key];
1563
                            valType = type(val);
1564
                            if (valType == TYPES.a)
1565
                                obj[key] = val[template ? 1 : 0];
1566
                            else if (valType == TYPES.o)
1567
                                obj[key] = recursive(val);
1568
                        }
1569
                        return obj;
1570
                    };
1571
                    return recursive(FRAMEWORK.extend(true, {}, optionsDefaultsAndTemplate));
1572
                };
1573

1574
                return {
1575
                    _defaults: convert(),
1576

1577
                    _template: convert(true),
1578

1579
                    /**
1580
                     * Validates the passed object by the passed template.
1581
                     * @param obj The object which shall be validated.
1582
                     * @param template The template which defines the allowed values and types.
1583
                     * @param writeErrors True if errors shall be logged to the console.
1584
                     * @param diffObj If a object is passed then only valid differences to this object will be returned.
1585
                     * @returns {{}} A object which contains two objects called "default" and "prepared" which contains only the valid properties of the passed original object and discards not different values compared to the passed diffObj.
1586
                     */
1587
                    _validate: function (obj, template, writeErrors, diffObj) {
1588
                        var validatedOptions = {};
1589
                        var validatedOptionsPrepared = {};
1590
                        var objectCopy = FRAMEWORK.extend(true, {}, obj);
1591
                        var inArray = FRAMEWORK.inArray;
1592
                        var isEmptyObj = FRAMEWORK.isEmptyObject;
1593
                        var checkObjectProps = function (data, template, diffData, validatedOptions, validatedOptionsPrepared, prevPropName) {
1594
                            for (var prop in template) {
1595
                                if (template[LEXICON.hOP](prop) && data[LEXICON.hOP](prop)) {
1596
                                    var isValid = false;
1597
                                    var isDiff = false;
1598
                                    var templateValue = template[prop];
1599
                                    var templateValueType = type(templateValue);
1600
                                    var templateIsComplex = templateValueType == TYPES.o;
1601
                                    var templateTypes = !COMPATIBILITY.isA(templateValue) ? [templateValue] : templateValue;
1602
                                    var dataDiffValue = diffData[prop];
1603
                                    var dataValue = data[prop];
1604
                                    var dataValueType = type(dataValue);
1605
                                    var propPrefix = prevPropName ? prevPropName + '.' : '';
1606
                                    var error = "The option \"" + propPrefix + prop + "\" wasn't set, because";
1607
                                    var errorPossibleTypes = [];
1608
                                    var errorRestrictedStrings = [];
1609
                                    var restrictedStringValuesSplit;
1610
                                    var restrictedStringValuesPossibilitiesSplit;
1611
                                    var isRestrictedValue;
1612
                                    var mainPossibility;
1613
                                    var currType;
1614
                                    var i;
1615
                                    var v;
1616
                                    var j;
1617

1618
                                    dataDiffValue = dataDiffValue === undefined ? {} : dataDiffValue;
1619

1620
                                    //if the template has a object as value, it means that the options are complex (verschachtelt)
1621
                                    if (templateIsComplex && dataValueType == TYPES.o) {
1622
                                        validatedOptions[prop] = {};
1623
                                        validatedOptionsPrepared[prop] = {};
1624
                                        checkObjectProps(dataValue, templateValue, dataDiffValue, validatedOptions[prop], validatedOptionsPrepared[prop], propPrefix + prop);
1625
                                        FRAMEWORK.each([data, validatedOptions, validatedOptionsPrepared], function (index, value) {
1626
                                            if (isEmptyObj(value[prop])) {
1627
                                                delete value[prop];
1628
                                            }
1629
                                        });
1630
                                    }
1631
                                    else if (!templateIsComplex) {
1632
                                        for (i = 0; i < templateTypes[LEXICON.l]; i++) {
1633
                                            currType = templateTypes[i];
1634
                                            templateValueType = type(currType);
1635
                                            //if currtype is string and starts with restrictedStringPrefix and end with restrictedStringSuffix
1636
                                            isRestrictedValue = templateValueType == TYPES.s && inArray(currType, possibleTemplateTypes) === -1;
1637
                                            if (isRestrictedValue) {
1638
                                                errorPossibleTypes.push(TYPES.s);
1639

1640
                                                //split it into a array which contains all possible values for example: ["y:yes", "n:no", "m:maybe"]
1641
                                                restrictedStringValuesSplit = currType.split(restrictedStringsSplit);
1642
                                                errorRestrictedStrings = errorRestrictedStrings.concat(restrictedStringValuesSplit);
1643
                                                for (v = 0; v < restrictedStringValuesSplit[LEXICON.l]; v++) {
1644
                                                    //split the possible values into their possibiliteis for example: ["y", "yes"] -> the first is always the mainPossibility
1645
                                                    restrictedStringValuesPossibilitiesSplit = restrictedStringValuesSplit[v].split(restrictedStringsPossibilitiesSplit);
1646
                                                    mainPossibility = restrictedStringValuesPossibilitiesSplit[0];
1647
                                                    for (j = 0; j < restrictedStringValuesPossibilitiesSplit[LEXICON.l]; j++) {
1648
                                                        //if any possibility matches with the dataValue, its valid
1649
                                                        if (dataValue === restrictedStringValuesPossibilitiesSplit[j]) {
1650
                                                            isValid = true;
1651
                                                            break;
1652
                                                        }
1653
                                                    }
1654
                                                    if (isValid)
1655
                                                        break;
1656
                                                }
1657
                                            }
1658
                                            else {
1659
                                                errorPossibleTypes.push(currType);
1660

1661
                                                if (dataValueType === currType) {
1662
                                                    isValid = true;
1663
                                                    break;
1664
                                                }
1665
                                            }
1666
                                        }
1667

1668
                                        if (isValid) {
1669
                                            isDiff = dataValue !== dataDiffValue;
1670

1671
                                            if (isDiff)
1672
                                                validatedOptions[prop] = dataValue;
1673

1674
                                            if (isRestrictedValue ? inArray(dataDiffValue, restrictedStringValuesPossibilitiesSplit) < 0 : isDiff)
1675
                                                validatedOptionsPrepared[prop] = isRestrictedValue ? mainPossibility : dataValue;
1676
                                        }
1677
                                        else if (writeErrors) {
1678
                                            console.warn(error + " it doesn't accept the type [ " + dataValueType.toUpperCase() + " ] with the value of \"" + dataValue + "\".\r\n" +
1679
                                                "Accepted types are: [ " + errorPossibleTypes.join(', ').toUpperCase() + " ]." +
1680
                                                (errorRestrictedStrings[length] > 0 ? "\r\nValid strings are: [ " + errorRestrictedStrings.join(', ').split(restrictedStringsPossibilitiesSplit).join(', ') + " ]." : ''));
1681
                                        }
1682
                                        delete data[prop];
1683
                                    }
1684
                                }
1685
                            }
1686
                        };
1687
                        checkObjectProps(objectCopy, template, diffObj || {}, validatedOptions, validatedOptionsPrepared);
1688

1689
                        //add values which aren't specified in the template to the finished validated object to prevent them from being discarded
1690
                        /*
1691
                        if(keepForeignProps) {
1692
                            FRAMEWORK.extend(true, validatedOptions, objectCopy);
1693
                            FRAMEWORK.extend(true, validatedOptionsPrepared, objectCopy);
1694
                        }
1695
                        */
1696

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

1700
                        return {
1701
                            _default: validatedOptions,
1702
                            _prepared: validatedOptionsPrepared
1703
                        };
1704
                    }
1705
                }
1706
            }());
1707

1708
            /**
1709
             * Initializes the object which contains global information about the plugin and each instance of it.
1710
             */
1711
            function initOverlayScrollbarsStatics() {
1712
                if (!_pluginsGlobals)
1713
                    _pluginsGlobals = new OverlayScrollbarsGlobals(_pluginsOptions._defaults);
1714
                if (!_pluginsAutoUpdateLoop)
1715
                    _pluginsAutoUpdateLoop = new OverlayScrollbarsAutoUpdateLoop(_pluginsGlobals);
1716
            }
1717

1718
            /**
1719
             * The global object for the OverlayScrollbars objects. It contains resources which every OverlayScrollbars object needs. This object is initialized only once: if the first OverlayScrollbars object gets initialized.
1720
             * @param defaultOptions
1721
             * @constructor
1722
             */
1723
            function OverlayScrollbarsGlobals(defaultOptions) {
1724
                var _base = this;
1725
                var strOverflow = 'overflow';
1726
                var strHidden = 'hidden';
1727
                var strScroll = 'scroll';
1728
                var bodyElement = FRAMEWORK('body');
1729
                var scrollbarDummyElement = FRAMEWORK('<div id="os-dummy-scrollbar-size"><div></div></div>');
1730
                var scrollbarDummyElement0 = scrollbarDummyElement[0];
1731
                var dummyContainerChild = FRAMEWORK(scrollbarDummyElement.children('div').eq(0));
1732

1733
                bodyElement.append(scrollbarDummyElement);
1734
                scrollbarDummyElement.hide().show(); //fix IE8 bug (incorrect measuring)
1735

1736
                var nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement0);
1737
                var nativeScrollbarIsOverlaid = {
1738
                    x: nativeScrollbarSize.x === 0,
1739
                    y: nativeScrollbarSize.y === 0
1740
                };
1741
                var msie = (function () {
1742
                    var ua = window.navigator.userAgent;
1743
                    var strIndexOf = 'indexOf';
1744
                    var strSubString = 'substring';
1745
                    var msie = ua[strIndexOf]('MSIE ');
1746
                    var trident = ua[strIndexOf]('Trident/');
1747
                    var edge = ua[strIndexOf]('Edge/');
1748
                    var rv = ua[strIndexOf]('rv:');
1749
                    var result;
1750
                    var parseIntFunc = parseInt;
1751

1752
                    // IE 10 or older => return version number
1753
                    if (msie > 0)
1754
                        result = parseIntFunc(ua[strSubString](msie + 5, ua[strIndexOf]('.', msie)), 10);
1755

1756
                    // IE 11 => return version number
1757
                    else if (trident > 0)
1758
                        result = parseIntFunc(ua[strSubString](rv + 3, ua[strIndexOf]('.', rv)), 10);
1759

1760
                    // Edge (IE 12+) => return version number
1761
                    else if (edge > 0)
1762
                        result = parseIntFunc(ua[strSubString](edge + 5, ua[strIndexOf]('.', edge)), 10);
1763

1764
                    // other browser
1765
                    return result;
1766
                })();
1767

1768
                FRAMEWORK.extend(_base, {
1769
                    defaultOptions: defaultOptions,
1770
                    msie: msie,
1771
                    autoUpdateLoop: false,
1772
                    autoUpdateRecommended: !COMPATIBILITY.mO(),
1773
                    nativeScrollbarSize: nativeScrollbarSize,
1774
                    nativeScrollbarIsOverlaid: nativeScrollbarIsOverlaid,
1775
                    nativeScrollbarStyling: (function () {
1776
                        var result = false;
1777
                        scrollbarDummyElement.addClass('os-viewport-native-scrollbars-invisible');
1778
                        try {
1779
                            result = (scrollbarDummyElement.css('scrollbar-width') === 'none' && (msie > 9 || !msie)) || window.getComputedStyle(scrollbarDummyElement0, '::-webkit-scrollbar').getPropertyValue('display') === 'none';
1780
                        } catch (ex) { }
1781

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

1787
                        return result;
1788
                    })(),
1789
                    overlayScrollbarDummySize: { x: 30, y: 30 },
1790
                    cssCalc: VENDORS._cssPropertyValue('width', 'calc', '(1px)') || null,
1791
                    restrictedMeasuring: (function () {
1792
                        //https://bugzilla.mozilla.org/show_bug.cgi?id=1439305
1793
                        //since 1.11.0 always false -> fixed via CSS (hopefully)
1794
                        scrollbarDummyElement.css(strOverflow, strHidden);
1795
                        var scrollSize = {
1796
                            w: scrollbarDummyElement0[LEXICON.sW],
1797
                            h: scrollbarDummyElement0[LEXICON.sH]
1798
                        };
1799
                        scrollbarDummyElement.css(strOverflow, 'visible');
1800
                        var scrollSize2 = {
1801
                            w: scrollbarDummyElement0[LEXICON.sW],
1802
                            h: scrollbarDummyElement0[LEXICON.sH]
1803
                        };
1804
                        return (scrollSize.w - scrollSize2.w) !== 0 || (scrollSize.h - scrollSize2.h) !== 0;
1805
                    })(),
1806
                    rtlScrollBehavior: (function () {
1807
                        scrollbarDummyElement.css({ 'overflow-y': strHidden, 'overflow-x': strScroll, 'direction': 'rtl' }).scrollLeft(0);
1808
                        var dummyContainerOffset = scrollbarDummyElement.offset();
1809
                        var dummyContainerChildOffset = dummyContainerChild.offset();
1810
                        //https://github.com/KingSora/OverlayScrollbars/issues/187
1811
                        scrollbarDummyElement.scrollLeft(-999);
1812
                        var dummyContainerChildOffsetAfterScroll = dummyContainerChild.offset();
1813
                        return {
1814
                            //origin direction = determines if the zero scroll position is on the left or right side
1815
                            //'i' means 'invert' (i === true means that the axis must be inverted to be correct)
1816
                            //true = on the left side
1817
                            //false = on the right side
1818
                            i: dummyContainerOffset.left === dummyContainerChildOffset.left,
1819
                            //negative = determines if the maximum scroll is positive or negative
1820
                            //'n' means 'negate' (n === true means that the axis must be negated to be correct)
1821
                            //true = negative
1822
                            //false = positive
1823
                            n: dummyContainerChildOffset.left !== dummyContainerChildOffsetAfterScroll.left
1824
                        };
1825
                    })(),
1826
                    supportTransform: !!VENDORS._cssProperty('transform'),
1827
                    supportTransition: !!VENDORS._cssProperty('transition'),
1828
                    supportPassiveEvents: (function () {
1829
                        var supportsPassive = false;
1830
                        try {
1831
                            window.addEventListener('test', null, Object.defineProperty({}, 'passive', {
1832
                                get: function () {
1833
                                    supportsPassive = true;
1834
                                }
1835
                            }));
1836
                        } catch (e) { }
1837
                        return supportsPassive;
1838
                    })(),
1839
                    supportResizeObserver: !!COMPATIBILITY.rO(),
1840
                    supportMutationObserver: !!COMPATIBILITY.mO()
1841
                });
1842

1843
                scrollbarDummyElement.removeAttr(LEXICON.s).remove();
1844

1845
                //Catch zoom event:
1846
                (function () {
1847
                    if (nativeScrollbarIsOverlaid.x && nativeScrollbarIsOverlaid.y)
1848
                        return;
1849

1850
                    var abs = MATH.abs;
1851
                    var windowWidth = COMPATIBILITY.wW();
1852
                    var windowHeight = COMPATIBILITY.wH();
1853
                    var windowDpr = getWindowDPR();
1854
                    var onResize = function () {
1855
                        if (INSTANCES().length > 0) {
1856
                            var newW = COMPATIBILITY.wW();
1857
                            var newH = COMPATIBILITY.wH();
1858
                            var deltaW = newW - windowWidth;
1859
                            var deltaH = newH - windowHeight;
1860

1861
                            if (deltaW === 0 && deltaH === 0)
1862
                                return;
1863

1864
                            var deltaWRatio = MATH.round(newW / (windowWidth / 100.0));
1865
                            var deltaHRatio = MATH.round(newH / (windowHeight / 100.0));
1866
                            var absDeltaW = abs(deltaW);
1867
                            var absDeltaH = abs(deltaH);
1868
                            var absDeltaWRatio = abs(deltaWRatio);
1869
                            var absDeltaHRatio = abs(deltaHRatio);
1870
                            var newDPR = getWindowDPR();
1871

1872
                            var deltaIsBigger = absDeltaW > 2 && absDeltaH > 2;
1873
                            var difference = !differenceIsBiggerThanOne(absDeltaWRatio, absDeltaHRatio);
1874
                            var dprChanged = newDPR !== windowDpr && windowDpr > 0;
1875
                            var isZoom = deltaIsBigger && difference && dprChanged;
1876
                            var oldScrollbarSize = _base.nativeScrollbarSize;
1877
                            var newScrollbarSize;
1878

1879
                            if (isZoom) {
1880
                                bodyElement.append(scrollbarDummyElement);
1881
                                newScrollbarSize = _base.nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement[0]);
1882
                                scrollbarDummyElement.remove();
1883
                                if (oldScrollbarSize.x !== newScrollbarSize.x || oldScrollbarSize.y !== newScrollbarSize.y) {
1884
                                    FRAMEWORK.each(INSTANCES(), function () {
1885
                                        if (INSTANCES(this))
1886
                                            INSTANCES(this).update('zoom');
1887
                                    });
1888
                                }
1889
                            }
1890

1891
                            windowWidth = newW;
1892
                            windowHeight = newH;
1893
                            windowDpr = newDPR;
1894
                        }
1895
                    };
1896

1897
                    function differenceIsBiggerThanOne(valOne, valTwo) {
1898
                        var absValOne = abs(valOne);
1899
                        var absValTwo = abs(valTwo);
1900
                        return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
1901
                    }
1902

1903
                    function getWindowDPR() {
1904
                        var dDPI = window.screen.deviceXDPI || 0;
1905
                        var sDPI = window.screen.logicalXDPI || 1;
1906
                        return window.devicePixelRatio || (dDPI / sDPI);
1907
                    }
1908

1909
                    FRAMEWORK(window).on('resize', onResize);
1910
                })();
1911

1912
                function calcNativeScrollbarSize(measureElement) {
1913
                    return {
1914
                        x: measureElement[LEXICON.oH] - measureElement[LEXICON.cH],
1915
                        y: measureElement[LEXICON.oW] - measureElement[LEXICON.cW]
1916
                    };
1917
                }
1918
            }
1919

1920
            /**
1921
             * The object which manages the auto update loop for all OverlayScrollbars objects. This object is initialized only once: if the first OverlayScrollbars object gets initialized.
1922
             * @constructor
1923
             */
1924
            function OverlayScrollbarsAutoUpdateLoop(globals) {
1925
                var _base = this;
1926
                var _inArray = FRAMEWORK.inArray;
1927
                var _getNow = COMPATIBILITY.now;
1928
                var _strAutoUpdate = 'autoUpdate';
1929
                var _strAutoUpdateInterval = _strAutoUpdate + 'Interval';
1930
                var _strLength = LEXICON.l;
1931
                var _loopingInstances = [];
1932
                var _loopingInstancesIntervalCache = [];
1933
                var _loopIsActive = false;
1934
                var _loopIntervalDefault = 33;
1935
                var _loopInterval = _loopIntervalDefault;
1936
                var _loopTimeOld = _getNow();
1937
                var _loopID;
1938

1939

1940
                /**
1941
                 * The auto update loop which will run every 50 milliseconds or less if the update interval of a instance is lower than 50 milliseconds.
1942
                 */
1943
                var loop = function () {
1944
                    if (_loopingInstances[_strLength] > 0 && _loopIsActive) {
1945
                        _loopID = COMPATIBILITY.rAF()(function () {
1946
                            loop();
1947
                        });
1948
                        var timeNew = _getNow();
1949
                        var timeDelta = timeNew - _loopTimeOld;
1950
                        var lowestInterval;
1951
                        var instance;
1952
                        var instanceOptions;
1953
                        var instanceAutoUpdateAllowed;
1954
                        var instanceAutoUpdateInterval;
1955
                        var now;
1956

1957
                        if (timeDelta > _loopInterval) {
1958
                            _loopTimeOld = timeNew - (timeDelta % _loopInterval);
1959
                            lowestInterval = _loopIntervalDefault;
1960
                            for (var i = 0; i < _loopingInstances[_strLength]; i++) {
1961
                                instance = _loopingInstances[i];
1962
                                if (instance !== undefined) {
1963
                                    instanceOptions = instance.options();
1964
                                    instanceAutoUpdateAllowed = instanceOptions[_strAutoUpdate];
1965
                                    instanceAutoUpdateInterval = MATH.max(1, instanceOptions[_strAutoUpdateInterval]);
1966
                                    now = _getNow();
1967

1968
                                    if ((instanceAutoUpdateAllowed === true || instanceAutoUpdateAllowed === null) && (now - _loopingInstancesIntervalCache[i]) > instanceAutoUpdateInterval) {
1969
                                        instance.update('auto');
1970
                                        _loopingInstancesIntervalCache[i] = new Date(now += instanceAutoUpdateInterval);
1971
                                    }
1972

1973
                                    lowestInterval = MATH.max(1, MATH.min(lowestInterval, instanceAutoUpdateInterval));
1974
                                }
1975
                            }
1976
                            _loopInterval = lowestInterval;
1977
                        }
1978
                    } else {
1979
                        _loopInterval = _loopIntervalDefault;
1980
                    }
1981
                };
1982

1983
                /**
1984
                 * Add OverlayScrollbars instance to the auto update loop. Only successful if the instance isn't already added.
1985
                 * @param instance The instance which shall be updated in a loop automatically.
1986
                 */
1987
                _base.add = function (instance) {
1988
                    if (_inArray(instance, _loopingInstances) === -1) {
1989
                        _loopingInstances.push(instance);
1990
                        _loopingInstancesIntervalCache.push(_getNow());
1991
                        if (_loopingInstances[_strLength] > 0 && !_loopIsActive) {
1992
                            _loopIsActive = true;
1993
                            globals.autoUpdateLoop = _loopIsActive;
1994
                            loop();
1995
                        }
1996
                    }
1997
                };
1998

1999
                /**
2000
                 * Remove OverlayScrollbars instance from the auto update loop. Only successful if the instance was added before.
2001
                 * @param instance The instance which shall be updated in a loop automatically.
2002
                 */
2003
                _base.remove = function (instance) {
2004
                    var index = _inArray(instance, _loopingInstances);
2005
                    if (index > -1) {
2006
                        //remove from loopingInstances list
2007
                        _loopingInstancesIntervalCache.splice(index, 1);
2008
                        _loopingInstances.splice(index, 1);
2009

2010
                        //correct update loop behavior
2011
                        if (_loopingInstances[_strLength] === 0 && _loopIsActive) {
2012
                            _loopIsActive = false;
2013
                            globals.autoUpdateLoop = _loopIsActive;
2014
                            if (_loopID !== undefined) {
2015
                                COMPATIBILITY.cAF()(_loopID);
2016
                                _loopID = -1;
2017
                            }
2018
                        }
2019
                    }
2020
                };
2021
            }
2022

2023
            /**
2024
             * A object which manages the scrollbars visibility of the target element.
2025
             * @param pluginTargetElement The element from which the scrollbars shall be hidden.
2026
             * @param options The custom options.
2027
             * @param extensions The custom extensions.
2028
             * @param globals
2029
             * @param autoUpdateLoop
2030
             * @returns {*}
2031
             * @constructor
2032
             */
2033
            function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) {
2034
                //shortcuts
2035
                var type = COMPATIBILITY.type;
2036
                var inArray = FRAMEWORK.inArray;
2037
                var each = FRAMEWORK.each;
2038

2039
                //make correct instanceof
2040
                var _base = new _plugin();
2041
                var _frameworkProto = FRAMEWORK[LEXICON.p];
2042

2043
                //if passed element is no HTML element: skip and return
2044
                if (!isHTMLElement(pluginTargetElement))
2045
                    return;
2046

2047
                //if passed element is already initialized: set passed options if there are any and return its instance
2048
                if (INSTANCES(pluginTargetElement)) {
2049
                    var inst = INSTANCES(pluginTargetElement);
2050
                    inst.options(options);
2051
                    return inst;
2052
                }
2053

2054
                //globals:
2055
                var _nativeScrollbarIsOverlaid;
2056
                var _overlayScrollbarDummySize;
2057
                var _rtlScrollBehavior;
2058
                var _autoUpdateRecommended;
2059
                var _msieVersion;
2060
                var _nativeScrollbarStyling;
2061
                var _cssCalc;
2062
                var _nativeScrollbarSize;
2063
                var _supportTransition;
2064
                var _supportTransform;
2065
                var _supportPassiveEvents;
2066
                var _supportResizeObserver;
2067
                var _supportMutationObserver;
2068
                var _restrictedMeasuring;
2069

2070
                //general readonly:
2071
                var _initialized;
2072
                var _destroyed;
2073
                var _isTextarea;
2074
                var _isBody;
2075
                var _documentMixed;
2076
                var _domExists;
2077

2078
                //general:
2079
                var _isBorderBox;
2080
                var _sizeAutoObserverAdded;
2081
                var _paddingX;
2082
                var _paddingY;
2083
                var _borderX;
2084
                var _borderY;
2085
                var _marginX;
2086
                var _marginY;
2087
                var _isRTL;
2088
                var _sleeping;
2089
                var _contentBorderSize = {};
2090
                var _scrollHorizontalInfo = {};
2091
                var _scrollVerticalInfo = {};
2092
                var _viewportSize = {};
2093
                var _nativeScrollbarMinSize = {};
2094

2095
                //naming:	
2096
                var _strMinusHidden = '-hidden';
2097
                var _strMarginMinus = 'margin-';
2098
                var _strPaddingMinus = 'padding-';
2099
                var _strBorderMinus = 'border-';
2100
                var _strTop = 'top';
2101
                var _strRight = 'right';
2102
                var _strBottom = 'bottom';
2103
                var _strLeft = 'left';
2104
                var _strMinMinus = 'min-';
2105
                var _strMaxMinus = 'max-';
2106
                var _strWidth = 'width';
2107
                var _strHeight = 'height';
2108
                var _strFloat = 'float';
2109
                var _strEmpty = '';
2110
                var _strAuto = 'auto';
2111
                var _strSync = 'sync';
2112
                var _strScroll = 'scroll';
2113
                var _strHundredPercent = '100%';
2114
                var _strX = 'x';
2115
                var _strY = 'y';
2116
                var _strDot = '.';
2117
                var _strSpace = ' ';
2118
                var _strScrollbar = 'scrollbar';
2119
                var _strMinusHorizontal = '-horizontal';
2120
                var _strMinusVertical = '-vertical';
2121
                var _strScrollLeft = _strScroll + 'Left';
2122
                var _strScrollTop = _strScroll + 'Top';
2123
                var _strMouseTouchDownEvent = 'mousedown touchstart';
2124
                var _strMouseTouchUpEvent = 'mouseup touchend touchcancel';
2125
                var _strMouseTouchMoveEvent = 'mousemove touchmove';
2126
                var _strMouseEnter = 'mouseenter';
2127
                var _strMouseLeave = 'mouseleave';
2128
                var _strKeyDownEvent = 'keydown';
2129
                var _strKeyUpEvent = 'keyup';
2130
                var _strSelectStartEvent = 'selectstart';
2131
                var _strTransitionEndEvent = 'transitionend webkitTransitionEnd oTransitionEnd';
2132
                var _strResizeObserverProperty = '__overlayScrollbarsRO__';
2133

2134
                //class names:	
2135
                var _cassNamesPrefix = 'os-';
2136
                var _classNameHTMLElement = _cassNamesPrefix + 'html';
2137
                var _classNameHostElement = _cassNamesPrefix + 'host';
2138
                var _classNameHostElementForeign = _classNameHostElement + '-foreign';
2139
                var _classNameHostTextareaElement = _classNameHostElement + '-textarea';
2140
                var _classNameHostScrollbarHorizontalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusHorizontal + _strMinusHidden;
2141
                var _classNameHostScrollbarVerticalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusVertical + _strMinusHidden;
2142
                var _classNameHostTransition = _classNameHostElement + '-transition';
2143
                var _classNameHostRTL = _classNameHostElement + '-rtl';
2144
                var _classNameHostResizeDisabled = _classNameHostElement + '-resize-disabled';
2145
                var _classNameHostScrolling = _classNameHostElement + '-scrolling';
2146
                var _classNameHostOverflow = _classNameHostElement + '-overflow';
2147
                var _classNameHostOverflow = _classNameHostElement + '-overflow';
2148
                var _classNameHostOverflowX = _classNameHostOverflow + '-x';
2149
                var _classNameHostOverflowY = _classNameHostOverflow + '-y';
2150
                var _classNameTextareaElement = _cassNamesPrefix + 'textarea';
2151
                var _classNameTextareaCoverElement = _classNameTextareaElement + '-cover';
2152
                var _classNamePaddingElement = _cassNamesPrefix + 'padding';
2153
                var _classNameViewportElement = _cassNamesPrefix + 'viewport';
2154
                var _classNameViewportNativeScrollbarsInvisible = _classNameViewportElement + '-native-scrollbars-invisible';
2155
                var _classNameViewportNativeScrollbarsOverlaid = _classNameViewportElement + '-native-scrollbars-overlaid';
2156
                var _classNameContentElement = _cassNamesPrefix + 'content';
2157
                var _classNameContentArrangeElement = _cassNamesPrefix + 'content-arrange';
2158
                var _classNameContentGlueElement = _cassNamesPrefix + 'content-glue';
2159
                var _classNameSizeAutoObserverElement = _cassNamesPrefix + 'size-auto-observer';
2160
                var _classNameResizeObserverElement = _cassNamesPrefix + 'resize-observer';
2161
                var _classNameResizeObserverItemElement = _cassNamesPrefix + 'resize-observer-item';
2162
                var _classNameResizeObserverItemFinalElement = _classNameResizeObserverItemElement + '-final';
2163
                var _classNameTextInherit = _cassNamesPrefix + 'text-inherit';
2164
                var _classNameScrollbar = _cassNamesPrefix + _strScrollbar;
2165
                var _classNameScrollbarTrack = _classNameScrollbar + '-track';
2166
                var _classNameScrollbarTrackOff = _classNameScrollbarTrack + '-off';
2167
                var _classNameScrollbarHandle = _classNameScrollbar + '-handle';
2168
                var _classNameScrollbarHandleOff = _classNameScrollbarHandle + '-off';
2169
                var _classNameScrollbarUnusable = _classNameScrollbar + '-unusable';
2170
                var _classNameScrollbarAutoHidden = _classNameScrollbar + '-' + _strAuto + _strMinusHidden;
2171
                var _classNameScrollbarCorner = _classNameScrollbar + '-corner';
2172
                var _classNameScrollbarCornerResize = _classNameScrollbarCorner + '-resize';
2173
                var _classNameScrollbarCornerResizeB = _classNameScrollbarCornerResize + '-both';
2174
                var _classNameScrollbarCornerResizeH = _classNameScrollbarCornerResize + _strMinusHorizontal;
2175
                var _classNameScrollbarCornerResizeV = _classNameScrollbarCornerResize + _strMinusVertical;
2176
                var _classNameScrollbarHorizontal = _classNameScrollbar + _strMinusHorizontal;
2177
                var _classNameScrollbarVertical = _classNameScrollbar + _strMinusVertical;
2178
                var _classNameDragging = _cassNamesPrefix + 'dragging';
2179
                var _classNameThemeNone = _cassNamesPrefix + 'theme-none';
2180
                var _classNamesDynamicDestroy = [
2181
                    _classNameViewportNativeScrollbarsInvisible,
2182
                    _classNameViewportNativeScrollbarsOverlaid,
2183
                    _classNameScrollbarTrackOff,
2184
                    _classNameScrollbarHandleOff,
2185
                    _classNameScrollbarUnusable,
2186
                    _classNameScrollbarAutoHidden,
2187
                    _classNameScrollbarCornerResize,
2188
                    _classNameScrollbarCornerResizeB,
2189
                    _classNameScrollbarCornerResizeH,
2190
                    _classNameScrollbarCornerResizeV,
2191
                    _classNameDragging].join(_strSpace);
2192

2193
                //callbacks:	
2194
                var _callbacksInitQeueue = [];
2195

2196
                //attrs viewport shall inherit from target	
2197
                var _viewportAttrsFromTarget = [LEXICON.ti];
2198

2199
                //options:	
2200
                var _defaultOptions;
2201
                var _currentOptions;
2202
                var _currentPreparedOptions;
2203

2204
                //extensions:	
2205
                var _extensions = {};
2206
                var _extensionsPrivateMethods = 'added removed on contract';
2207

2208
                //update	
2209
                var _lastUpdateTime;
2210
                var _swallowedUpdateHints = {};
2211
                var _swallowedUpdateTimeout;
2212
                var _swallowUpdateLag = 42;
2213
                var _updateOnLoadEventName = 'load';
2214
                var _updateOnLoadElms = [];
2215

2216
                //DOM elements:	
2217
                var _windowElement;
2218
                var _documentElement;
2219
                var _htmlElement;
2220
                var _bodyElement;
2221
                var _targetElement;                     //the target element of this OverlayScrollbars object	
2222
                var _hostElement;                       //the host element of this OverlayScrollbars object -> may be the same as targetElement	
2223
                var _sizeAutoObserverElement;           //observes size auto changes	
2224
                var _sizeObserverElement;               //observes size and padding changes	
2225
                var _paddingElement;                    //manages the padding	
2226
                var _viewportElement;                   //is the viewport of our scrollbar model	
2227
                var _contentElement;                    //the element which holds the content	
2228
                var _contentArrangeElement;             //is needed for correct sizing of the content element (only if native scrollbars are overlays)	
2229
                var _contentGlueElement;                //has always the size of the content element	
2230
                var _textareaCoverElement;              //only applied if target is a textarea element. Used for correct size calculation and for prevention of uncontrolled scrolling	
2231
                var _scrollbarCornerElement;
2232
                var _scrollbarHorizontalElement;
2233
                var _scrollbarHorizontalTrackElement;
2234
                var _scrollbarHorizontalHandleElement;
2235
                var _scrollbarVerticalElement;
2236
                var _scrollbarVerticalTrackElement;
2237
                var _scrollbarVerticalHandleElement;
2238
                var _windowElementNative;
2239
                var _documentElementNative;
2240
                var _targetElementNative;
2241
                var _hostElementNative;
2242
                var _sizeAutoObserverElementNative;
2243
                var _sizeObserverElementNative;
2244
                var _paddingElementNative;
2245
                var _viewportElementNative;
2246
                var _contentElementNative;
2247

2248
                //Cache:	
2249
                var _hostSizeCache;
2250
                var _contentScrollSizeCache;
2251
                var _arrangeContentSizeCache;
2252
                var _hasOverflowCache;
2253
                var _hideOverflowCache;
2254
                var _widthAutoCache;
2255
                var _heightAutoCache;
2256
                var _cssBoxSizingCache;
2257
                var _cssPaddingCache;
2258
                var _cssBorderCache;
2259
                var _cssMarginCache;
2260
                var _cssDirectionCache;
2261
                var _cssDirectionDetectedCache;
2262
                var _paddingAbsoluteCache;
2263
                var _clipAlwaysCache;
2264
                var _contentGlueSizeCache;
2265
                var _overflowBehaviorCache;
2266
                var _overflowAmountCache;
2267
                var _ignoreOverlayScrollbarHidingCache;
2268
                var _autoUpdateCache;
2269
                var _sizeAutoCapableCache;
2270
                var _contentElementScrollSizeChangeDetectedCache;
2271
                var _hostElementSizeChangeDetectedCache;
2272
                var _scrollbarsVisibilityCache;
2273
                var _scrollbarsAutoHideCache;
2274
                var _scrollbarsClickScrollingCache;
2275
                var _scrollbarsDragScrollingCache;
2276
                var _resizeCache;
2277
                var _normalizeRTLCache;
2278
                var _classNameCache;
2279
                var _oldClassName;
2280
                var _textareaAutoWrappingCache;
2281
                var _textareaInfoCache;
2282
                var _textareaSizeCache;
2283
                var _textareaDynHeightCache;
2284
                var _textareaDynWidthCache;
2285
                var _bodyMinSizeCache;
2286
                var _updateAutoCache = {};
2287

2288
                //MutationObserver:	
2289
                var _mutationObserverHost;
2290
                var _mutationObserverContent;
2291
                var _mutationObserverHostCallback;
2292
                var _mutationObserverContentCallback;
2293
                var _mutationObserversConnected;
2294
                var _mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows'];
2295
                var _mutationObserverAttrsHost = [LEXICON.i, LEXICON.c, LEXICON.s, 'open'].concat(_viewportAttrsFromTarget);
2296

2297
                //events:	
2298
                var _destroyEvents = [];
2299

2300
                //textarea:	
2301
                var _textareaHasFocus;
2302

2303
                //scrollbars:	
2304
                var _scrollbarsAutoHideTimeoutId;
2305
                var _scrollbarsAutoHideMoveTimeoutId;
2306
                var _scrollbarsAutoHideDelay;
2307
                var _scrollbarsAutoHideNever;
2308
                var _scrollbarsAutoHideScroll;
2309
                var _scrollbarsAutoHideMove;
2310
                var _scrollbarsAutoHideLeave;
2311
                var _scrollbarsHandleHovered;
2312
                var _scrollbarsHandlesDefineScrollPos;
2313

2314
                //resize	
2315
                var _resizeNone;
2316
                var _resizeBoth;
2317
                var _resizeHorizontal;
2318
                var _resizeVertical;
2319

2320

2321
                //==== Event Listener ====//	
2322

2323
                /**	
2324
                 * Adds or removes a event listener from the given element. 	
2325
                 * @param element The element to which the event listener shall be applied or removed.	
2326
                 * @param eventNames The name(s) of the events.	
2327
                 * @param listener The method which shall be called.	
2328
                 * @param remove True if the handler shall be removed, false or undefined if the handler shall be added.	
2329
                 * @param passiveOrOptions The options for the event.
2330
                 */
2331
                function setupResponsiveEventListener(element, eventNames, listener, remove, passiveOrOptions) {
2332
                    var collected = COMPATIBILITY.isA(eventNames) && COMPATIBILITY.isA(listener);
2333
                    var method = remove ? 'removeEventListener' : 'addEventListener';
2334
                    var onOff = remove ? 'off' : 'on';
2335
                    var events = collected ? false : eventNames.split(_strSpace)
2336
                    var i = 0;
2337

2338
                    var passiveOrOptionsIsObj = FRAMEWORK.isPlainObject(passiveOrOptions);
2339
                    var passive = (_supportPassiveEvents && (passiveOrOptionsIsObj ? (passiveOrOptions._passive) : passiveOrOptions)) || false;
2340
                    var capture = passiveOrOptionsIsObj && (passiveOrOptions._capture || false);
2341
                    var nativeParam = _supportPassiveEvents ? {
2342
                        passive: passive,
2343
                        capture: capture,
2344
                    } : capture;
2345

2346
                    if (collected) {
2347
                        for (; i < eventNames[LEXICON.l]; i++)
2348
                            setupResponsiveEventListener(element, eventNames[i], listener[i], remove, passiveOrOptions);
2349
                    }
2350
                    else {
2351
                        for (; i < events[LEXICON.l]; i++) {
2352
                            if(_supportPassiveEvents) {
2353
                                element[0][method](events[i], listener, nativeParam);
2354
                            }
2355
                            else {
2356
                                element[onOff](events[i], listener);
2357
                            }     
2358
                        }
2359
                    }
2360
                }
2361

2362

2363
                function addDestroyEventListener(element, eventNames, listener, passive) {
2364
                    setupResponsiveEventListener(element, eventNames, listener, false, passive);
2365
                    _destroyEvents.push(COMPATIBILITY.bind(setupResponsiveEventListener, 0, element, eventNames, listener, true, passive));
2366
                }
2367

2368
                //==== Resize Observer ====//
2369

2370
                /**
2371
                 * Adds or removes a resize observer from the given element.
2372
                 * @param targetElement The element to which the resize observer shall be added or removed.
2373
                 * @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change or false / undefined if the resizeObserver shall be removed.
2374
                 */
2375
                function setupResizeObserver(targetElement, onElementResizedCallback) {
2376
                    if (targetElement) {
2377
                        var resizeObserver = COMPATIBILITY.rO();
2378
                        var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart';
2379
                        var strChildNodes = 'childNodes';
2380
                        var constScroll = 3333333;
2381
                        var callback = function () {
2382
                            targetElement[_strScrollTop](constScroll)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll : constScroll);
2383
                            onElementResizedCallback();
2384
                        };
2385
                        //add resize observer:
2386
                        if (onElementResizedCallback) {
2387
                            if (_supportResizeObserver) {
2388
                                var element = targetElement.addClass('observed').append(generateDiv(_classNameResizeObserverElement)).contents()[0];
2389
                                var observer = element[_strResizeObserverProperty] = new resizeObserver(callback);
2390
                                observer.observe(element);
2391
                            }
2392
                            else {
2393
                                if (_msieVersion > 9 || !_autoUpdateRecommended) {
2394
                                    targetElement.prepend(
2395
                                        generateDiv(_classNameResizeObserverElement,
2396
                                            generateDiv({ c: _classNameResizeObserverItemElement, dir: 'ltr' },
2397
                                                generateDiv(_classNameResizeObserverItemElement,
2398
                                                    generateDiv(_classNameResizeObserverItemFinalElement)
2399
                                                ) +
2400
                                                generateDiv(_classNameResizeObserverItemElement,
2401
                                                    generateDiv({ c: _classNameResizeObserverItemFinalElement, style: 'width: 200%; height: 200%' })
2402
                                                )
2403
                                            )
2404
                                        )
2405
                                    );
2406

2407
                                    var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0];
2408
                                    var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]);
2409
                                    var expandElement = FRAMEWORK(observerElement[strChildNodes][0]);
2410
                                    var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]);
2411
                                    var widthCache = observerElement[LEXICON.oW];
2412
                                    var heightCache = observerElement[LEXICON.oH];
2413
                                    var isDirty;
2414
                                    var rAFId;
2415
                                    var currWidth;
2416
                                    var currHeight;
2417
                                    var factor = 2;
2418
                                    var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!!
2419
                                    var reset = function () {
2420
                                        /*
2421
                                         var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
2422
                                         var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
2423
                                         var expandChildCSS = {};
2424
                                         expandChildCSS[_strWidth] = sizeResetWidth;
2425
                                         expandChildCSS[_strHeight] = sizeResetHeight;
2426
                                         expandElementChild.css(expandChildCSS);
2427

2428

2429
                                         expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
2430
                                         shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
2431
                                         */
2432
                                        expandElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);
2433
                                        shrinkElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);
2434
                                    };
2435
                                    var onResized = function () {
2436
                                        rAFId = 0;
2437
                                        if (!isDirty)
2438
                                            return;
2439

2440
                                        widthCache = currWidth;
2441
                                        heightCache = currHeight;
2442
                                        callback();
2443
                                    };
2444
                                    var onScroll = function (event) {
2445
                                        currWidth = observerElement[LEXICON.oW];
2446
                                        currHeight = observerElement[LEXICON.oH];
2447
                                        isDirty = currWidth != widthCache || currHeight != heightCache;
2448

2449
                                        if (event && isDirty && !rAFId) {
2450
                                            COMPATIBILITY.cAF()(rAFId);
2451
                                            rAFId = COMPATIBILITY.rAF()(onResized);
2452
                                        }
2453
                                        else if (!event)
2454
                                            onResized();
2455

2456
                                        reset();
2457
                                        if (event) {
2458
                                            COMPATIBILITY.prvD(event);
2459
                                            COMPATIBILITY.stpP(event);
2460
                                        }
2461
                                        return false;
2462
                                    };
2463
                                    var expandChildCSS = {};
2464
                                    var observerElementCSS = {};
2465

2466
                                    setTopRightBottomLeft(observerElementCSS, _strEmpty, [
2467
                                        -((nativeScrollbarSize.y + 1) * factor),
2468
                                        nativeScrollbarSize.x * -factor,
2469
                                        nativeScrollbarSize.y * -factor,
2470
                                        -((nativeScrollbarSize.x + 1) * factor)
2471
                                    ]);
2472

2473
                                    FRAMEWORK(observerElement).css(observerElementCSS);
2474
                                    expandElement.on(_strScroll, onScroll);
2475
                                    shrinkElement.on(_strScroll, onScroll);
2476
                                    targetElement.on(strAnimationStartEvent, function () {
2477
                                        onScroll(false);
2478
                                    });
2479
                                    //lets assume that the divs will never be that large and a constant value is enough
2480
                                    expandChildCSS[_strWidth] = constScroll;
2481
                                    expandChildCSS[_strHeight] = constScroll;
2482
                                    expandElementChild.css(expandChildCSS);
2483

2484
                                    reset();
2485
                                }
2486
                                else {
2487
                                    var attachEvent = _documentElementNative.attachEvent;
2488
                                    var isIE = _msieVersion !== undefined;
2489
                                    if (attachEvent) {
2490
                                        targetElement.prepend(generateDiv(_classNameResizeObserverElement));
2491
                                        findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback);
2492
                                    }
2493
                                    else {
2494
                                        var obj = _documentElementNative.createElement(TYPES.o);
2495
                                        obj.setAttribute(LEXICON.ti, '-1');
2496
                                        obj.setAttribute(LEXICON.c, _classNameResizeObserverElement);
2497
                                        obj.onload = function () {
2498
                                            var wnd = this.contentDocument.defaultView;
2499
                                            wnd.addEventListener('resize', callback);
2500
                                            wnd.document.documentElement.style.display = 'none';
2501
                                        };
2502
                                        obj.type = 'text/html';
2503
                                        if (isIE)
2504
                                            targetElement.prepend(obj);
2505
                                        obj.data = 'about:blank';
2506
                                        if (!isIE)
2507
                                            targetElement.prepend(obj);
2508
                                        targetElement.on(strAnimationStartEvent, callback);
2509
                                    }
2510
                                }
2511
                            }
2512

2513
                            if (targetElement[0] === _sizeObserverElementNative) {
2514
                                var directionChanged = function () {
2515
                                    var dir = _hostElement.css('direction');
2516
                                    var css = {};
2517
                                    var scrollLeftValue = 0;
2518
                                    var result = false;
2519
                                    if (dir !== _cssDirectionDetectedCache) {
2520
                                        if (dir === 'ltr') {
2521
                                            css[_strLeft] = 0;
2522
                                            css[_strRight] = _strAuto;
2523
                                            scrollLeftValue = constScroll;
2524
                                        }
2525
                                        else {
2526
                                            css[_strLeft] = _strAuto;
2527
                                            css[_strRight] = 0;
2528
                                            scrollLeftValue = _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll;
2529
                                        }
2530
                                        //execution order is important for IE!!!
2531
                                        _sizeObserverElement.children().eq(0).css(css);
2532
                                        _sizeObserverElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constScroll);
2533
                                        _cssDirectionDetectedCache = dir;
2534
                                        result = true;
2535
                                    }
2536
                                    return result;
2537
                                };
2538
                                directionChanged();
2539
                                addDestroyEventListener(targetElement, _strScroll, function (event) {
2540
                                    if (directionChanged())
2541
                                        update();
2542
                                    COMPATIBILITY.prvD(event);
2543
                                    COMPATIBILITY.stpP(event);
2544
                                    return false;
2545
                                });
2546
                            }
2547
                        }
2548
                        //remove resize observer:
2549
                        else {
2550
                            if (_supportResizeObserver) {
2551
                                var element = targetElement.contents()[0];
2552
                                var resizeObserverObj = element[_strResizeObserverProperty];
2553
                                if (resizeObserverObj) {
2554
                                    resizeObserverObj.disconnect();
2555
                                    delete element[_strResizeObserverProperty];
2556
                                }
2557
                            }
2558
                            else {
2559
                                remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0));
2560
                            }
2561
                        }
2562
                    }
2563
                }
2564

2565
                /**
2566
                 * Freezes or unfreezes the given resize observer.
2567
                 * @param targetElement The element to which the target resize observer is applied.
2568
                 * @param freeze True if the resize observer shall be frozen, false otherwise.
2569
                 
2570
                function freezeResizeObserver(targetElement, freeze) {
2571
                    if (targetElement !== undefined) {
2572
                        if(freeze) {
2573
                            if (_supportResizeObserver) {
2574
                                var element = targetElement.contents()[0];
2575
                                element[_strResizeObserverProperty].unobserve(element);
2576
                            }
2577
                            else {
2578
                                targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0);
2579
                                var w = targetElement.css(_strWidth);
2580
                                var h = targetElement.css(_strHeight);
2581
                                var css = {};
2582
                                css[_strWidth] = w;
2583
                                css[_strHeight] = h;
2584
                                targetElement.css(css);
2585
                            }
2586
                        }
2587
                        else {
2588
                            if (_supportResizeObserver) {
2589
                                var element = targetElement.contents()[0];
2590
                                element[_strResizeObserverProperty].observe(element);
2591
                            }
2592
                            else {
2593
                                var css = { };
2594
                                css[_strHeight] = _strEmpty;
2595
                                css[_strWidth] = _strEmpty;
2596
                                targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css);
2597
                            }
2598
                        }
2599
                    }
2600
                }
2601
                */
2602

2603

2604
                //==== Mutation Observers ====//
2605

2606
                /**
2607
                 * Creates MutationObservers for the host and content Element if they are supported.
2608
                 */
2609
                function createMutationObservers() {
2610
                    if (_supportMutationObserver) {
2611
                        var mutationObserverContentLag = 11;
2612
                        var mutationObserver = COMPATIBILITY.mO();
2613
                        var contentLastUpdate = COMPATIBILITY.now();
2614
                        var mutationTarget;
2615
                        var mutationAttrName;
2616
                        var mutationIsClass;
2617
                        var oldMutationVal;
2618
                        var newClassVal;
2619
                        var hostClassNameRegex;
2620
                        var contentTimeout;
2621
                        var now;
2622
                        var sizeAuto;
2623
                        var action;
2624

2625
                        _mutationObserverHostCallback = function (mutations) {
2626

2627
                            var doUpdate = false;
2628
                            var doUpdateForce = false;
2629
                            var mutation;
2630
                            var mutatedAttrs = [];
2631

2632
                            if (_initialized && !_sleeping) {
2633
                                each(mutations, function () {
2634
                                    mutation = this;
2635
                                    mutationTarget = mutation.target;
2636
                                    mutationAttrName = mutation.attributeName;
2637
                                    mutationIsClass = mutationAttrName === LEXICON.c;
2638
                                    oldMutationVal = mutation.oldValue;
2639
                                    newClassVal = mutationTarget.className;
2640

2641
                                    if (_domExists && mutationIsClass && !doUpdateForce) {
2642
                                        // if old class value contains _classNameHostElementForeign and new class value doesn't
2643
                                        if (oldMutationVal.indexOf(_classNameHostElementForeign) > -1 && newClassVal.indexOf(_classNameHostElementForeign) < 0) {
2644
                                            hostClassNameRegex = createHostClassNameRegExp(true);
2645
                                            _hostElementNative.className = newClassVal.split(_strSpace).concat(oldMutationVal.split(_strSpace).filter(function (name) {
2646
                                                return name.match(hostClassNameRegex);
2647
                                            })).join(_strSpace);
2648
                                            doUpdate = doUpdateForce = true;
2649
                                        }
2650
                                    }
2651

2652
                                    if (!doUpdate) {
2653
                                        doUpdate = mutationIsClass
2654
                                            ? hostClassNamesChanged(oldMutationVal, newClassVal)
2655
                                            : mutationAttrName === LEXICON.s
2656
                                                ? oldMutationVal !== mutationTarget[LEXICON.s].cssText
2657
                                                : true;
2658
                                    }
2659

2660
                                    mutatedAttrs.push(mutationAttrName);
2661
                                });
2662

2663
                                updateViewportAttrsFromTarget(mutatedAttrs);
2664

2665
                                if (doUpdate)
2666
                                    _base.update(doUpdateForce || _strAuto);
2667
                            }
2668
                            return doUpdate;
2669
                        };
2670
                        _mutationObserverContentCallback = function (mutations) {
2671
                            var doUpdate = false;
2672
                            var mutation;
2673

2674
                            if (_initialized && !_sleeping) {
2675
                                each(mutations, function () {
2676
                                    mutation = this;
2677
                                    doUpdate = isUnknownMutation(mutation);
2678
                                    return !doUpdate;
2679
                                });
2680

2681
                                if (doUpdate) {
2682
                                    now = COMPATIBILITY.now();
2683
                                    sizeAuto = (_heightAutoCache || _widthAutoCache);
2684
                                    action = function () {
2685
                                        if (!_destroyed) {
2686
                                            contentLastUpdate = now;
2687

2688
                                            //if cols, rows or wrap attr was changed
2689
                                            if (_isTextarea)
2690
                                                textareaUpdate();
2691

2692
                                            if (sizeAuto)
2693
                                                update();
2694
                                            else
2695
                                                _base.update(_strAuto);
2696
                                        }
2697
                                    };
2698
                                    clearTimeout(contentTimeout);
2699
                                    if (mutationObserverContentLag <= 0 || now - contentLastUpdate > mutationObserverContentLag || !sizeAuto)
2700
                                        action();
2701
                                    else
2702
                                        contentTimeout = setTimeout(action, mutationObserverContentLag);
2703
                                }
2704
                            }
2705
                            return doUpdate;
2706
                        }
2707

2708
                        _mutationObserverHost = new mutationObserver(_mutationObserverHostCallback);
2709
                        _mutationObserverContent = new mutationObserver(_mutationObserverContentCallback);
2710
                    }
2711
                }
2712

2713
                /**
2714
                 * Connects the MutationObservers if they are supported.
2715
                 */
2716
                function connectMutationObservers() {
2717
                    if (_supportMutationObserver && !_mutationObserversConnected) {
2718
                        _mutationObserverHost.observe(_hostElementNative, {
2719
                            attributes: true,
2720
                            attributeOldValue: true,
2721
                            attributeFilter: _mutationObserverAttrsHost
2722
                        });
2723

2724
                        _mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, {
2725
                            attributes: true,
2726
                            attributeOldValue: true,
2727
                            subtree: !_isTextarea,
2728
                            childList: !_isTextarea,
2729
                            characterData: !_isTextarea,
2730
                            attributeFilter: _isTextarea ? _mutationObserverAttrsTextarea : _mutationObserverAttrsHost
2731
                        });
2732

2733
                        _mutationObserversConnected = true;
2734
                    }
2735
                }
2736

2737
                /**
2738
                 * Disconnects the MutationObservers if they are supported.
2739
                 */
2740
                function disconnectMutationObservers() {
2741
                    if (_supportMutationObserver && _mutationObserversConnected) {
2742
                        _mutationObserverHost.disconnect();
2743
                        _mutationObserverContent.disconnect();
2744

2745
                        _mutationObserversConnected = false;
2746
                    }
2747
                }
2748

2749

2750
                //==== Events of elements ====//
2751

2752
                /**
2753
                 * This method gets called every time the host element gets resized. IMPORTANT: Padding changes are detected too!!
2754
                 * It refreshes the hostResizedEventArgs and the hostSizeResizeCache.
2755
                 * If there are any size changes, the update method gets called.
2756
                 */
2757
                function hostOnResized() {
2758
                    if (!_sleeping) {
2759
                        var changed;
2760
                        var hostSize = {
2761
                            w: _sizeObserverElementNative[LEXICON.sW],
2762
                            h: _sizeObserverElementNative[LEXICON.sH]
2763
                        };
2764

2765
                        changed = checkCache(hostSize, _hostElementSizeChangeDetectedCache);
2766
                        _hostElementSizeChangeDetectedCache = hostSize;
2767
                        if (changed)
2768
                            update({ _hostSizeChanged: true });
2769
                    }
2770
                }
2771

2772
                /**
2773
                 * The mouse enter event of the host element. This event is only needed for the autoHide feature.
2774
                 */
2775
                function hostOnMouseEnter() {
2776
                    if (_scrollbarsAutoHideLeave)
2777
                        refreshScrollbarsAutoHide(true);
2778
                }
2779

2780
                /**
2781
                 * The mouse leave event of the host element. This event is only needed for the autoHide feature.
2782
                 */
2783
                function hostOnMouseLeave() {
2784
                    if (_scrollbarsAutoHideLeave && !_bodyElement.hasClass(_classNameDragging))
2785
                        refreshScrollbarsAutoHide(false);
2786
                }
2787

2788
                /**
2789
                 * The mouse move event of the host element. This event is only needed for the autoHide "move" feature.
2790
                 */
2791
                function hostOnMouseMove() {
2792
                    if (_scrollbarsAutoHideMove) {
2793
                        refreshScrollbarsAutoHide(true);
2794
                        clearTimeout(_scrollbarsAutoHideMoveTimeoutId);
2795
                        _scrollbarsAutoHideMoveTimeoutId = setTimeout(function () {
2796
                            if (_scrollbarsAutoHideMove && !_destroyed)
2797
                                refreshScrollbarsAutoHide(false);
2798
                        }, 100);
2799
                    }
2800
                }
2801

2802
                /**
2803
                 * Prevents text from deselection if attached to the document element on the mousedown event of a DOM element.
2804
                 * @param event The select start event.
2805
                 */
2806
                function documentOnSelectStart(event) {
2807
                    COMPATIBILITY.prvD(event);
2808
                    return false;
2809
                }
2810

2811
                /**	
2812
                 * A callback which will be called after a element has loaded.	
2813
                 */
2814
                function updateOnLoadCallback(event) {
2815
                    var elm = FRAMEWORK(event.target);
2816

2817
                    eachUpdateOnLoad(function (i, updateOnLoadSelector) {
2818
                        if (elm.is(updateOnLoadSelector)) {
2819
                            update({ _contentSizeChanged: true });
2820
                        }
2821
                    });
2822
                }
2823

2824
                /**
2825
                * Adds or removes mouse & touch events of the host element. (for handling auto-hiding of the scrollbars)
2826
                * @param destroy Indicates whether the events shall be added or removed.
2827
                */
2828
                function setupHostMouseTouchEvents(destroy) {
2829
                    if (!destroy)
2830
                        setupHostMouseTouchEvents(true);
2831

2832
                    setupResponsiveEventListener(_hostElement,
2833
                        _strMouseTouchMoveEvent.split(_strSpace)[0],
2834
                        hostOnMouseMove,
2835
                        (!_scrollbarsAutoHideMove || destroy), true);
2836
                    setupResponsiveEventListener(_hostElement,
2837
                        [_strMouseEnter, _strMouseLeave],
2838
                        [hostOnMouseEnter, hostOnMouseLeave],
2839
                        (!_scrollbarsAutoHideLeave || destroy), true);
2840

2841
                    //if the plugin is initialized and the mouse is over the host element, make the scrollbars visible
2842
                    if (!_initialized && !destroy)
2843
                        _hostElement.one('mouseover', hostOnMouseEnter);
2844
                }
2845

2846

2847
                //==== Update Detection ====//
2848

2849
                /**
2850
                 * Measures the min width and min height of the body element and refreshes the related cache.
2851
                 * @returns {boolean} True if the min width or min height has changed, false otherwise.
2852
                 */
2853
                function bodyMinSizeChanged() {
2854
                    var bodyMinSize = {};
2855
                    if (_isBody && _contentArrangeElement) {
2856
                        bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth));
2857
                        bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight));
2858
                        bodyMinSize.c = checkCache(bodyMinSize, _bodyMinSizeCache);
2859
                        bodyMinSize.f = true; //flag for "measured at least once"
2860
                    }
2861
                    _bodyMinSizeCache = bodyMinSize;
2862
                    return !!bodyMinSize.c;
2863
                }
2864

2865
                /**
2866
                 * Returns true if the class names really changed (new class without plugin host prefix)
2867
                 * @param oldClassNames The old ClassName string or array.
2868
                 * @param newClassNames The new ClassName string or array.
2869
                 * @returns {boolean} True if the class names has really changed, false otherwise.
2870
                 */
2871
                function hostClassNamesChanged(oldClassNames, newClassNames) {
2872
                    var currClasses = typeof newClassNames == TYPES.s ? newClassNames.split(_strSpace) : [];
2873
                    var oldClasses = typeof oldClassNames == TYPES.s ? oldClassNames.split(_strSpace) : [];
2874
                    var diff = getArrayDifferences(oldClasses, currClasses);
2875

2876
                    // remove none theme from diff list to prevent update
2877
                    var idx = inArray(_classNameThemeNone, diff);
2878
                    var i;
2879
                    var regex;
2880

2881
                    if (idx > -1)
2882
                        diff.splice(idx, 1);
2883

2884
                    if (diff[LEXICON.l] > 0) {
2885
                        regex = createHostClassNameRegExp(true, true);
2886
                        for (i = 0; i < diff.length; i++) {
2887
                            if (!diff[i].match(regex)) {
2888
                                return true;
2889
                            }
2890
                        }
2891
                    }
2892
                    return false;
2893
                }
2894

2895
                /**
2896
                 * Returns true if the given mutation is not from a from the plugin generated element. If the target element is a textarea the mutation is always unknown.
2897
                 * @param mutation The mutation which shall be checked.
2898
                 * @returns {boolean} True if the mutation is from a unknown element, false otherwise.
2899
                 */
2900
                function isUnknownMutation(mutation) {
2901
                    var attributeName = mutation.attributeName;
2902
                    var mutationTarget = mutation.target;
2903
                    var mutationType = mutation.type;
2904
                    var strClosest = 'closest';
2905

2906
                    if (mutationTarget === _contentElementNative)
2907
                        return attributeName === null;
2908
                    if (mutationType === 'attributes' && (attributeName === LEXICON.c || attributeName === LEXICON.s) && !_isTextarea) {
2909
                        //ignore className changes by the plugin	
2910
                        if (attributeName === LEXICON.c && FRAMEWORK(mutationTarget).hasClass(_classNameHostElement))
2911
                            return hostClassNamesChanged(mutation.oldValue, mutationTarget.className);
2912

2913
                        //only do it of browser support it natively	
2914
                        if (typeof mutationTarget[strClosest] != TYPES.f)
2915
                            return true;
2916
                        if (mutationTarget[strClosest](_strDot + _classNameResizeObserverElement) !== null ||
2917
                            mutationTarget[strClosest](_strDot + _classNameScrollbar) !== null ||
2918
                            mutationTarget[strClosest](_strDot + _classNameScrollbarCorner) !== null)
2919
                            return false;
2920
                    }
2921
                    return true;
2922
                }
2923

2924
                /**
2925
                 * Returns true if the content size was changed since the last time this method was called.
2926
                 * @returns {boolean} True if the content size was changed, false otherwise.
2927
                 */
2928
                function updateAutoContentSizeChanged() {
2929
                    if (_sleeping)
2930
                        return false;
2931

2932
                    var contentMeasureElement = getContentMeasureElement();
2933
                    var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0;
2934
                    var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea;
2935
                    var css = {};
2936
                    var float;
2937
                    var bodyMinSizeC;
2938
                    var changed;
2939
                    var contentElementScrollSize;
2940

2941
                    if (setCSS) {
2942
                        float = _contentElement.css(_strFloat);
2943
                        css[_strFloat] = _isRTL ? _strRight : _strLeft;
2944
                        css[_strWidth] = _strAuto;
2945
                        _contentElement.css(css);
2946
                    }
2947
                    contentElementScrollSize = {
2948
                        w: contentMeasureElement[LEXICON.sW] + textareaValueLength,
2949
                        h: contentMeasureElement[LEXICON.sH] + textareaValueLength
2950
                    };
2951
                    if (setCSS) {
2952
                        css[_strFloat] = float;
2953
                        css[_strWidth] = _strHundredPercent;
2954
                        _contentElement.css(css);
2955
                    }
2956

2957
                    bodyMinSizeC = bodyMinSizeChanged();
2958
                    changed = checkCache(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache);
2959

2960
                    _contentElementScrollSizeChangeDetectedCache = contentElementScrollSize;
2961

2962
                    return changed || bodyMinSizeC;
2963
                }
2964

2965
                /**
2966
                 * Returns true when a attribute which the MutationObserver would observe has changed.  
2967
                 * @returns {boolean} True if one of the attributes which a MutationObserver would observe has changed, false or undefined otherwise.
2968
                 */
2969
                function meaningfulAttrsChanged() {
2970
                    if (_sleeping || _mutationObserversConnected)
2971
                        return;
2972

2973
                    var elem;
2974
                    var curr;
2975
                    var cache;
2976
                    var changedAttrs = [];
2977
                    var checks = [
2978
                        {
2979
                            _elem: _hostElement,
2980
                            _attrs: _mutationObserverAttrsHost.concat(':visible')
2981
                        },
2982
                        {
2983
                            _elem: _isTextarea ? _targetElement : undefined,
2984
                            _attrs: _mutationObserverAttrsTextarea
2985
                        }
2986
                    ];
2987

2988
                    each(checks, function (index, check) {
2989
                        elem = check._elem;
2990
                        if (elem) {
2991
                            each(check._attrs, function (index, attr) {
2992
                                curr = attr.charAt(0) === ':' ? elem.is(attr) : elem.attr(attr);
2993
                                cache = _updateAutoCache[attr];
2994

2995
                                if (checkCache(curr, cache)) {
2996
                                    changedAttrs.push(attr);
2997
                                }
2998

2999
                                _updateAutoCache[attr] = curr;
3000
                            });
3001
                        }
3002
                    });
3003

3004
                    updateViewportAttrsFromTarget(changedAttrs);
3005

3006
                    return changedAttrs[LEXICON.l] > 0;
3007
                }
3008

3009
                /**
3010
                 * Checks is a CSS Property of a child element is affecting the scroll size of the content.
3011
                 * @param propertyName The CSS property name.
3012
                 * @returns {boolean} True if the property is affecting the content scroll size, false otherwise.
3013
                 */
3014
                function isSizeAffectingCSSProperty(propertyName) {
3015
                    if (!_initialized)
3016
                        return true;
3017
                    var flexGrow = 'flex-grow';
3018
                    var flexShrink = 'flex-shrink';
3019
                    var flexBasis = 'flex-basis';
3020
                    var affectingPropsX = [
3021
                        _strWidth,
3022
                        _strMinMinus + _strWidth,
3023
                        _strMaxMinus + _strWidth,
3024
                        _strMarginMinus + _strLeft,
3025
                        _strMarginMinus + _strRight,
3026
                        _strLeft,
3027
                        _strRight,
3028
                        'font-weight',
3029
                        'word-spacing',
3030
                        flexGrow,
3031
                        flexShrink,
3032
                        flexBasis
3033
                    ];
3034
                    var affectingPropsXContentBox = [
3035
                        _strPaddingMinus + _strLeft,
3036
                        _strPaddingMinus + _strRight,
3037
                        _strBorderMinus + _strLeft + _strWidth,
3038
                        _strBorderMinus + _strRight + _strWidth
3039
                    ];
3040
                    var affectingPropsY = [
3041
                        _strHeight,
3042
                        _strMinMinus + _strHeight,
3043
                        _strMaxMinus + _strHeight,
3044
                        _strMarginMinus + _strTop,
3045
                        _strMarginMinus + _strBottom,
3046
                        _strTop,
3047
                        _strBottom,
3048
                        'line-height',
3049
                        flexGrow,
3050
                        flexShrink,
3051
                        flexBasis
3052
                    ];
3053
                    var affectingPropsYContentBox = [
3054
                        _strPaddingMinus + _strTop,
3055
                        _strPaddingMinus + _strBottom,
3056
                        _strBorderMinus + _strTop + _strWidth,
3057
                        _strBorderMinus + _strBottom + _strWidth
3058
                    ];
3059
                    var _strS = 's';
3060
                    var _strVS = 'v-s';
3061
                    var checkX = _overflowBehaviorCache.x === _strS || _overflowBehaviorCache.x === _strVS;
3062
                    var checkY = _overflowBehaviorCache.y === _strS || _overflowBehaviorCache.y === _strVS;
3063
                    var sizeIsAffected = false;
3064
                    var checkPropertyName = function (arr, name) {
3065
                        for (var i = 0; i < arr[LEXICON.l]; i++) {
3066
                            if (arr[i] === name)
3067
                                return true;
3068
                        }
3069
                        return false;
3070
                    };
3071

3072
                    if (checkY) {
3073
                        sizeIsAffected = checkPropertyName(affectingPropsY, propertyName);
3074
                        if (!sizeIsAffected && !_isBorderBox)
3075
                            sizeIsAffected = checkPropertyName(affectingPropsYContentBox, propertyName);
3076
                    }
3077
                    if (checkX && !sizeIsAffected) {
3078
                        sizeIsAffected = checkPropertyName(affectingPropsX, propertyName);
3079
                        if (!sizeIsAffected && !_isBorderBox)
3080
                            sizeIsAffected = checkPropertyName(affectingPropsXContentBox, propertyName);
3081
                    }
3082
                    return sizeIsAffected;
3083
                }
3084

3085

3086
                //==== Update ====//
3087

3088
                /**
3089
                 * Sets the attribute values of the viewport element to the values from the target element.
3090
                 * The value of a attribute is only set if the attribute is whitelisted.
3091
                 * @attrs attrs The array of attributes which shall be set or undefined if all whitelisted shall be set.
3092
                 */
3093
                function updateViewportAttrsFromTarget(attrs) {
3094
                    attrs = attrs || _viewportAttrsFromTarget;
3095
                    each(attrs, function (index, attr) {
3096
                        if (COMPATIBILITY.inA(attr, _viewportAttrsFromTarget) > -1) {
3097
                            var targetAttr = _targetElement.attr(attr);
3098
                            if (type(targetAttr) == TYPES.s) {
3099
                                _viewportElement.attr(attr, targetAttr);
3100
                            }
3101
                            else {
3102
                                _viewportElement.removeAttr(attr);
3103
                            }
3104
                        }
3105
                    });
3106
                }
3107

3108
                /**
3109
                 * Updates the variables and size of the textarea element, and manages the scroll on new line or new character.
3110
                 */
3111
                function textareaUpdate() {
3112
                    if (!_sleeping) {
3113
                        var wrapAttrOff = !_textareaAutoWrappingCache;
3114
                        var minWidth = _viewportSize.w;
3115
                        var minHeight = _viewportSize.h;
3116
                        var css = {};
3117
                        var doMeasure = _widthAutoCache || wrapAttrOff;
3118
                        var origWidth;
3119
                        var width;
3120
                        var origHeight;
3121
                        var height;
3122

3123
                        //reset min size
3124
                        css[_strMinMinus + _strWidth] = _strEmpty;
3125
                        css[_strMinMinus + _strHeight] = _strEmpty;
3126

3127
                        //set width auto
3128
                        css[_strWidth] = _strAuto;
3129
                        _targetElement.css(css);
3130

3131
                        //measure width
3132
                        origWidth = _targetElementNative[LEXICON.oW];
3133
                        width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1;
3134
                        /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/
3135

3136
                        //set measured width
3137
                        css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent;
3138
                        css[_strMinMinus + _strWidth] = _strHundredPercent;
3139

3140
                        //set height auto
3141
                        css[_strHeight] = _strAuto;
3142
                        _targetElement.css(css);
3143

3144
                        //measure height
3145
                        origHeight = _targetElementNative[LEXICON.oH];
3146
                        height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1);
3147

3148
                        //append correct size values
3149
                        css[_strWidth] = width;
3150
                        css[_strHeight] = height;
3151
                        _textareaCoverElement.css(css);
3152

3153
                        //apply min width / min height to prevent textarea collapsing
3154
                        css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/;
3155
                        css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/;
3156
                        _targetElement.css(css);
3157

3158
                        return {
3159
                            _originalWidth: origWidth,
3160
                            _originalHeight: origHeight,
3161
                            _dynamicWidth: width,
3162
                            _dynamicHeight: height
3163
                        };
3164
                    }
3165
                }
3166

3167
                /**
3168
                 * Updates the plugin and DOM to the current options.
3169
                 * This method should only be called if a update is 100% required.
3170
                 * @param updateHints A objects which contains hints for this update:
3171
                 * {
3172
                 *   _hostSizeChanged : boolean,
3173
                 *   _contentSizeChanged : boolean,
3174
                 *   _force : boolean,                             == preventSwallowing
3175
                 *   _changedOptions : { },                        == preventSwallowing && preventSleep
3176
                *  }
3177
                 */
3178
                function update(updateHints) {
3179
                    clearTimeout(_swallowedUpdateTimeout);
3180
                    updateHints = updateHints || {};
3181
                    _swallowedUpdateHints._hostSizeChanged |= updateHints._hostSizeChanged;
3182
                    _swallowedUpdateHints._contentSizeChanged |= updateHints._contentSizeChanged;
3183
                    _swallowedUpdateHints._force |= updateHints._force;
3184

3185
                    var now = COMPATIBILITY.now();
3186
                    var hostSizeChanged = !!_swallowedUpdateHints._hostSizeChanged;
3187
                    var contentSizeChanged = !!_swallowedUpdateHints._contentSizeChanged;
3188
                    var force = !!_swallowedUpdateHints._force;
3189
                    var changedOptions = updateHints._changedOptions;
3190
                    var swallow = _swallowUpdateLag > 0 && _initialized && !_destroyed && !force && !changedOptions && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache);
3191
                    var displayIsHidden;
3192

3193
                    if (swallow)
3194
                        _swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag);
3195

3196
                    //abort update due to:
3197
                    //destroyed
3198
                    //swallowing
3199
                    //sleeping
3200
                    //host is hidden or has false display
3201
                    if (_destroyed || swallow || (_sleeping && !changedOptions) || (_initialized && !force && (displayIsHidden = _hostElement.is(':hidden'))) || _hostElement.css('display') === 'inline')
3202
                        return;
3203

3204
                    _lastUpdateTime = now;
3205
                    _swallowedUpdateHints = {};
3206

3207
                    //if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely.
3208
                    if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
3209
                        //native scrollbars are hidden, so change the values to zero
3210
                        _nativeScrollbarSize.x = 0;
3211
                        _nativeScrollbarSize.y = 0;
3212
                    }
3213
                    else {
3214
                        //refresh native scrollbar size (in case of zoom)
3215
                        _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
3216
                    }
3217

3218
                    // Scrollbar padding is needed for firefox, because firefox hides scrollbar automatically if the size of the div is too small.
3219
                    // The calculation: [scrollbar size +3 *3]
3220
                    // (+3 because of possible decoration e.g. borders, margins etc., but only if native scrollbar is NOT a overlaid scrollbar)
3221
                    // (*3 because (1)increase / (2)decrease -button and (3)resize handle)
3222
                    _nativeScrollbarMinSize = {
3223
                        x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3,
3224
                        y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 3
3225
                    };
3226

3227
                    changedOptions = changedOptions || {};
3228
                    //freezeResizeObserver(_sizeObserverElement, true);
3229
                    //freezeResizeObserver(_sizeAutoObserverElement, true);
3230

3231
                    var checkCacheAutoForce = function () {
3232
                        return checkCache.apply(this, [].slice.call(arguments).concat([force]));
3233
                    };
3234

3235
                    //save current scroll offset
3236
                    var currScroll = {
3237
                        x: _viewportElement[_strScrollLeft](),
3238
                        y: _viewportElement[_strScrollTop]()
3239
                    };
3240

3241
                    var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars;
3242
                    var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea;
3243

3244
                    //scrollbars visibility:
3245
                    var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility;
3246
                    var scrollbarsVisibilityChanged = checkCacheAutoForce(scrollbarsVisibility, _scrollbarsVisibilityCache);
3247

3248
                    //scrollbars autoHide:
3249
                    var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide;
3250
                    var scrollbarsAutoHideChanged = checkCacheAutoForce(scrollbarsAutoHide, _scrollbarsAutoHideCache);
3251

3252
                    //scrollbars click scrolling
3253
                    var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling;
3254
                    var scrollbarsClickScrollingChanged = checkCacheAutoForce(scrollbarsClickScrolling, _scrollbarsClickScrollingCache);
3255

3256
                    //scrollbars drag scrolling
3257
                    var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling;
3258
                    var scrollbarsDragScrollingChanged = checkCacheAutoForce(scrollbarsDragScrolling, _scrollbarsDragScrollingCache);
3259

3260
                    //className
3261
                    var className = _currentPreparedOptions.className;
3262
                    var classNameChanged = checkCacheAutoForce(className, _classNameCache);
3263

3264
                    //resize
3265
                    var resize = _currentPreparedOptions.resize;
3266
                    var resizeChanged = checkCacheAutoForce(resize, _resizeCache) && !_isBody; //body can't be resized since the window itself acts as resize possibility.
3267

3268
                    //paddingAbsolute
3269
                    var paddingAbsolute = _currentPreparedOptions.paddingAbsolute;
3270
                    var paddingAbsoluteChanged = checkCacheAutoForce(paddingAbsolute, _paddingAbsoluteCache);
3271

3272
                    //clipAlways
3273
                    var clipAlways = _currentPreparedOptions.clipAlways;
3274
                    var clipAlwaysChanged = checkCacheAutoForce(clipAlways, _clipAlwaysCache);
3275

3276
                    //sizeAutoCapable
3277
                    var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport.
3278
                    var sizeAutoCapableChanged = checkCacheAutoForce(sizeAutoCapable, _sizeAutoCapableCache);
3279

3280
                    //showNativeScrollbars
3281
                    var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars;
3282
                    var ignoreOverlayScrollbarHidingChanged = checkCacheAutoForce(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache);
3283

3284
                    //autoUpdate
3285
                    var autoUpdate = _currentPreparedOptions.autoUpdate;
3286
                    var autoUpdateChanged = checkCacheAutoForce(autoUpdate, _autoUpdateCache);
3287

3288
                    //overflowBehavior
3289
                    var overflowBehavior = _currentPreparedOptions.overflowBehavior;
3290
                    var overflowBehaviorChanged = checkCacheAutoForce(overflowBehavior, _overflowBehaviorCache, force);
3291

3292
                    //dynWidth:
3293
                    var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth;
3294
                    var textareaDynWidthChanged = checkCacheAutoForce(_textareaDynWidthCache, textareaDynWidth);
3295

3296
                    //dynHeight:
3297
                    var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight;
3298
                    var textareaDynHeightChanged = checkCacheAutoForce(_textareaDynHeightCache, textareaDynHeight);
3299

3300
                    //scrollbars visibility
3301
                    _scrollbarsAutoHideNever = scrollbarsAutoHide === 'n';
3302
                    _scrollbarsAutoHideScroll = scrollbarsAutoHide === 's';
3303
                    _scrollbarsAutoHideMove = scrollbarsAutoHide === 'm';
3304
                    _scrollbarsAutoHideLeave = scrollbarsAutoHide === 'l';
3305

3306
                    //scrollbars autoHideDelay
3307
                    _scrollbarsAutoHideDelay = currentPreparedOptionsScrollbars.autoHideDelay;
3308

3309
                    //old className
3310
                    _oldClassName = _classNameCache;
3311

3312
                    //resize
3313
                    _resizeNone = resize === 'n';
3314
                    _resizeBoth = resize === 'b';
3315
                    _resizeHorizontal = resize === 'h';
3316
                    _resizeVertical = resize === 'v';
3317

3318
                    //normalizeRTL
3319
                    _normalizeRTLCache = _currentPreparedOptions.normalizeRTL;
3320

3321
                    //ignore overlay scrollbar hiding
3322
                    ignoreOverlayScrollbarHiding = ignoreOverlayScrollbarHiding && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y);
3323

3324
                    //refresh options cache
3325
                    _scrollbarsVisibilityCache = scrollbarsVisibility;
3326
                    _scrollbarsAutoHideCache = scrollbarsAutoHide;
3327
                    _scrollbarsClickScrollingCache = scrollbarsClickScrolling;
3328
                    _scrollbarsDragScrollingCache = scrollbarsDragScrolling;
3329
                    _classNameCache = className;
3330
                    _resizeCache = resize;
3331
                    _paddingAbsoluteCache = paddingAbsolute;
3332
                    _clipAlwaysCache = clipAlways;
3333
                    _sizeAutoCapableCache = sizeAutoCapable;
3334
                    _ignoreOverlayScrollbarHidingCache = ignoreOverlayScrollbarHiding;
3335
                    _autoUpdateCache = autoUpdate;
3336
                    _overflowBehaviorCache = extendDeep({}, overflowBehavior);
3337
                    _textareaDynWidthCache = textareaDynWidth;
3338
                    _textareaDynHeightCache = textareaDynHeight;
3339
                    _hasOverflowCache = _hasOverflowCache || { x: false, y: false };
3340

3341
                    //set correct class name to the host element
3342
                    if (classNameChanged) {
3343
                        removeClass(_hostElement, _oldClassName + _strSpace + _classNameThemeNone);
3344
                        addClass(_hostElement, className !== undefined && className !== null && className.length > 0 ? className : _classNameThemeNone);
3345
                    }
3346

3347
                    //set correct auto Update
3348
                    if (autoUpdateChanged) {
3349
                        if (autoUpdate === true || (autoUpdate === null && _autoUpdateRecommended)) {
3350
                            disconnectMutationObservers();
3351
                            autoUpdateLoop.add(_base);
3352
                        }
3353
                        else {
3354
                            autoUpdateLoop.remove(_base);
3355
                            connectMutationObservers();
3356
                        }
3357
                    }
3358

3359
                    //activate or deactivate size auto capability
3360
                    if (sizeAutoCapableChanged) {
3361
                        if (sizeAutoCapable) {
3362
                            if (_contentGlueElement) {
3363
                                _contentGlueElement.show();
3364
                            }
3365
                            else {
3366
                                _contentGlueElement = FRAMEWORK(generateDiv(_classNameContentGlueElement));
3367
                                _paddingElement.before(_contentGlueElement);
3368
                            }
3369
                            if (_sizeAutoObserverAdded) {
3370
                                _sizeAutoObserverElement.show();
3371
                            }
3372
                            else {
3373
                                _sizeAutoObserverElement = FRAMEWORK(generateDiv(_classNameSizeAutoObserverElement));
3374
                                _sizeAutoObserverElementNative = _sizeAutoObserverElement[0];
3375

3376
                                _contentGlueElement.before(_sizeAutoObserverElement);
3377
                                var oldSize = { w: -1, h: -1 };
3378
                                setupResizeObserver(_sizeAutoObserverElement, function () {
3379
                                    var newSize = {
3380
                                        w: _sizeAutoObserverElementNative[LEXICON.oW],
3381
                                        h: _sizeAutoObserverElementNative[LEXICON.oH]
3382
                                    };
3383
                                    if (checkCache(newSize, oldSize)) {
3384
                                        if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) {
3385
                                            update();
3386
                                        }
3387
                                        else if (_initialized && (!_heightAutoCache && newSize.h === 0) || (!_widthAutoCache && newSize.w === 0)) {
3388
                                            update();
3389
                                        }
3390
                                    }
3391
                                    oldSize = newSize;
3392
                                });
3393
                                _sizeAutoObserverAdded = true;
3394
                                //fix heightAuto detector bug if height is fixed but contentHeight is 0.
3395
                                //the probability this bug will ever happen is very very low, thats why its ok if we use calc which isn't supported in IE8.
3396
                                if (_cssCalc !== null)
3397
                                    _sizeAutoObserverElement.css(_strHeight, _cssCalc + '(100% + 1px)');
3398
                            }
3399
                        }
3400
                        else {
3401
                            if (_sizeAutoObserverAdded)
3402
                                _sizeAutoObserverElement.hide();
3403
                            if (_contentGlueElement)
3404
                                _contentGlueElement.hide();
3405
                        }
3406
                    }
3407

3408
                    //if force, update all resizeObservers too
3409
                    if (force) {
3410
                        _sizeObserverElement.find('*').trigger(_strScroll);
3411
                        if (_sizeAutoObserverAdded)
3412
                            _sizeAutoObserverElement.find('*').trigger(_strScroll);
3413
                    }
3414

3415
                    //display hidden:
3416
                    displayIsHidden = displayIsHidden === undefined ? _hostElement.is(':hidden') : displayIsHidden;
3417

3418
                    //textarea AutoWrapping:
3419
                    var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false;
3420
                    var textareaAutoWrappingChanged = checkCacheAutoForce(textareaAutoWrapping, _textareaAutoWrappingCache);
3421

3422
                    //detect direction:
3423
                    var cssDirection = _hostElement.css('direction');
3424
                    var cssDirectionChanged = checkCacheAutoForce(cssDirection, _cssDirectionCache);
3425

3426
                    //detect box-sizing:
3427
                    var boxSizing = _hostElement.css('box-sizing');
3428
                    var boxSizingChanged = checkCacheAutoForce(boxSizing, _cssBoxSizingCache);
3429

3430
                    //detect padding:
3431
                    var padding = getTopRightBottomLeftHost(_strPaddingMinus);
3432

3433
                    //width + height auto detecting var:
3434
                    var sizeAutoObserverElementBCRect;
3435
                    //exception occurs in IE8 sometimes (unknown exception)
3436
                    try {
3437
                        sizeAutoObserverElementBCRect = _sizeAutoObserverAdded ? _sizeAutoObserverElementNative[LEXICON.bCR]() : null;
3438
                    } catch (ex) {
3439
                        return;
3440
                    }
3441

3442
                    _isRTL = cssDirection === 'rtl';
3443
                    _isBorderBox = (boxSizing === 'border-box');
3444
                    var isRTLLeft = _isRTL ? _strLeft : _strRight;
3445
                    var isRTLRight = _isRTL ? _strRight : _strLeft;
3446

3447
                    //detect width auto:
3448
                    var widthAutoResizeDetection = false;
3449
                    var widthAutoObserverDetection = (_sizeAutoObserverAdded && (_hostElement.css(_strFloat) !== 'none' /*|| _isTextarea */)) ? (MATH.round(sizeAutoObserverElementBCRect.right - sizeAutoObserverElementBCRect.left) === 0) && (!paddingAbsolute ? (_hostElementNative[LEXICON.cW] - _paddingX) > 0 : true) : false;
3450
                    if (sizeAutoCapable && !widthAutoObserverDetection) {
3451
                        var tmpCurrHostWidth = _hostElementNative[LEXICON.oW];
3452
                        var tmpCurrContentGlueWidth = _contentGlueElement.css(_strWidth);
3453
                        _contentGlueElement.css(_strWidth, _strAuto);
3454

3455
                        var tmpNewHostWidth = _hostElementNative[LEXICON.oW];
3456
                        _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
3457
                        widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
3458
                        if (!widthAutoResizeDetection) {
3459
                            _contentGlueElement.css(_strWidth, tmpCurrHostWidth + 1);
3460
                            tmpNewHostWidth = _hostElementNative[LEXICON.oW];
3461
                            _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
3462
                            widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
3463
                        }
3464
                    }
3465
                    var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden;
3466
                    var widthAutoChanged = checkCacheAutoForce(widthAuto, _widthAutoCache);
3467
                    var wasWidthAuto = !widthAuto && _widthAutoCache;
3468

3469
                    //detect height auto:
3470
                    var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false;
3471
                    var heightAutoChanged = checkCacheAutoForce(heightAuto, _heightAutoCache);
3472
                    var wasHeightAuto = !heightAuto && _heightAutoCache;
3473

3474
                    //detect border:
3475
                    //we need the border only if border box and auto size
3476
                    var updateBorderX = (widthAuto && _isBorderBox) || !_isBorderBox;
3477
                    var updateBorderY = (heightAuto && _isBorderBox) || !_isBorderBox;
3478
                    var border = getTopRightBottomLeftHost(_strBorderMinus, '-' + _strWidth, !updateBorderX, !updateBorderY)
3479

3480
                    //detect margin:
3481
                    var margin = getTopRightBottomLeftHost(_strMarginMinus);
3482

3483
                    //vars to apply correct css
3484
                    var contentElementCSS = {};
3485
                    var contentGlueElementCSS = {};
3486

3487
                    //funcs
3488
                    var getHostSize = function () {
3489
                        //has to be clientSize because offsetSize respect borders
3490
                        return {
3491
                            w: _hostElementNative[LEXICON.cW],
3492
                            h: _hostElementNative[LEXICON.cH]
3493
                        };
3494
                    };
3495
                    var getViewportSize = function () {
3496
                        //viewport size is padding container because it never has padding, margin and a border
3497
                        //determine zoom rounding error -> sometimes scrollWidth/Height is smaller than clientWidth/Height
3498
                        //if this happens add the difference to the viewportSize to compensate the rounding error
3499
                        return {
3500
                            w: _paddingElementNative[LEXICON.oW] + MATH.max(0, _contentElementNative[LEXICON.cW] - _contentElementNative[LEXICON.sW]),
3501
                            h: _paddingElementNative[LEXICON.oH] + MATH.max(0, _contentElementNative[LEXICON.cH] - _contentElementNative[LEXICON.sH])
3502
                        };
3503
                    };
3504

3505
                    //set info for padding
3506
                    var paddingAbsoluteX = _paddingX = padding.l + padding.r;
3507
                    var paddingAbsoluteY = _paddingY = padding.t + padding.b;
3508
                    paddingAbsoluteX *= paddingAbsolute ? 1 : 0;
3509
                    paddingAbsoluteY *= paddingAbsolute ? 1 : 0;
3510
                    padding.c = checkCacheAutoForce(padding, _cssPaddingCache);
3511

3512
                    //set info for border
3513
                    _borderX = border.l + border.r;
3514
                    _borderY = border.t + border.b;
3515
                    border.c = checkCacheAutoForce(border, _cssBorderCache);
3516

3517
                    //set info for margin
3518
                    _marginX = margin.l + margin.r;
3519
                    _marginY = margin.t + margin.b;
3520
                    margin.c = checkCacheAutoForce(margin, _cssMarginCache);
3521

3522
                    //refresh cache
3523
                    _textareaAutoWrappingCache = textareaAutoWrapping;
3524
                    _cssDirectionCache = cssDirection;
3525
                    _cssBoxSizingCache = boxSizing;
3526
                    _widthAutoCache = widthAuto;
3527
                    _heightAutoCache = heightAuto;
3528
                    _cssPaddingCache = padding;
3529
                    _cssBorderCache = border;
3530
                    _cssMarginCache = margin;
3531

3532
                    //IEFix direction changed
3533
                    if (cssDirectionChanged && _sizeAutoObserverAdded)
3534
                        _sizeAutoObserverElement.css(_strFloat, isRTLRight);
3535

3536
                    //apply padding:
3537
                    if (padding.c || cssDirectionChanged || paddingAbsoluteChanged || widthAutoChanged || heightAutoChanged || boxSizingChanged || sizeAutoCapableChanged) {
3538
                        var paddingElementCSS = {};
3539
                        var textareaCSS = {};
3540
                        var paddingValues = [padding.t, padding.r, padding.b, padding.l];
3541

3542
                        setTopRightBottomLeft(contentGlueElementCSS, _strMarginMinus, [-padding.t, -padding.r, -padding.b, -padding.l]);
3543
                        if (paddingAbsolute) {
3544
                            setTopRightBottomLeft(paddingElementCSS, _strEmpty, paddingValues);
3545
                            setTopRightBottomLeft(_isTextarea ? textareaCSS : contentElementCSS, _strPaddingMinus);
3546
                        }
3547
                        else {
3548
                            setTopRightBottomLeft(paddingElementCSS, _strEmpty);
3549
                            setTopRightBottomLeft(_isTextarea ? textareaCSS : contentElementCSS, _strPaddingMinus, paddingValues);
3550
                        }
3551

3552
                        _paddingElement.css(paddingElementCSS);
3553
                        _targetElement.css(textareaCSS);
3554
                    }
3555

3556
                    //viewport size is padding container because it never has padding, margin and a border.
3557
                    _viewportSize = getViewportSize();
3558

3559
                    //update Textarea
3560
                    var textareaSize = _isTextarea ? textareaUpdate() : false;
3561
                    var textareaSizeChanged = _isTextarea && checkCacheAutoForce(textareaSize, _textareaSizeCache);
3562
                    var textareaDynOrigSize = _isTextarea && textareaSize ? {
3563
                        w: textareaDynWidth ? textareaSize._dynamicWidth : textareaSize._originalWidth,
3564
                        h: textareaDynHeight ? textareaSize._dynamicHeight : textareaSize._originalHeight
3565
                    } : {};
3566
                    _textareaSizeCache = textareaSize;
3567

3568
                    //fix height auto / width auto in cooperation with current padding & boxSizing behavior:
3569
                    if (heightAuto && (heightAutoChanged || paddingAbsoluteChanged || boxSizingChanged || padding.c || border.c)) {
3570
                        contentElementCSS[_strHeight] = _strAuto;
3571
                    }
3572
                    else if (heightAutoChanged || paddingAbsoluteChanged) {
3573
                        contentElementCSS[_strHeight] = _strHundredPercent;
3574
                    }
3575
                    if (widthAuto && (widthAutoChanged || paddingAbsoluteChanged || boxSizingChanged || padding.c || border.c || cssDirectionChanged)) {
3576
                        contentElementCSS[_strWidth] = _strAuto;
3577
                        contentGlueElementCSS[_strMaxMinus + _strWidth] = _strHundredPercent; //IE Fix
3578
                    }
3579
                    else if (widthAutoChanged || paddingAbsoluteChanged) {
3580
                        contentElementCSS[_strWidth] = _strHundredPercent;
3581
                        contentElementCSS[_strFloat] = _strEmpty;
3582
                        contentGlueElementCSS[_strMaxMinus + _strWidth] = _strEmpty; //IE Fix
3583
                    }
3584
                    if (widthAuto) {
3585
                        //textareaDynOrigSize.w || _strAuto :: doesnt works because applied margin will shift width
3586
                        contentGlueElementCSS[_strWidth] = _strAuto;
3587

3588
                        contentElementCSS[_strWidth] = VENDORS._cssPropertyValue(_strWidth, 'max-content intrinsic') || _strAuto;
3589
                        contentElementCSS[_strFloat] = isRTLRight;
3590
                    }
3591
                    else {
3592
                        contentGlueElementCSS[_strWidth] = _strEmpty;
3593
                    }
3594
                    if (heightAuto) {
3595
                        //textareaDynOrigSize.h || _contentElementNative[LEXICON.cH] :: use for anti scroll jumping
3596
                        contentGlueElementCSS[_strHeight] = textareaDynOrigSize.h || _contentElementNative[LEXICON.cH];
3597
                    }
3598
                    else {
3599
                        contentGlueElementCSS[_strHeight] = _strEmpty;
3600
                    }
3601
                    if (sizeAutoCapable)
3602
                        _contentGlueElement.css(contentGlueElementCSS);
3603
                    _contentElement.css(contentElementCSS);
3604

3605
                    //CHECKPOINT HERE ~
3606
                    contentElementCSS = {};
3607
                    contentGlueElementCSS = {};
3608

3609
                    //if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true
3610
                    if (hostSizeChanged || contentSizeChanged || textareaSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged) {
3611
                        var strOverflow = 'overflow';
3612
                        var strOverflowX = strOverflow + '-x';
3613
                        var strOverflowY = strOverflow + '-y';
3614
                        var strHidden = 'hidden';
3615
                        var strVisible = 'visible';
3616

3617
                        //Reset the viewport (very important for natively overlaid scrollbars and zoom change
3618
                        //don't change the overflow prop as it is very expensive and affects performance !A LOT!
3619
                        if (!_nativeScrollbarStyling) {
3620
                            var viewportElementResetCSS = {};
3621
                            var resetXTmp = _hasOverflowCache.y && _hideOverflowCache.ys && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.y ? _viewportElement.css(isRTLLeft) : -_nativeScrollbarSize.y) : 0;
3622
                            var resetBottomTmp = _hasOverflowCache.x && _hideOverflowCache.xs && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.x ? _viewportElement.css(_strBottom) : -_nativeScrollbarSize.x) : 0;
3623
                            setTopRightBottomLeft(viewportElementResetCSS, _strEmpty);
3624
                            _viewportElement.css(viewportElementResetCSS);
3625
                        }
3626

3627
                        //measure several sizes:
3628
                        var contentMeasureElement = getContentMeasureElement();
3629
                        //in Firefox content element has to have overflow hidden, else element margins aren't calculated properly, this element prevents this bug, but only if scrollbars aren't overlaid
3630
                        var contentSize = {
3631
                            //use clientSize because natively overlaidScrollbars add borders
3632
                            w: textareaDynOrigSize.w || contentMeasureElement[LEXICON.cW],
3633
                            h: textareaDynOrigSize.h || contentMeasureElement[LEXICON.cH]
3634
                        };
3635
                        var scrollSize = {
3636
                            w: contentMeasureElement[LEXICON.sW],
3637
                            h: contentMeasureElement[LEXICON.sH]
3638
                        };
3639

3640
                        //apply the correct viewport style and measure viewport size
3641
                        if (!_nativeScrollbarStyling) {
3642
                            viewportElementResetCSS[_strBottom] = wasHeightAuto ? _strEmpty : resetBottomTmp;
3643
                            viewportElementResetCSS[isRTLLeft] = wasWidthAuto ? _strEmpty : resetXTmp;
3644
                            _viewportElement.css(viewportElementResetCSS);
3645
                        }
3646
                        _viewportSize = getViewportSize();
3647

3648
                        //measure and correct several sizes
3649
                        var hostSize = getHostSize();
3650
                        var hostAbsoluteRectSize = {
3651
                            w: hostSize.w - _marginX - _borderX - (_isBorderBox ? 0 : _paddingX),
3652
                            h: hostSize.h - _marginY - _borderY - (_isBorderBox ? 0 : _paddingY)
3653
                        };
3654
                        var contentGlueSize = {
3655
                            //client/scrollSize + AbsolutePadding -> because padding is only applied to the paddingElement if its absolute, so you have to add it manually
3656
                            //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
3657
                            w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostAbsoluteRectSize.w),
3658
                            h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostAbsoluteRectSize.h)
3659
                        };
3660
                        contentGlueSize.c = checkCacheAutoForce(contentGlueSize, _contentGlueSizeCache);
3661
                        _contentGlueSizeCache = contentGlueSize;
3662

3663
                        //apply correct contentGlue size
3664
                        if (sizeAutoCapable) {
3665
                            //size contentGlue correctly to make sure the element has correct size if the sizing switches to auto
3666
                            if (contentGlueSize.c || (heightAuto || widthAuto)) {
3667
                                contentGlueElementCSS[_strWidth] = contentGlueSize.w;
3668
                                contentGlueElementCSS[_strHeight] = contentGlueSize.h;
3669

3670
                                //textarea-sizes are already calculated correctly at this point
3671
                                if (!_isTextarea) {
3672
                                    contentSize = {
3673
                                        //use clientSize because natively overlaidScrollbars add borders
3674
                                        w: contentMeasureElement[LEXICON.cW],
3675
                                        h: contentMeasureElement[LEXICON.cH]
3676
                                    };
3677
                                }
3678
                            }
3679
                            var textareaCoverCSS = {};
3680
                            var setContentGlueElementCSSfunction = function (horizontal) {
3681
                                var scrollbarVars = getScrollbarVars(horizontal);
3682
                                var wh = scrollbarVars._w_h;
3683
                                var strWH = scrollbarVars._width_height;
3684
                                var autoSize = horizontal ? widthAuto : heightAuto;
3685
                                var borderSize = horizontal ? _borderX : _borderY;
3686
                                var paddingSize = horizontal ? _paddingX : _paddingY;
3687
                                var marginSize = horizontal ? _marginX : _marginY;
3688
                                var viewportSize = _viewportSize[wh] - borderSize - marginSize - (_isBorderBox ? 0 : paddingSize);
3689

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

3694
                                //if size is auto and host is smaller than size as min size, make content glue size -1 to make sure size changes will be detected (this is only needed if padding is 0)
3695
                                if (autoSize && (contentSize[wh] < viewportSize) && (horizontal && _isTextarea ? !textareaAutoWrapping : true)) {
3696
                                    if (_isTextarea)
3697
                                        textareaCoverCSS[strWH] = parseToZeroOrNumber(_textareaCoverElement.css(strWH)) - 1;
3698
                                    contentGlueElementCSS[strWH] -= 1;
3699
                                }
3700

3701
                                //make sure content glue size is at least 1
3702
                                if (contentSize[wh] > 0)
3703
                                    contentGlueElementCSS[strWH] = MATH.max(1, contentGlueElementCSS[strWH]);
3704
                            };
3705
                            setContentGlueElementCSSfunction(true);
3706
                            setContentGlueElementCSSfunction(false);
3707

3708
                            if (_isTextarea)
3709
                                _textareaCoverElement.css(textareaCoverCSS);
3710
                            _contentGlueElement.css(contentGlueElementCSS);
3711
                        }
3712
                        if (widthAuto)
3713
                            contentElementCSS[_strWidth] = _strHundredPercent;
3714
                        if (widthAuto && !_isBorderBox && !_mutationObserversConnected)
3715
                            contentElementCSS[_strFloat] = 'none';
3716

3717
                        //apply and reset content style
3718
                        _contentElement.css(contentElementCSS);
3719
                        contentElementCSS = {};
3720

3721
                        //measure again, but this time all correct sizes:
3722
                        var contentScrollSize = {
3723
                            w: contentMeasureElement[LEXICON.sW],
3724
                            h: contentMeasureElement[LEXICON.sH],
3725
                        };
3726
                        contentScrollSize.c = contentSizeChanged = checkCacheAutoForce(contentScrollSize, _contentScrollSizeCache);
3727
                        _contentScrollSizeCache = contentScrollSize;
3728

3729
                        //refresh viewport size after correct measuring
3730
                        _viewportSize = getViewportSize();
3731

3732
                        hostSize = getHostSize();
3733
                        hostSizeChanged = checkCacheAutoForce(hostSize, _hostSizeCache);
3734
                        _hostSizeCache = hostSize;
3735

3736
                        var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0);
3737
                        var previousOverflowAmount = _overflowAmountCache;
3738
                        var overflowBehaviorIsVS = {};
3739
                        var overflowBehaviorIsVH = {};
3740
                        var overflowBehaviorIsS = {};
3741
                        var overflowAmount = {};
3742
                        var hasOverflow = {};
3743
                        var hideOverflow = {};
3744
                        var canScroll = {};
3745
                        var viewportRect = _paddingElementNative[LEXICON.bCR]();
3746
                        var setOverflowVariables = function (horizontal) {
3747
                            var scrollbarVars = getScrollbarVars(horizontal);
3748
                            var scrollbarVarsInverted = getScrollbarVars(!horizontal);
3749
                            var xyI = scrollbarVarsInverted._x_y;
3750
                            var xy = scrollbarVars._x_y;
3751
                            var wh = scrollbarVars._w_h;
3752
                            var widthHeight = scrollbarVars._width_height;
3753
                            var scrollMax = _strScroll + scrollbarVars._Left_Top + 'Max';
3754
                            var fractionalOverflowAmount = viewportRect[widthHeight] ? MATH.abs(viewportRect[widthHeight] - _viewportSize[wh]) : 0;
3755
                            var checkFractionalOverflowAmount = previousOverflowAmount && previousOverflowAmount[xy] > 0 && _viewportElementNative[scrollMax] === 0;
3756
                            overflowBehaviorIsVS[xy] = overflowBehavior[xy] === 'v-s';
3757
                            overflowBehaviorIsVH[xy] = overflowBehavior[xy] === 'v-h';
3758
                            overflowBehaviorIsS[xy] = overflowBehavior[xy] === 's';
3759
                            overflowAmount[xy] = MATH.max(0, MATH.round((contentScrollSize[wh] - _viewportSize[wh]) * 100) / 100);
3760
                            overflowAmount[xy] *= (hideOverflowForceTextarea || (checkFractionalOverflowAmount && fractionalOverflowAmount > 0 && fractionalOverflowAmount < 1)) ? 0 : 1;
3761
                            hasOverflow[xy] = overflowAmount[xy] > 0;
3762

3763
                            //hideOverflow:
3764
                            //x || y : true === overflow is hidden by "overflow: scroll" OR "overflow: hidden"
3765
                            //xs || ys : true === overflow is hidden by "overflow: scroll"
3766
                            hideOverflow[xy] = overflowBehaviorIsVS[xy] || overflowBehaviorIsVH[xy] ? (hasOverflow[xyI] && !overflowBehaviorIsVS[xyI] && !overflowBehaviorIsVH[xyI]) : hasOverflow[xy];
3767
                            hideOverflow[xy + 's'] = hideOverflow[xy] ? (overflowBehaviorIsS[xy] || overflowBehaviorIsVS[xy]) : false;
3768

3769
                            canScroll[xy] = hasOverflow[xy] && hideOverflow[xy + 's'];
3770
                        };
3771
                        setOverflowVariables(true);
3772
                        setOverflowVariables(false);
3773

3774
                        overflowAmount.c = checkCacheAutoForce(overflowAmount, _overflowAmountCache);
3775
                        _overflowAmountCache = overflowAmount;
3776
                        hasOverflow.c = checkCacheAutoForce(hasOverflow, _hasOverflowCache);
3777
                        _hasOverflowCache = hasOverflow;
3778
                        hideOverflow.c = checkCacheAutoForce(hideOverflow, _hideOverflowCache);
3779
                        _hideOverflowCache = hideOverflow;
3780

3781
                        //if native scrollbar is overlay at x OR y axis, prepare DOM
3782
                        if (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) {
3783
                            var borderDesign = 'px solid transparent';
3784
                            var contentArrangeElementCSS = {};
3785
                            var arrangeContent = {};
3786
                            var arrangeChanged = force;
3787
                            var setContentElementCSS;
3788

3789
                            if (hasOverflow.x || hasOverflow.y) {
3790
                                arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty;
3791
                                arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty;
3792
                                arrangeChanged = checkCacheAutoForce(arrangeContent, _arrangeContentSizeCache);
3793
                                _arrangeContentSizeCache = arrangeContent;
3794
                            }
3795

3796
                            if (hasOverflow.c || hideOverflow.c || contentScrollSize.c || cssDirectionChanged || widthAutoChanged || heightAutoChanged || widthAuto || heightAuto || ignoreOverlayScrollbarHidingChanged) {
3797
                                contentElementCSS[_strMarginMinus + isRTLRight] = contentElementCSS[_strBorderMinus + isRTLRight] = _strEmpty;
3798
                                setContentElementCSS = function (horizontal) {
3799
                                    var scrollbarVars = getScrollbarVars(horizontal);
3800
                                    var scrollbarVarsInverted = getScrollbarVars(!horizontal);
3801
                                    var xy = scrollbarVars._x_y;
3802
                                    var strDirection = horizontal ? _strBottom : isRTLLeft;
3803
                                    var invertedAutoSize = horizontal ? heightAuto : widthAuto;
3804

3805
                                    if (_nativeScrollbarIsOverlaid[xy] && hasOverflow[xy] && hideOverflow[xy + 's']) {
3806
                                        contentElementCSS[_strMarginMinus + strDirection] = invertedAutoSize ? (ignoreOverlayScrollbarHiding ? _strEmpty : _overlayScrollbarDummySize[xy]) : _strEmpty;
3807
                                        contentElementCSS[_strBorderMinus + strDirection] = ((horizontal ? !invertedAutoSize : true) && !ignoreOverlayScrollbarHiding) ? (_overlayScrollbarDummySize[xy] + borderDesign) : _strEmpty;
3808
                                    }
3809
                                    else {
3810
                                        arrangeContent[scrollbarVarsInverted._w_h] =
3811
                                            contentElementCSS[_strMarginMinus + strDirection] =
3812
                                            contentElementCSS[_strBorderMinus + strDirection] = _strEmpty;
3813
                                        arrangeChanged = true;
3814
                                    }
3815
                                };
3816

3817
                                if (_nativeScrollbarStyling) {
3818
                                    addRemoveClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible, !ignoreOverlayScrollbarHiding)
3819
                                }
3820
                                else {
3821
                                    setContentElementCSS(true);
3822
                                    setContentElementCSS(false);
3823
                                }
3824
                            }
3825
                            if (ignoreOverlayScrollbarHiding) {
3826
                                arrangeContent.w = arrangeContent.h = _strEmpty;
3827
                                arrangeChanged = true;
3828
                            }
3829
                            if (arrangeChanged && !_nativeScrollbarStyling) {
3830
                                contentArrangeElementCSS[_strWidth] = hideOverflow.y ? arrangeContent.w : _strEmpty;
3831
                                contentArrangeElementCSS[_strHeight] = hideOverflow.x ? arrangeContent.h : _strEmpty;
3832

3833
                                if (!_contentArrangeElement) {
3834
                                    _contentArrangeElement = FRAMEWORK(generateDiv(_classNameContentArrangeElement));
3835
                                    _viewportElement.prepend(_contentArrangeElement);
3836
                                }
3837
                                _contentArrangeElement.css(contentArrangeElementCSS);
3838
                            }
3839
                            _contentElement.css(contentElementCSS);
3840
                        }
3841

3842
                        var viewportElementCSS = {};
3843
                        var paddingElementCSS = {};
3844
                        var setViewportCSS;
3845
                        if (hostSizeChanged || hasOverflow.c || hideOverflow.c || contentScrollSize.c || overflowBehaviorChanged || boxSizingChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged || clipAlwaysChanged || heightAutoChanged) {
3846
                            viewportElementCSS[isRTLRight] = _strEmpty;
3847
                            setViewportCSS = function (horizontal) {
3848
                                var scrollbarVars = getScrollbarVars(horizontal);
3849
                                var scrollbarVarsInverted = getScrollbarVars(!horizontal);
3850
                                var xy = scrollbarVars._x_y;
3851
                                var XY = scrollbarVars._X_Y;
3852
                                var strDirection = horizontal ? _strBottom : isRTLLeft;
3853

3854
                                var reset = function () {
3855
                                    viewportElementCSS[strDirection] = _strEmpty;
3856
                                    _contentBorderSize[scrollbarVarsInverted._w_h] = 0;
3857
                                };
3858
                                if (hasOverflow[xy] && hideOverflow[xy + 's']) {
3859
                                    viewportElementCSS[strOverflow + XY] = _strScroll;
3860
                                    if (ignoreOverlayScrollbarHiding || _nativeScrollbarStyling) {
3861
                                        reset();
3862
                                    }
3863
                                    else {
3864
                                        viewportElementCSS[strDirection] = -(_nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[xy] : _nativeScrollbarSize[xy]);
3865
                                        _contentBorderSize[scrollbarVarsInverted._w_h] = _nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[scrollbarVarsInverted._x_y] : 0;
3866
                                    }
3867
                                } else {
3868
                                    viewportElementCSS[strOverflow + XY] = _strEmpty;
3869
                                    reset();
3870
                                }
3871
                            };
3872
                            setViewportCSS(true);
3873
                            setViewportCSS(false);
3874

3875
                            // if the scroll container is too small and if there is any overflow with no overlay scrollbar (and scrollbar styling isn't possible), 
3876
                            // make viewport element greater in size (Firefox hide Scrollbars fix)
3877
                            // because firefox starts hiding scrollbars on too small elements
3878
                            // with this behavior the overflow calculation may be incorrect or the scrollbars would appear suddenly
3879
                            // https://bugzilla.mozilla.org/show_bug.cgi?id=292284
3880
                            if (!_nativeScrollbarStyling
3881
                                && (_viewportSize.h < _nativeScrollbarMinSize.x || _viewportSize.w < _nativeScrollbarMinSize.y)
3882
                                && ((hasOverflow.x && hideOverflow.x && !_nativeScrollbarIsOverlaid.x) || (hasOverflow.y && hideOverflow.y && !_nativeScrollbarIsOverlaid.y))) {
3883
                                viewportElementCSS[_strPaddingMinus + _strTop] = _nativeScrollbarMinSize.x;
3884
                                viewportElementCSS[_strMarginMinus + _strTop] = -_nativeScrollbarMinSize.x;
3885

3886
                                viewportElementCSS[_strPaddingMinus + isRTLRight] = _nativeScrollbarMinSize.y;
3887
                                viewportElementCSS[_strMarginMinus + isRTLRight] = -_nativeScrollbarMinSize.y;
3888
                            }
3889
                            else {
3890
                                viewportElementCSS[_strPaddingMinus + _strTop] =
3891
                                    viewportElementCSS[_strMarginMinus + _strTop] =
3892
                                    viewportElementCSS[_strPaddingMinus + isRTLRight] =
3893
                                    viewportElementCSS[_strMarginMinus + isRTLRight] = _strEmpty;
3894
                            }
3895
                            viewportElementCSS[_strPaddingMinus + isRTLLeft] =
3896
                                viewportElementCSS[_strMarginMinus + isRTLLeft] = _strEmpty;
3897

3898
                            //if there is any overflow (x OR y axis) and this overflow shall be hidden, make overflow hidden, else overflow visible
3899
                            if ((hasOverflow.x && hideOverflow.x) || (hasOverflow.y && hideOverflow.y) || hideOverflowForceTextarea) {
3900
                                //only hide if is Textarea
3901
                                if (_isTextarea && hideOverflowForceTextarea) {
3902
                                    paddingElementCSS[strOverflowX] =
3903
                                        paddingElementCSS[strOverflowY] = strHidden;
3904
                                }
3905
                            }
3906
                            else {
3907
                                if (!clipAlways || (overflowBehaviorIsVH.x || overflowBehaviorIsVS.x || overflowBehaviorIsVH.y || overflowBehaviorIsVS.y)) {
3908
                                    //only un-hide if Textarea
3909
                                    if (_isTextarea) {
3910
                                        paddingElementCSS[strOverflowX] =
3911
                                            paddingElementCSS[strOverflowY] = _strEmpty;
3912
                                    }
3913
                                    viewportElementCSS[strOverflowX] =
3914
                                        viewportElementCSS[strOverflowY] = strVisible;
3915
                                }
3916
                            }
3917

3918
                            _paddingElement.css(paddingElementCSS);
3919
                            _viewportElement.css(viewportElementCSS);
3920
                            viewportElementCSS = {};
3921

3922
                            //force soft redraw in webkit because without the scrollbars will may appear because DOM wont be redrawn under special conditions
3923
                            if ((hasOverflow.c || boxSizingChanged || widthAutoChanged || heightAutoChanged) && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
3924
                                var elementStyle = _contentElementNative[LEXICON.s];
3925
                                var dump;
3926
                                elementStyle.webkitTransform = 'scale(1)';
3927
                                elementStyle.display = 'run-in';
3928
                                dump = _contentElementNative[LEXICON.oH];
3929
                                elementStyle.display = _strEmpty; //|| dump; //use dump to prevent it from deletion if minify
3930
                                elementStyle.webkitTransform = _strEmpty;
3931
                            }
3932
                            /*
3933
                            //force hard redraw in webkit if native overlaid scrollbars shall appear
3934
                            if (ignoreOverlayScrollbarHidingChanged && ignoreOverlayScrollbarHiding) {
3935
                                _hostElement.hide();
3936
                                var dump = _hostElementNative[LEXICON.oH];
3937
                                _hostElement.show();
3938
                            }
3939
                            */
3940
                        }
3941

3942
                        //change to direction RTL and width auto Bugfix in Webkit
3943
                        //without this fix, the DOM still thinks the scrollbar is LTR and thus the content is shifted to the left
3944
                        contentElementCSS = {};
3945
                        if (cssDirectionChanged || widthAutoChanged || heightAutoChanged) {
3946
                            if (_isRTL && widthAuto) {
3947
                                var floatTmp = _contentElement.css(_strFloat);
3948
                                var posLeftWithoutFloat = MATH.round(_contentElement.css(_strFloat, _strEmpty).css(_strLeft, _strEmpty).position().left);
3949
                                _contentElement.css(_strFloat, floatTmp);
3950
                                var posLeftWithFloat = MATH.round(_contentElement.position().left);
3951

3952
                                if (posLeftWithoutFloat !== posLeftWithFloat)
3953
                                    contentElementCSS[_strLeft] = posLeftWithoutFloat;
3954
                            }
3955
                            else {
3956
                                contentElementCSS[_strLeft] = _strEmpty;
3957
                            }
3958
                        }
3959
                        _contentElement.css(contentElementCSS);
3960

3961
                        //handle scroll position
3962
                        if (_isTextarea && contentSizeChanged) {
3963
                            var textareaInfo = getTextareaInfo();
3964
                            if (textareaInfo) {
3965
                                var textareaRowsChanged = _textareaInfoCache === undefined ? true : textareaInfo._rows !== _textareaInfoCache._rows;
3966
                                var cursorRow = textareaInfo._cursorRow;
3967
                                var cursorCol = textareaInfo._cursorColumn;
3968
                                var widestRow = textareaInfo._widestRow;
3969
                                var lastRow = textareaInfo._rows;
3970
                                var lastCol = textareaInfo._columns;
3971
                                var cursorPos = textareaInfo._cursorPosition;
3972
                                var cursorMax = textareaInfo._cursorMax;
3973
                                var cursorIsLastPosition = (cursorPos >= cursorMax && _textareaHasFocus);
3974
                                var textareaScrollAmount = {
3975
                                    x: (!textareaAutoWrapping && (cursorCol === lastCol && cursorRow === widestRow)) ? _overflowAmountCache.x : -1,
3976
                                    y: (textareaAutoWrapping ? cursorIsLastPosition || textareaRowsChanged && (previousOverflowAmount ? (currScroll.y === previousOverflowAmount.y) : false) : (cursorIsLastPosition || textareaRowsChanged) && cursorRow === lastRow) ? _overflowAmountCache.y : -1
3977
                                };
3978
                                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.
3979
                                currScroll.y = textareaScrollAmount.y > -1 ? textareaScrollAmount.y : currScroll.y;
3980
                            }
3981
                            _textareaInfoCache = textareaInfo;
3982
                        }
3983
                        if (_isRTL && _rtlScrollBehavior.i && _nativeScrollbarIsOverlaid.y && hasOverflow.x && _normalizeRTLCache)
3984
                            currScroll.x += _contentBorderSize.w || 0;
3985
                        if (widthAuto)
3986
                            _hostElement[_strScrollLeft](0);
3987
                        if (heightAuto)
3988
                            _hostElement[_strScrollTop](0);
3989
                        _viewportElement[_strScrollLeft](currScroll.x)[_strScrollTop](currScroll.y);
3990

3991
                        //scrollbars management:
3992
                        var scrollbarsVisibilityVisible = scrollbarsVisibility === 'v';
3993
                        var scrollbarsVisibilityHidden = scrollbarsVisibility === 'h';
3994
                        var scrollbarsVisibilityAuto = scrollbarsVisibility === 'a';
3995
                        var refreshScrollbarsVisibility = function (showX, showY) {
3996
                            showY = showY === undefined ? showX : showY;
3997
                            refreshScrollbarAppearance(true, showX, canScroll.x)
3998
                            refreshScrollbarAppearance(false, showY, canScroll.y)
3999
                        };
4000

4001
                        //manage class name which indicates scrollable overflow
4002
                        addRemoveClass(_hostElement, _classNameHostOverflow, hideOverflow.x || hideOverflow.y);
4003
                        addRemoveClass(_hostElement, _classNameHostOverflowX, hideOverflow.x);
4004
                        addRemoveClass(_hostElement, _classNameHostOverflowY, hideOverflow.y);
4005

4006
                        //add or remove rtl class name for styling purposes except when its body, then the scrollbar stays
4007
                        if (cssDirectionChanged && !_isBody) {
4008
                            addRemoveClass(_hostElement, _classNameHostRTL, _isRTL);
4009
                        }
4010

4011
                        //manage the resize feature (CSS3 resize "polyfill" for this plugin)
4012
                        if (_isBody)
4013
                            addClass(_hostElement, _classNameHostResizeDisabled);
4014
                        if (resizeChanged) {
4015
                            addRemoveClass(_hostElement, _classNameHostResizeDisabled, _resizeNone);
4016
                            addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResize, !_resizeNone);
4017
                            addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeB, _resizeBoth);
4018
                            addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeH, _resizeHorizontal);
4019
                            addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV, _resizeVertical);
4020
                        }
4021

4022
                        //manage the scrollbars general visibility + the scrollbar interactivity (unusable class name)
4023
                        if (scrollbarsVisibilityChanged || overflowBehaviorChanged || hideOverflow.c || hasOverflow.c || ignoreOverlayScrollbarHidingChanged) {
4024
                            if (ignoreOverlayScrollbarHiding) {
4025
                                if (ignoreOverlayScrollbarHidingChanged) {
4026
                                    removeClass(_hostElement, _classNameHostScrolling);
4027
                                    if (ignoreOverlayScrollbarHiding) {
4028
                                        refreshScrollbarsVisibility(false);
4029
                                    }
4030
                                }
4031
                            }
4032
                            else if (scrollbarsVisibilityAuto) {
4033
                                refreshScrollbarsVisibility(canScroll.x, canScroll.y);
4034
                            }
4035
                            else if (scrollbarsVisibilityVisible) {
4036
                                refreshScrollbarsVisibility(true);
4037
                            }
4038
                            else if (scrollbarsVisibilityHidden) {
4039
                                refreshScrollbarsVisibility(false);
4040
                            }
4041
                        }
4042

4043
                        //manage the scrollbars auto hide feature (auto hide them after specific actions)
4044
                        if (scrollbarsAutoHideChanged || ignoreOverlayScrollbarHidingChanged) {
4045
                            setupHostMouseTouchEvents(!_scrollbarsAutoHideLeave && !_scrollbarsAutoHideMove);
4046
                            refreshScrollbarsAutoHide(_scrollbarsAutoHideNever, !_scrollbarsAutoHideNever);
4047
                        }
4048

4049
                        //manage scrollbars handle length & offset - don't remove!
4050
                        if (hostSizeChanged || overflowAmount.c || heightAutoChanged || widthAutoChanged || resizeChanged || boxSizingChanged || paddingAbsoluteChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged) {
4051
                            refreshScrollbarHandleLength(true);
4052
                            refreshScrollbarHandleOffset(true);
4053
                            refreshScrollbarHandleLength(false);
4054
                            refreshScrollbarHandleOffset(false);
4055
                        }
4056

4057
                        //manage interactivity
4058
                        if (scrollbarsClickScrollingChanged)
4059
                            refreshScrollbarsInteractive(true, scrollbarsClickScrolling);
4060
                        if (scrollbarsDragScrollingChanged)
4061
                            refreshScrollbarsInteractive(false, scrollbarsDragScrolling);
4062

4063
                        //callbacks:
4064
                        dispatchCallback('onDirectionChanged', {
4065
                            isRTL: _isRTL,
4066
                            dir: cssDirection
4067
                        }, cssDirectionChanged);
4068
                        dispatchCallback('onHostSizeChanged', {
4069
                            width: _hostSizeCache.w,
4070
                            height: _hostSizeCache.h
4071
                        }, hostSizeChanged);
4072
                        dispatchCallback('onContentSizeChanged', {
4073
                            width: _contentScrollSizeCache.w,
4074
                            height: _contentScrollSizeCache.h
4075
                        }, contentSizeChanged);
4076
                        dispatchCallback('onOverflowChanged', {
4077
                            x: hasOverflow.x,
4078
                            y: hasOverflow.y,
4079
                            xScrollable: hideOverflow.xs,
4080
                            yScrollable: hideOverflow.ys,
4081
                            clipped: hideOverflow.x || hideOverflow.y
4082
                        }, hasOverflow.c || hideOverflow.c);
4083
                        dispatchCallback('onOverflowAmountChanged', {
4084
                            x: overflowAmount.x,
4085
                            y: overflowAmount.y
4086
                        }, overflowAmount.c);
4087
                    }
4088

4089
                    //fix body min size
4090
                    if (_isBody && _bodyMinSizeCache && (_hasOverflowCache.c || _bodyMinSizeCache.c)) {
4091
                        //its possible that no min size was measured until now, because the content arrange element was just added now, in this case, measure now the min size.
4092
                        if (!_bodyMinSizeCache.f)
4093
                            bodyMinSizeChanged();
4094
                        if (_nativeScrollbarIsOverlaid.y && _hasOverflowCache.x)
4095
                            _contentElement.css(_strMinMinus + _strWidth, _bodyMinSizeCache.w + _overlayScrollbarDummySize.y);
4096
                        if (_nativeScrollbarIsOverlaid.x && _hasOverflowCache.y)
4097
                            _contentElement.css(_strMinMinus + _strHeight, _bodyMinSizeCache.h + _overlayScrollbarDummySize.x);
4098
                        _bodyMinSizeCache.c = false;
4099
                    }
4100

4101
                    if (_initialized && changedOptions.updateOnLoad) {
4102
                        updateElementsOnLoad();
4103
                    }
4104

4105
                    //freezeResizeObserver(_sizeObserverElement, false);
4106
                    //freezeResizeObserver(_sizeAutoObserverElement, false);
4107

4108
                    dispatchCallback('onUpdated', { forced: force });
4109
                }
4110

4111
                /**
4112
                 * Updates the found elements of which the load event shall be handled.
4113
                 */
4114
                function updateElementsOnLoad() {
4115
                    if (!_isTextarea) {
4116
                        eachUpdateOnLoad(function (i, updateOnLoadSelector) {
4117
                            _contentElement.find(updateOnLoadSelector).each(function (i, el) {
4118
                                // if element doesn't have a updateOnLoadCallback applied
4119
                                if (COMPATIBILITY.inA(el, _updateOnLoadElms) < 0) {
4120
                                    _updateOnLoadElms.push(el);
4121
                                    FRAMEWORK(el)
4122
                                        .off(_updateOnLoadEventName, updateOnLoadCallback)
4123
                                        .on(_updateOnLoadEventName, updateOnLoadCallback);
4124
                                }
4125
                            });
4126
                        });
4127
                    }
4128
                }
4129

4130
                //==== Options ====//
4131

4132
                /**
4133
                 * Sets new options but doesn't call the update method.
4134
                 * @param newOptions The object which contains the new options.
4135
                 * @returns {*} A object which contains the changed options.
4136
                 */
4137
                function setOptions(newOptions) {
4138
                    var validatedOpts = _pluginsOptions._validate(newOptions, _pluginsOptions._template, true, _currentOptions)
4139

4140
                    _currentOptions = extendDeep({}, _currentOptions, validatedOpts._default);
4141
                    _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, validatedOpts._prepared);
4142

4143
                    return validatedOpts._prepared;
4144
                }
4145

4146

4147
                //==== Structure ====//
4148

4149
                /**
4150
                 * Builds or destroys the wrapper and helper DOM elements.
4151
                 * @param destroy Indicates whether the DOM shall be build or destroyed.
4152
                 */
4153
                /**
4154
                 * Builds or destroys the wrapper and helper DOM elements.
4155
                 * @param destroy Indicates whether the DOM shall be build or destroyed.
4156
                 */
4157
                function setupStructureDOM(destroy) {
4158
                    var strParent = 'parent';
4159
                    var classNameResizeObserverHost = 'os-resize-observer-host';
4160
                    var classNameTextareaElementFull = _classNameTextareaElement + _strSpace + _classNameTextInherit;
4161
                    var textareaClass = _isTextarea ? _strSpace + _classNameTextInherit : _strEmpty;
4162
                    var adoptAttrs = _currentPreparedOptions.textarea.inheritedAttrs;
4163
                    var adoptAttrsMap = {};
4164
                    var applyAdoptedAttrs = function () {
4165
                        var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement;
4166
                        each(adoptAttrsMap, function (key, value) {
4167
                            if (type(value) == TYPES.s) {
4168
                                if (key == LEXICON.c)
4169
                                    applyAdoptedAttrsElm.addClass(value);
4170
                                else
4171
                                    applyAdoptedAttrsElm.attr(key, value);
4172
                            }
4173
                        });
4174
                    };
4175
                    var hostElementClassNames = [
4176
                        _classNameHostElement,
4177
                        _classNameHostElementForeign,
4178
                        _classNameHostTextareaElement,
4179
                        _classNameHostResizeDisabled,
4180
                        _classNameHostRTL,
4181
                        _classNameHostScrollbarHorizontalHidden,
4182
                        _classNameHostScrollbarVerticalHidden,
4183
                        _classNameHostTransition,
4184
                        _classNameHostScrolling,
4185
                        _classNameHostOverflow,
4186
                        _classNameHostOverflowX,
4187
                        _classNameHostOverflowY,
4188
                        _classNameThemeNone,
4189
                        _classNameTextareaElement,
4190
                        _classNameTextInherit,
4191
                        _classNameCache].join(_strSpace);
4192
                    var hostElementCSS = {};
4193

4194
                    //get host element as first element, because that's the most upper element and required for the other elements
4195
                    _hostElement = _hostElement || (_isTextarea ? (_domExists ? _targetElement[strParent]()[strParent]()[strParent]()[strParent]() : FRAMEWORK(generateDiv(_classNameHostTextareaElement))) : _targetElement);
4196
                    _contentElement = _contentElement || selectOrGenerateDivByClass(_classNameContentElement + textareaClass);
4197
                    _viewportElement = _viewportElement || selectOrGenerateDivByClass(_classNameViewportElement + textareaClass);
4198
                    _paddingElement = _paddingElement || selectOrGenerateDivByClass(_classNamePaddingElement + textareaClass);
4199
                    _sizeObserverElement = _sizeObserverElement || selectOrGenerateDivByClass(classNameResizeObserverHost);
4200
                    _textareaCoverElement = _textareaCoverElement || (_isTextarea ? selectOrGenerateDivByClass(_classNameTextareaCoverElement) : undefined);
4201

4202
                    //add this class to workaround class changing issues with UI frameworks especially Vue
4203
                    if (_domExists)
4204
                        addClass(_hostElement, _classNameHostElementForeign);
4205

4206
                    //on destroy, remove all generated class names from the host element before collecting the adopted attributes 
4207
                    //to prevent adopting generated class names
4208
                    if (destroy)
4209
                        removeClass(_hostElement, hostElementClassNames);
4210

4211
                    //collect all adopted attributes
4212
                    adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(_strSpace) : adoptAttrs;
4213
                    if (COMPATIBILITY.isA(adoptAttrs) && _isTextarea) {
4214
                        each(adoptAttrs, function (i, v) {
4215
                            if (type(v) == TYPES.s) {
4216
                                adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v);
4217
                            }
4218
                        });
4219
                    }
4220

4221
                    if (!destroy) {
4222
                        if (_isTextarea) {
4223
                            if (!_currentPreparedOptions.sizeAutoCapable) {
4224
                                hostElementCSS[_strWidth] = _targetElement.css(_strWidth);
4225
                                hostElementCSS[_strHeight] = _targetElement.css(_strHeight);
4226
                            }
4227

4228
                            if (!_domExists)
4229
                                _targetElement.addClass(_classNameTextInherit).wrap(_hostElement);
4230

4231
                            //jQuery clones elements in wrap functions, so we have to select them again
4232
                            _hostElement = _targetElement[strParent]().css(hostElementCSS);
4233
                        }
4234

4235
                        if (!_domExists) {
4236
                            //add the correct class to the target element
4237
                            addClass(_targetElement, _isTextarea ? classNameTextareaElementFull : _classNameHostElement);
4238

4239
                            //wrap the content into the generated elements to create the required DOM
4240
                            _hostElement.wrapInner(_contentElement)
4241
                                .wrapInner(_viewportElement)
4242
                                .wrapInner(_paddingElement)
4243
                                .prepend(_sizeObserverElement);
4244

4245
                            //jQuery clones elements in wrap functions, so we have to select them again
4246
                            _contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);
4247
                            _viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);
4248
                            _paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);
4249

4250
                            if (_isTextarea) {
4251
                                _contentElement.prepend(_textareaCoverElement);
4252
                                applyAdoptedAttrs();
4253
                            }
4254
                        }
4255

4256
                        if (_nativeScrollbarStyling)
4257
                            addClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);
4258
                        if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)
4259
                            addClass(_viewportElement, _classNameViewportNativeScrollbarsOverlaid);
4260
                        if (_isBody)
4261
                            addClass(_htmlElement, _classNameHTMLElement);
4262

4263
                        _sizeObserverElementNative = _sizeObserverElement[0];
4264
                        _hostElementNative = _hostElement[0];
4265
                        _paddingElementNative = _paddingElement[0];
4266
                        _viewportElementNative = _viewportElement[0];
4267
                        _contentElementNative = _contentElement[0];
4268

4269
                        updateViewportAttrsFromTarget();
4270
                    }
4271
                    else {
4272
                        if (_domExists && _initialized) {
4273
                            //clear size observer
4274
                            _sizeObserverElement.children().remove();
4275

4276
                            //remove the style property and classes from already generated elements
4277
                            each([_paddingElement, _viewportElement, _contentElement, _textareaCoverElement], function (i, elm) {
4278
                                if (elm) {
4279
                                    removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
4280
                                }
4281
                            });
4282

4283
                            //add classes to the host element which was removed previously to match the expected DOM
4284
                            addClass(_hostElement, _isTextarea ? _classNameHostTextareaElement : _classNameHostElement);
4285
                        }
4286
                        else {
4287
                            //remove size observer
4288
                            remove(_sizeObserverElement);
4289

4290
                            //unwrap the content to restore DOM
4291
                            _contentElement.contents()
4292
                                .unwrap()
4293
                                .unwrap()
4294
                                .unwrap();
4295

4296
                            if (_isTextarea) {
4297
                                _targetElement.unwrap();
4298
                                remove(_hostElement);
4299
                                remove(_textareaCoverElement);
4300
                                applyAdoptedAttrs();
4301
                            }
4302
                        }
4303

4304
                        if (_isTextarea)
4305
                            _targetElement.removeAttr(LEXICON.s);
4306

4307
                        if (_isBody)
4308
                            removeClass(_htmlElement, _classNameHTMLElement);
4309
                    }
4310
                }
4311

4312
                /**
4313
                 * Adds or removes all wrapper elements interactivity events.
4314
                 * @param destroy Indicates whether the Events shall be added or removed.
4315
                 */
4316
                function setupStructureEvents() {
4317
                    var textareaKeyDownRestrictedKeyCodes = [
4318
                        112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123,    //F1 to F12
4319
                        33, 34,                                                   //page up, page down
4320
                        37, 38, 39, 40,                                           //left, up, right, down arrows
4321
                        16, 17, 18, 19, 20, 144                                   //Shift, Ctrl, Alt, Pause, CapsLock, NumLock
4322
                    ];
4323
                    var textareaKeyDownKeyCodesList = [];
4324
                    var textareaUpdateIntervalID;
4325
                    var scrollStopTimeoutId;
4326
                    var scrollStopDelay = 175;
4327
                    var strFocus = 'focus';
4328

4329
                    function updateTextarea(doClearInterval) {
4330
                        textareaUpdate();
4331
                        _base.update(_strAuto);
4332
                        if (doClearInterval && _autoUpdateRecommended)
4333
                            clearInterval(textareaUpdateIntervalID);
4334
                    }
4335
                    function textareaOnScroll(event) {
4336
                        _targetElement[_strScrollLeft](_rtlScrollBehavior.i && _normalizeRTLCache ? 9999999 : 0);
4337
                        _targetElement[_strScrollTop](0);
4338
                        COMPATIBILITY.prvD(event);
4339
                        COMPATIBILITY.stpP(event);
4340
                        return false;
4341
                    }
4342
                    function textareaOnDrop(event) {
4343
                        setTimeout(function () {
4344
                            if (!_destroyed)
4345
                                updateTextarea();
4346
                        }, 50);
4347
                    }
4348
                    function textareaOnFocus() {
4349
                        _textareaHasFocus = true;
4350
                        addClass(_hostElement, strFocus);
4351
                    }
4352
                    function textareaOnFocusout() {
4353
                        _textareaHasFocus = false;
4354
                        textareaKeyDownKeyCodesList = [];
4355
                        removeClass(_hostElement, strFocus);
4356
                        updateTextarea(true);
4357
                    }
4358
                    function textareaOnKeyDown(event) {
4359
                        var keyCode = event.keyCode;
4360

4361
                        if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {
4362
                            if (!textareaKeyDownKeyCodesList[LEXICON.l]) {
4363
                                updateTextarea();
4364
                                textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60);
4365
                            }
4366
                            if (inArray(keyCode, textareaKeyDownKeyCodesList) < 0)
4367
                                textareaKeyDownKeyCodesList.push(keyCode);
4368
                        }
4369
                    }
4370
                    function textareaOnKeyUp(event) {
4371
                        var keyCode = event.keyCode;
4372
                        var index = inArray(keyCode, textareaKeyDownKeyCodesList);
4373

4374
                        if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {
4375
                            if (index > -1)
4376
                                textareaKeyDownKeyCodesList.splice(index, 1);
4377
                            if (!textareaKeyDownKeyCodesList[LEXICON.l])
4378
                                updateTextarea(true);
4379
                        }
4380
                    }
4381
                    function contentOnTransitionEnd(event) {
4382
                        if (_autoUpdateCache === true)
4383
                            return;
4384
                        event = event.originalEvent || event;
4385
                        if (isSizeAffectingCSSProperty(event.propertyName))
4386
                            _base.update(_strAuto);
4387
                    }
4388
                    function viewportOnScroll(event) {
4389
                        if (!_sleeping) {
4390
                            if (scrollStopTimeoutId !== undefined)
4391
                                clearTimeout(scrollStopTimeoutId);
4392
                            else {
4393
                                if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
4394
                                    refreshScrollbarsAutoHide(true);
4395

4396
                                if (!nativeOverlayScrollbarsAreActive())
4397
                                    addClass(_hostElement, _classNameHostScrolling);
4398

4399
                                dispatchCallback('onScrollStart', event);
4400
                            }
4401

4402
                            //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset
4403
                            //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point
4404
                            //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove
4405
                            if (!_scrollbarsHandlesDefineScrollPos) {
4406
                                refreshScrollbarHandleOffset(true);
4407
                                refreshScrollbarHandleOffset(false);
4408
                            }
4409
                            dispatchCallback('onScroll', event);
4410

4411
                            scrollStopTimeoutId = setTimeout(function () {
4412
                                if (!_destroyed) {
4413
                                    //OnScrollStop:
4414
                                    clearTimeout(scrollStopTimeoutId);
4415
                                    scrollStopTimeoutId = undefined;
4416

4417
                                    if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
4418
                                        refreshScrollbarsAutoHide(false);
4419

4420
                                    if (!nativeOverlayScrollbarsAreActive())
4421
                                        removeClass(_hostElement, _classNameHostScrolling);
4422

4423
                                    dispatchCallback('onScrollStop', event);
4424
                                }
4425
                            }, scrollStopDelay);
4426
                        }
4427
                    }
4428

4429

4430
                    if (_isTextarea) {
4431
                        if (_msieVersion > 9 || !_autoUpdateRecommended) {
4432
                            addDestroyEventListener(_targetElement, 'input', updateTextarea);
4433
                        }
4434
                        else {
4435
                            addDestroyEventListener(_targetElement,
4436
                                [_strKeyDownEvent, _strKeyUpEvent],
4437
                                [textareaOnKeyDown, textareaOnKeyUp]);
4438
                        }
4439

4440
                        addDestroyEventListener(_targetElement,
4441
                            [_strScroll, 'drop', strFocus, strFocus + 'out'],
4442
                            [textareaOnScroll, textareaOnDrop, textareaOnFocus, textareaOnFocusout]);
4443
                    }
4444
                    else {
4445
                        addDestroyEventListener(_contentElement, _strTransitionEndEvent, contentOnTransitionEnd);
4446
                    }
4447
                    addDestroyEventListener(_viewportElement, _strScroll, viewportOnScroll, true);
4448
                }
4449

4450

4451
                //==== Scrollbars ====//
4452

4453
                /**
4454
                 * Builds or destroys all scrollbar DOM elements (scrollbar, track, handle)
4455
                 * @param destroy Indicates whether the DOM shall be build or destroyed.
4456
                 */
4457
                function setupScrollbarsDOM(destroy) {
4458
                    var selectOrGenerateScrollbarDOM = function (isHorizontal) {
4459
                        var scrollbarClassName = isHorizontal ? _classNameScrollbarHorizontal : _classNameScrollbarVertical;
4460
                        var scrollbar = selectOrGenerateDivByClass(_classNameScrollbar + _strSpace + scrollbarClassName, true);
4461
                        var track = selectOrGenerateDivByClass(_classNameScrollbarTrack, scrollbar);
4462
                        var handle = selectOrGenerateDivByClass(_classNameScrollbarHandle, scrollbar);
4463

4464
                        if (!_domExists && !destroy) {
4465
                            scrollbar.append(track);
4466
                            track.append(handle);
4467
                        }
4468

4469
                        return {
4470
                            _scrollbar: scrollbar,
4471
                            _track: track,
4472
                            _handle: handle
4473
                        };
4474
                    };
4475
                    function resetScrollbarDOM(isHorizontal) {
4476
                        var scrollbarVars = getScrollbarVars(isHorizontal);
4477
                        var scrollbar = scrollbarVars._scrollbar;
4478
                        var track = scrollbarVars._track;
4479
                        var handle = scrollbarVars._handle;
4480

4481
                        if (_domExists && _initialized) {
4482
                            each([scrollbar, track, handle], function (i, elm) {
4483
                                removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
4484
                            });
4485
                        }
4486
                        else {
4487
                            remove(scrollbar || selectOrGenerateScrollbarDOM(isHorizontal)._scrollbar);
4488
                        }
4489
                    }
4490
                    var horizontalElements;
4491
                    var verticalElements;
4492

4493
                    if (!destroy) {
4494
                        horizontalElements = selectOrGenerateScrollbarDOM(true);
4495
                        verticalElements = selectOrGenerateScrollbarDOM();
4496

4497
                        _scrollbarHorizontalElement = horizontalElements._scrollbar;
4498
                        _scrollbarHorizontalTrackElement = horizontalElements._track;
4499
                        _scrollbarHorizontalHandleElement = horizontalElements._handle;
4500
                        _scrollbarVerticalElement = verticalElements._scrollbar;
4501
                        _scrollbarVerticalTrackElement = verticalElements._track;
4502
                        _scrollbarVerticalHandleElement = verticalElements._handle;
4503

4504
                        if (!_domExists) {
4505
                            _paddingElement.after(_scrollbarVerticalElement);
4506
                            _paddingElement.after(_scrollbarHorizontalElement);
4507
                        }
4508
                    }
4509
                    else {
4510
                        resetScrollbarDOM(true);
4511
                        resetScrollbarDOM();
4512
                    }
4513
                }
4514

4515
                /**
4516
                 * Initializes all scrollbar interactivity events. (track and handle dragging, clicking, scrolling)
4517
                 * @param isHorizontal True if the target scrollbar is the horizontal scrollbar, false if the target scrollbar is the vertical scrollbar.
4518
                 */
4519
                function setupScrollbarEvents(isHorizontal) {
4520
                    var scrollbarVars = getScrollbarVars(isHorizontal);
4521
                    var scrollbarVarsInfo = scrollbarVars._info;
4522
                    var insideIFrame = _windowElementNative.top !== _windowElementNative;
4523
                    var xy = scrollbarVars._x_y;
4524
                    var XY = scrollbarVars._X_Y;
4525
                    var scroll = _strScroll + scrollbarVars._Left_Top;
4526
                    var strActive = 'active';
4527
                    var strSnapHandle = 'snapHandle';
4528
                    var strClickEvent = 'click';
4529
                    var scrollDurationFactor = 1;
4530
                    var increaseDecreaseScrollAmountKeyCodes = [16, 17]; //shift, ctrl
4531
                    var trackTimeout;
4532
                    var mouseDownScroll;
4533
                    var mouseDownOffset;
4534
                    var mouseDownInvertedScale;
4535

4536
                    function getPointerPosition(event) {
4537
                        return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames.
4538
                    }
4539
                    function getPreparedScrollbarsOption(name) {
4540
                        return _currentPreparedOptions.scrollbars[name];
4541
                    }
4542
                    function increaseTrackScrollAmount() {
4543
                        scrollDurationFactor = 0.5;
4544
                    }
4545
                    function decreaseTrackScrollAmount() {
4546
                        scrollDurationFactor = 1;
4547
                    }
4548
                    function stopClickEventPropagation(event) {
4549
                        COMPATIBILITY.stpP(event);
4550
                    }
4551
                    function documentKeyDown(event) {
4552
                        if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
4553
                            increaseTrackScrollAmount();
4554
                    }
4555
                    function documentKeyUp(event) {
4556
                        if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
4557
                            decreaseTrackScrollAmount();
4558
                    }
4559
                    function onMouseTouchDownContinue(event) {
4560
                        var originalEvent = event.originalEvent || event;
4561
                        var isTouchEvent = originalEvent.touches !== undefined;
4562
                        return _sleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
4563
                    }
4564
                    function documentDragMove(event) {
4565
                        if (onMouseTouchDownContinue(event)) {
4566
                            var trackLength = scrollbarVarsInfo._trackLength;
4567
                            var handleLength = scrollbarVarsInfo._handleLength;
4568
                            var scrollRange = scrollbarVarsInfo._maxScroll;
4569
                            var scrollRaw = (getPointerPosition(event) - mouseDownOffset) * mouseDownInvertedScale;
4570
                            var scrollDeltaPercent = scrollRaw / (trackLength - handleLength);
4571
                            var scrollDelta = (scrollRange * scrollDeltaPercent);
4572
                            scrollDelta = isFinite(scrollDelta) ? scrollDelta : 0;
4573
                            if (_isRTL && isHorizontal && !_rtlScrollBehavior.i)
4574
                                scrollDelta *= -1;
4575

4576
                            _viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta));
4577

4578
                            if (_scrollbarsHandlesDefineScrollPos)
4579
                                refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta);
4580

4581
                            if (!_supportPassiveEvents)
4582
                                COMPATIBILITY.prvD(event);
4583
                        }
4584
                        else
4585
                            documentMouseTouchUp(event);
4586
                    }
4587
                    function documentMouseTouchUp(event) {
4588
                        event = event || event.originalEvent;
4589

4590
                        setupResponsiveEventListener(_documentElement,
4591
                            [_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],
4592
                            [documentDragMove, documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart],
4593
                            true);
4594
                        COMPATIBILITY.rAF()(function() {
4595
                            setupResponsiveEventListener(_documentElement, strClickEvent, stopClickEventPropagation, true, { _capture: true });
4596
                        });
4597
                        
4598
                            
4599
                        if (_scrollbarsHandlesDefineScrollPos)
4600
                            refreshScrollbarHandleOffset(isHorizontal, true);
4601

4602
                        _scrollbarsHandlesDefineScrollPos = false;
4603
                        removeClass(_bodyElement, _classNameDragging);
4604
                        removeClass(scrollbarVars._handle, strActive);
4605
                        removeClass(scrollbarVars._track, strActive);
4606
                        removeClass(scrollbarVars._scrollbar, strActive);
4607

4608
                        mouseDownScroll = undefined;
4609
                        mouseDownOffset = undefined;
4610
                        mouseDownInvertedScale = 1;
4611

4612
                        decreaseTrackScrollAmount();
4613

4614
                        if (trackTimeout !== undefined) {
4615
                            _base.scrollStop();
4616
                            clearTimeout(trackTimeout);
4617
                            trackTimeout = undefined;
4618
                        }
4619

4620
                        if (event) {
4621
                            var rect = _hostElementNative[LEXICON.bCR]();
4622
                            var mouseInsideHost = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
4623

4624
                            //if mouse is outside host element
4625
                            if (!mouseInsideHost)
4626
                                hostOnMouseLeave();
4627

4628
                            if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
4629
                                refreshScrollbarsAutoHide(false);
4630
                        }
4631
                    }
4632
                    function onHandleMouseTouchDown(event) {
4633
                        if (onMouseTouchDownContinue(event))
4634
                            onHandleMouseTouchDownAction(event);
4635
                    }
4636
                    function onHandleMouseTouchDownAction(event) {
4637
                        mouseDownScroll = _viewportElement[scroll]();
4638
                        mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll;
4639
                        if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL)
4640
                            mouseDownScroll = mouseDownScroll < 0 ? 0 : mouseDownScroll;
4641

4642
                        mouseDownInvertedScale = getHostElementInvertedScale()[xy];
4643
                        mouseDownOffset = getPointerPosition(event);
4644

4645
                        _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);
4646
                        addClass(_bodyElement, _classNameDragging);
4647
                        addClass(scrollbarVars._handle, strActive);
4648
                        addClass(scrollbarVars._scrollbar, strActive);
4649

4650
                        setupResponsiveEventListener(_documentElement,
4651
                            [_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strSelectStartEvent],
4652
                            [documentDragMove, documentMouseTouchUp, documentOnSelectStart]);
4653
                        COMPATIBILITY.rAF()(function() {
4654
                            setupResponsiveEventListener(_documentElement, strClickEvent, stopClickEventPropagation, false, { _capture: true });
4655
                        });
4656
                        
4657

4658
                        if (_msieVersion || !_documentMixed)
4659
                            COMPATIBILITY.prvD(event);
4660
                        COMPATIBILITY.stpP(event);
4661
                    }
4662
                    function onTrackMouseTouchDown(event) {
4663
                        if (onMouseTouchDownContinue(event)) {
4664
                            var handleToViewportRatio = scrollbarVars._info._handleLength / Math.round(MATH.min(1, _viewportSize[scrollbarVars._w_h] / _contentScrollSizeCache[scrollbarVars._w_h]) * scrollbarVars._info._trackLength);
4665
                            var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h] * handleToViewportRatio);
4666
                            var scrollBaseDuration = 270 * handleToViewportRatio;
4667
                            var scrollFirstIterationDelay = 400 * handleToViewportRatio;
4668
                            var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top];
4669
                            var ctrlKey = event.ctrlKey;
4670
                            var instantScroll = event.shiftKey;
4671
                            var instantScrollTransition = instantScroll && ctrlKey;
4672
                            var isFirstIteration = true;
4673
                            var easing = 'linear';
4674
                            var decreaseScroll;
4675
                            var finishedCondition;
4676
                            var scrollActionFinsished = function (transition) {
4677
                                if (_scrollbarsHandlesDefineScrollPos)
4678
                                    refreshScrollbarHandleOffset(isHorizontal, transition);
4679
                            };
4680
                            var scrollActionInstantFinished = function () {
4681
                                scrollActionFinsished();
4682
                                onHandleMouseTouchDownAction(event);
4683
                            };
4684
                            var scrollAction = function () {
4685
                                if (!_destroyed) {
4686
                                    var mouseOffset = (mouseDownOffset - trackOffset) * mouseDownInvertedScale;
4687
                                    var handleOffset = scrollbarVarsInfo._handleOffset;
4688
                                    var trackLength = scrollbarVarsInfo._trackLength;
4689
                                    var handleLength = scrollbarVarsInfo._handleLength;
4690
                                    var scrollRange = scrollbarVarsInfo._maxScroll;
4691
                                    var currScroll = scrollbarVarsInfo._currentScroll;
4692
                                    var scrollDuration = scrollBaseDuration * scrollDurationFactor;
4693
                                    var timeoutDelay = isFirstIteration ? MATH.max(scrollFirstIterationDelay, scrollDuration) : scrollDuration;
4694
                                    var instantScrollPosition = scrollRange * ((mouseOffset - (handleLength / 2)) / (trackLength - handleLength)); // 100% * positionPercent
4695
                                    var rtlIsNormal = _isRTL && isHorizontal && ((!_rtlScrollBehavior.i && !_rtlScrollBehavior.n) || _normalizeRTLCache);
4696
                                    var decreaseScrollCondition = rtlIsNormal ? handleOffset < mouseOffset : handleOffset > mouseOffset;
4697
                                    var scrollObj = {};
4698
                                    var animationObj = {
4699
                                        easing: easing,
4700
                                        step: function (now) {
4701
                                            if (_scrollbarsHandlesDefineScrollPos) {
4702
                                                _viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/4340
4703
                                                refreshScrollbarHandleOffset(isHorizontal, now);
4704
                                            }
4705
                                        }
4706
                                    };
4707
                                    instantScrollPosition = isFinite(instantScrollPosition) ? instantScrollPosition : 0;
4708
                                    instantScrollPosition = _isRTL && isHorizontal && !_rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
4709

4710
                                    //_base.scrollStop();
4711

4712
                                    if (instantScroll) {
4713
                                        _viewportElement[scroll](instantScrollPosition); //scroll instantly to new position
4714
                                        if (instantScrollTransition) {
4715
                                            //get the scroll position after instant scroll (in case CSS Snap Points are used) to get the correct snapped scroll position
4716
                                            //and the animation stops at the correct point
4717
                                            instantScrollPosition = _viewportElement[scroll]();
4718
                                            //scroll back to the position before instant scrolling so animation can be performed
4719
                                            _viewportElement[scroll](currScroll);
4720

4721
                                            instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
4722
                                            instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.n ? -instantScrollPosition : instantScrollPosition;
4723

4724
                                            scrollObj[xy] = instantScrollPosition;
4725
                                            _base.scroll(scrollObj, extendDeep(animationObj, {
4726
                                                duration: 130,
4727
                                                complete: scrollActionInstantFinished
4728
                                            }));
4729
                                        }
4730
                                        else
4731
                                            scrollActionInstantFinished();
4732
                                    }
4733
                                    else {
4734
                                        decreaseScroll = isFirstIteration ? decreaseScrollCondition : decreaseScroll;
4735
                                        finishedCondition = rtlIsNormal
4736
                                            ? (decreaseScroll ? handleOffset + handleLength >= mouseOffset : handleOffset <= mouseOffset)
4737
                                            : (decreaseScroll ? handleOffset <= mouseOffset : handleOffset + handleLength >= mouseOffset);
4738

4739
                                        if (finishedCondition) {
4740
                                            clearTimeout(trackTimeout);
4741
                                            _base.scrollStop();
4742
                                            trackTimeout = undefined;
4743
                                            scrollActionFinsished(true);
4744
                                        }
4745
                                        else {
4746
                                            trackTimeout = setTimeout(scrollAction, timeoutDelay);
4747

4748
                                            scrollObj[xy] = (decreaseScroll ? '-=' : '+=') + scrollDistance;
4749
                                            _base.scroll(scrollObj, extendDeep(animationObj, {
4750
                                                duration: scrollDuration
4751
                                            }));
4752
                                        }
4753
                                        isFirstIteration = false;
4754
                                    }
4755
                                }
4756
                            };
4757
                            if (ctrlKey)
4758
                                increaseTrackScrollAmount();
4759

4760
                            mouseDownInvertedScale = getHostElementInvertedScale()[xy];
4761
                            mouseDownOffset = COMPATIBILITY.page(event)[xy];
4762

4763
                            _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);
4764
                            addClass(_bodyElement, _classNameDragging);
4765
                            addClass(scrollbarVars._track, strActive);
4766
                            addClass(scrollbarVars._scrollbar, strActive);
4767

4768
                            setupResponsiveEventListener(_documentElement,
4769
                                [_strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],
4770
                                [documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart]);
4771

4772
                            scrollAction();
4773
                            COMPATIBILITY.prvD(event);
4774
                            COMPATIBILITY.stpP(event);
4775
                        }
4776
                    }
4777
                    function onTrackMouseTouchEnter(event) {
4778
                        //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move".
4779
                        _scrollbarsHandleHovered = true;
4780
                        if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
4781
                            refreshScrollbarsAutoHide(true);
4782
                    }
4783
                    function onTrackMouseTouchLeave(event) {
4784
                        _scrollbarsHandleHovered = false;
4785
                        if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
4786
                            refreshScrollbarsAutoHide(false);
4787
                    }
4788
                    function onScrollbarMouseTouchDown(event) {
4789
                        COMPATIBILITY.stpP(event);
4790
                    }
4791

4792
                    addDestroyEventListener(scrollbarVars._handle,
4793
                        _strMouseTouchDownEvent,
4794
                        onHandleMouseTouchDown);
4795
                    addDestroyEventListener(scrollbarVars._track,
4796
                        [_strMouseTouchDownEvent, _strMouseEnter, _strMouseLeave],
4797
                        [onTrackMouseTouchDown, onTrackMouseTouchEnter, onTrackMouseTouchLeave]);
4798
                    addDestroyEventListener(scrollbarVars._scrollbar,
4799
                        _strMouseTouchDownEvent,
4800
                        onScrollbarMouseTouchDown);
4801

4802
                    if (_supportTransition) {
4803
                        addDestroyEventListener(scrollbarVars._scrollbar, _strTransitionEndEvent, function (event) {
4804
                            if (event.target !== scrollbarVars._scrollbar[0])
4805
                                return;
4806
                            refreshScrollbarHandleLength(isHorizontal);
4807
                            refreshScrollbarHandleOffset(isHorizontal);
4808
                        });
4809
                    }
4810
                }
4811

4812
                /**
4813
                 * Shows or hides the given scrollbar and applied a class name which indicates if the scrollbar is scrollable or not.
4814
                 * @param isHorizontal True if the horizontal scrollbar is the target, false if the vertical scrollbar is the target.
4815
                 * @param shallBeVisible True if the scrollbar shall be shown, false if hidden.
4816
                 * @param canScroll True if the scrollbar is scrollable, false otherwise.
4817
                 */
4818
                function refreshScrollbarAppearance(isHorizontal, shallBeVisible, canScroll) {
4819
                    var scrollbarHiddenClassName = isHorizontal ? _classNameHostScrollbarHorizontalHidden : _classNameHostScrollbarVerticalHidden;
4820
                    var scrollbarElement = isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement;
4821

4822
                    addRemoveClass(_hostElement, scrollbarHiddenClassName, !shallBeVisible);
4823
                    addRemoveClass(scrollbarElement, _classNameScrollbarUnusable, !canScroll);
4824
                }
4825

4826
                /**
4827
                 * Autoshows / autohides both scrollbars with.
4828
                 * @param shallBeVisible True if the scrollbars shall be autoshown (only the case if they are hidden by a autohide), false if the shall be auto hidden.
4829
                 * @param delayfree True if the scrollbars shall be hidden without a delay, false or undefined otherwise.
4830
                 */
4831
                function refreshScrollbarsAutoHide(shallBeVisible, delayfree) {
4832
                    clearTimeout(_scrollbarsAutoHideTimeoutId);
4833
                    if (shallBeVisible) {
4834
                        //if(_hasOverflowCache.x && _hideOverflowCache.xs)
4835
                        removeClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
4836
                        //if(_hasOverflowCache.y && _hideOverflowCache.ys)
4837
                        removeClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
4838
                    }
4839
                    else {
4840
                        var anyActive;
4841
                        var strActive = 'active';
4842
                        var hide = function () {
4843
                            if (!_scrollbarsHandleHovered && !_destroyed) {
4844
                                anyActive = _scrollbarHorizontalHandleElement.hasClass(strActive) || _scrollbarVerticalHandleElement.hasClass(strActive);
4845
                                if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
4846
                                    addClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
4847
                                if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
4848
                                    addClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
4849
                            }
4850
                        };
4851
                        if (_scrollbarsAutoHideDelay > 0 && delayfree !== true)
4852
                            _scrollbarsAutoHideTimeoutId = setTimeout(hide, _scrollbarsAutoHideDelay);
4853
                        else
4854
                            hide();
4855
                    }
4856
                }
4857

4858
                /**
4859
                 * Refreshes the handle length of the given scrollbar.
4860
                 * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
4861
                 */
4862
                function refreshScrollbarHandleLength(isHorizontal) {
4863
                    var handleCSS = {};
4864
                    var scrollbarVars = getScrollbarVars(isHorizontal);
4865
                    var scrollbarVarsInfo = scrollbarVars._info;
4866
                    var digit = 1000000;
4867
                    //get and apply intended handle length
4868
                    var handleRatio = MATH.min(1, _viewportSize[scrollbarVars._w_h] / _contentScrollSizeCache[scrollbarVars._w_h]);
4869
                    handleCSS[scrollbarVars._width_height] = (MATH.floor(handleRatio * 100 * digit) / digit) + '%'; //the last * digit / digit is for flooring to the 4th digit
4870

4871
                    if (!nativeOverlayScrollbarsAreActive())
4872
                        scrollbarVars._handle.css(handleCSS);
4873

4874
                    //measure the handle length to respect min & max length
4875
                    scrollbarVarsInfo._handleLength = scrollbarVars._handle[0]['offset' + scrollbarVars._Width_Height];
4876
                    scrollbarVarsInfo._handleLengthRatio = handleRatio;
4877
                }
4878

4879
                /**
4880
                 * Refreshes the handle offset of the given scrollbar.
4881
                 * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
4882
                 * @param scrollOrTransition The scroll position of the given scrollbar axis to which the handle shall be moved or a boolean which indicates whether a transition shall be applied. If undefined or boolean if the current scroll-offset is taken. (if isHorizontal ? scrollLeft : scrollTop)
4883
                 */
4884
                function refreshScrollbarHandleOffset(isHorizontal, scrollOrTransition) {
4885
                    var transition = type(scrollOrTransition) == TYPES.b;
4886
                    var transitionDuration = 250;
4887
                    var isRTLisHorizontal = _isRTL && isHorizontal;
4888
                    var scrollbarVars = getScrollbarVars(isHorizontal);
4889
                    var scrollbarVarsInfo = scrollbarVars._info;
4890
                    var strTranslateBrace = 'translate(';
4891
                    var strTransform = VENDORS._cssProperty('transform');
4892
                    var strTransition = VENDORS._cssProperty('transition');
4893
                    var nativeScroll = isHorizontal ? _viewportElement[_strScrollLeft]() : _viewportElement[_strScrollTop]();
4894
                    var currentScroll = scrollOrTransition === undefined || transition ? nativeScroll : scrollOrTransition;
4895

4896
                    //measure the handle length to respect min & max length
4897
                    var handleLength = scrollbarVarsInfo._handleLength;
4898
                    var trackLength = scrollbarVars._track[0]['offset' + scrollbarVars._Width_Height];
4899
                    var handleTrackDiff = trackLength - handleLength;
4900
                    var handleCSS = {};
4901
                    var transformOffset;
4902
                    var translateValue;
4903

4904
                    //DONT use the variable '_contentScrollSizeCache[scrollbarVars._w_h]' instead of '_viewportElement[0]['scroll' + scrollbarVars._Width_Height]'
4905
                    // because its a bit behind during the small delay when content size updates
4906
                    //(delay = mutationObserverContentLag, if its 0 then this var could be used)
4907
                    var maxScroll = (_viewportElementNative[_strScroll + scrollbarVars._Width_Height] - _viewportElementNative['client' + scrollbarVars._Width_Height]) * (_rtlScrollBehavior.n && isRTLisHorizontal ? -1 : 1); //* -1 if rtl scroll max is negative
4908
                    var getScrollRatio = function (base) {
4909
                        return isNaN(base / maxScroll) ? 0 : MATH.max(0, MATH.min(1, base / maxScroll));
4910
                    };
4911
                    var getHandleOffset = function (scrollRatio) {
4912
                        var offset = handleTrackDiff * scrollRatio;
4913
                        offset = isNaN(offset) ? 0 : offset;
4914
                        offset = (isRTLisHorizontal && !_rtlScrollBehavior.i) ? (trackLength - handleLength - offset) : offset;
4915
                        offset = MATH.max(0, offset);
4916
                        return offset;
4917
                    };
4918
                    var scrollRatio = getScrollRatio(nativeScroll);
4919
                    var unsnappedScrollRatio = getScrollRatio(currentScroll);
4920
                    var handleOffset = getHandleOffset(unsnappedScrollRatio);
4921
                    var snappedHandleOffset = getHandleOffset(scrollRatio);
4922

4923
                    scrollbarVarsInfo._maxScroll = maxScroll;
4924
                    scrollbarVarsInfo._currentScroll = nativeScroll;
4925
                    scrollbarVarsInfo._currentScrollRatio = scrollRatio;
4926

4927
                    if (_supportTransform) {
4928
                        transformOffset = isRTLisHorizontal ? -(trackLength - handleLength - handleOffset) : handleOffset; //in px
4929
                        //transformOffset = (transformOffset / trackLength * 100) * (trackLength / handleLength); //in %
4930
                        translateValue = isHorizontal ? strTranslateBrace + transformOffset + 'px, 0)' : strTranslateBrace + '0, ' + transformOffset + 'px)';
4931

4932
                        handleCSS[strTransform] = translateValue;
4933

4934
                        //apply or clear up transition
4935
                        if (_supportTransition)
4936
                            handleCSS[strTransition] = transition && MATH.abs(handleOffset - scrollbarVarsInfo._handleOffset) > 1 ? getCSSTransitionString(scrollbarVars._handle) + ', ' + (strTransform + _strSpace + transitionDuration + 'ms') : _strEmpty;
4937
                    }
4938
                    else
4939
                        handleCSS[scrollbarVars._left_top] = handleOffset;
4940

4941

4942
                    //only apply css if offset has changed and overflow exists.
4943
                    if (!nativeOverlayScrollbarsAreActive()) {
4944
                        scrollbarVars._handle.css(handleCSS);
4945

4946
                        //clear up transition
4947
                        if (_supportTransform && _supportTransition && transition) {
4948
                            scrollbarVars._handle.one(_strTransitionEndEvent, function () {
4949
                                if (!_destroyed)
4950
                                    scrollbarVars._handle.css(strTransition, _strEmpty);
4951
                            });
4952
                        }
4953
                    }
4954

4955
                    scrollbarVarsInfo._handleOffset = handleOffset;
4956
                    scrollbarVarsInfo._snappedHandleOffset = snappedHandleOffset;
4957
                    scrollbarVarsInfo._trackLength = trackLength;
4958
                }
4959

4960
                /**
4961
                 * Refreshes the interactivity of the given scrollbar element.
4962
                 * @param isTrack True if the track element is the target, false if the handle element is the target.
4963
                 * @param value True for interactivity false for no interactivity.
4964
                 */
4965
                function refreshScrollbarsInteractive(isTrack, value) {
4966
                    var action = value ? 'removeClass' : 'addClass';
4967
                    var element1 = isTrack ? _scrollbarHorizontalTrackElement : _scrollbarHorizontalHandleElement;
4968
                    var element2 = isTrack ? _scrollbarVerticalTrackElement : _scrollbarVerticalHandleElement;
4969
                    var className = isTrack ? _classNameScrollbarTrackOff : _classNameScrollbarHandleOff;
4970

4971
                    element1[action](className);
4972
                    element2[action](className);
4973
                }
4974

4975
                /**
4976
                 * Returns a object which is used for fast access for specific variables.
4977
                 * @param isHorizontal True if the horizontal scrollbar vars shall be accessed, false if the vertical scrollbar vars shall be accessed.
4978
                 * @returns {{wh: string, WH: string, lt: string, _wh: string, _lt: string, t: *, h: *, c: {}, s: *}}
4979
                 */
4980
                function getScrollbarVars(isHorizontal) {
4981
                    return {
4982
                        _width_height: isHorizontal ? _strWidth : _strHeight,
4983
                        _Width_Height: isHorizontal ? 'Width' : 'Height',
4984
                        _left_top: isHorizontal ? _strLeft : _strTop,
4985
                        _Left_Top: isHorizontal ? 'Left' : 'Top',
4986
                        _x_y: isHorizontal ? _strX : _strY,
4987
                        _X_Y: isHorizontal ? 'X' : 'Y',
4988
                        _w_h: isHorizontal ? 'w' : 'h',
4989
                        _l_t: isHorizontal ? 'l' : 't',
4990
                        _track: isHorizontal ? _scrollbarHorizontalTrackElement : _scrollbarVerticalTrackElement,
4991
                        _handle: isHorizontal ? _scrollbarHorizontalHandleElement : _scrollbarVerticalHandleElement,
4992
                        _scrollbar: isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement,
4993
                        _info: isHorizontal ? _scrollHorizontalInfo : _scrollVerticalInfo
4994
                    };
4995
                }
4996

4997

4998
                //==== Scrollbar Corner ====//
4999

5000
                /**
5001
                 * Builds or destroys the scrollbar corner DOM element.
5002
                 * @param destroy Indicates whether the DOM shall be build or destroyed.
5003
                 */
5004
                function setupScrollbarCornerDOM(destroy) {
5005
                    _scrollbarCornerElement = _scrollbarCornerElement || selectOrGenerateDivByClass(_classNameScrollbarCorner, true);
5006

5007
                    if (!destroy) {
5008
                        if (!_domExists) {
5009
                            _hostElement.append(_scrollbarCornerElement);
5010
                        }
5011
                    }
5012
                    else {
5013
                        if (_domExists && _initialized) {
5014
                            removeClass(_scrollbarCornerElement.removeAttr(LEXICON.s), _classNamesDynamicDestroy);
5015
                        }
5016
                        else {
5017
                            remove(_scrollbarCornerElement);
5018
                        }
5019
                    }
5020
                }
5021

5022
                /**
5023
                 * Initializes all scrollbar corner interactivity events.
5024
                 */
5025
                function setupScrollbarCornerEvents() {
5026
                    var insideIFrame = _windowElementNative.top !== _windowElementNative;
5027
                    var mouseDownPosition = {};
5028
                    var mouseDownSize = {};
5029
                    var mouseDownInvertedScale = {};
5030
                    var reconnectMutationObserver;
5031

5032
                    function documentDragMove(event) {
5033
                        if (onMouseTouchDownContinue(event)) {
5034
                            var pageOffset = getCoordinates(event);
5035
                            var hostElementCSS = {};
5036
                            if (_resizeHorizontal || _resizeBoth)
5037
                                hostElementCSS[_strWidth] = (mouseDownSize.w + (pageOffset.x - mouseDownPosition.x) * mouseDownInvertedScale.x);
5038
                            if (_resizeVertical || _resizeBoth)
5039
                                hostElementCSS[_strHeight] = (mouseDownSize.h + (pageOffset.y - mouseDownPosition.y) * mouseDownInvertedScale.y);
5040
                            _hostElement.css(hostElementCSS);
5041
                            COMPATIBILITY.stpP(event);
5042
                        }
5043
                        else {
5044
                            documentMouseTouchUp(event);
5045
                        }
5046
                    }
5047
                    function documentMouseTouchUp(event) {
5048
                        var eventIsTrusted = event !== undefined;
5049

5050
                        setupResponsiveEventListener(_documentElement,
5051
                            [_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],
5052
                            [documentOnSelectStart, documentDragMove, documentMouseTouchUp],
5053
                            true);
5054

5055
                        removeClass(_bodyElement, _classNameDragging);
5056
                        if (_scrollbarCornerElement.releaseCapture)
5057
                            _scrollbarCornerElement.releaseCapture();
5058

5059
                        if (eventIsTrusted) {
5060
                            if (reconnectMutationObserver)
5061
                                connectMutationObservers();
5062
                            _base.update(_strAuto);
5063
                        }
5064
                        reconnectMutationObserver = false;
5065
                    }
5066
                    function onMouseTouchDownContinue(event) {
5067
                        var originalEvent = event.originalEvent || event;
5068
                        var isTouchEvent = originalEvent.touches !== undefined;
5069
                        return _sleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
5070
                    }
5071
                    function getCoordinates(event) {
5072
                        return _msieVersion && insideIFrame ? { x: event.screenX, y: event.screenY } : COMPATIBILITY.page(event);
5073
                    }
5074

5075
                    addDestroyEventListener(_scrollbarCornerElement, _strMouseTouchDownEvent, function (event) {
5076
                        if (onMouseTouchDownContinue(event) && !_resizeNone) {
5077
                            if (_mutationObserversConnected) {
5078
                                reconnectMutationObserver = true;
5079
                                disconnectMutationObservers();
5080
                            }
5081

5082
                            mouseDownPosition = getCoordinates(event);
5083

5084
                            mouseDownSize.w = _hostElementNative[LEXICON.oW] - (!_isBorderBox ? _paddingX : 0);
5085
                            mouseDownSize.h = _hostElementNative[LEXICON.oH] - (!_isBorderBox ? _paddingY : 0);
5086
                            mouseDownInvertedScale = getHostElementInvertedScale();
5087

5088
                            setupResponsiveEventListener(_documentElement,
5089
                                [_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],
5090
                                [documentOnSelectStart, documentDragMove, documentMouseTouchUp]);
5091

5092
                            addClass(_bodyElement, _classNameDragging);
5093
                            if (_scrollbarCornerElement.setCapture)
5094
                                _scrollbarCornerElement.setCapture();
5095

5096
                            COMPATIBILITY.prvD(event);
5097
                            COMPATIBILITY.stpP(event);
5098
                        }
5099
                    });
5100
                }
5101

5102

5103
                //==== Utils ====//
5104

5105
                /**
5106
                 * Calls the callback with the given name. The Context of this callback is always _base (this).
5107
                 * @param name The name of the target which shall be called.
5108
                 * @param args The args with which the callback shall be called.
5109
                 * @param dependent Boolean which decides whether the callback shall be fired, undefined is like a "true" value.
5110
                 */
5111
                function dispatchCallback(name, args, dependent) {
5112
                    if (dependent === false)
5113
                        return;
5114
                    if (_initialized) {
5115
                        var callback = _currentPreparedOptions.callbacks[name];
5116
                        var extensionOnName = name;
5117
                        var ext;
5118

5119
                        if (extensionOnName.substr(0, 2) === 'on')
5120
                            extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3);
5121

5122
                        if (type(callback) == TYPES.f)
5123
                            callback.call(_base, args);
5124

5125
                        each(_extensions, function () {
5126
                            ext = this;
5127
                            if (type(ext.on) == TYPES.f)
5128
                                ext.on(extensionOnName, args);
5129
                        });
5130
                    }
5131
                    else if (!_destroyed)
5132
                        _callbacksInitQeueue.push({ n: name, a: args });
5133
                }
5134

5135
                /**
5136
                 * Sets the "top, right, bottom, left" properties, with a given prefix, of the given css object.
5137
                 * @param targetCSSObject The css object to which the values shall be applied.
5138
                 * @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
5139
                 * @param values A array of values which shall be applied to the "top, right, bottom, left" -properties. The array order is [top, right, bottom, left].
5140
                 * If this argument is undefined the value '' (empty string) will be applied to all properties.
5141
                 */
5142
                function setTopRightBottomLeft(targetCSSObject, prefix, values) {
5143
                    prefix = prefix || _strEmpty;
5144
                    values = values || [_strEmpty, _strEmpty, _strEmpty, _strEmpty];
5145

5146
                    targetCSSObject[prefix + _strTop] = values[0];
5147
                    targetCSSObject[prefix + _strRight] = values[1];
5148
                    targetCSSObject[prefix + _strBottom] = values[2];
5149
                    targetCSSObject[prefix + _strLeft] = values[3];
5150
                }
5151

5152
                /**
5153
                 * Gets the "top, right, bottom, left" CSS properties of the CSS property with the given prefix from the host element.
5154
                 * @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
5155
                 * @param suffix The suffix of the "top, right, bottom, left" css properties. (example: 'border-' is a valid prefix with '-width' is a valid suffix)
5156
                 * @param zeroX True if the x axis shall be 0.
5157
                 * @param zeroY True if the y axis shall be 0.
5158
                 * @returns {{}} The object which contains the numbers of the read CSS properties.
5159
                 */
5160
                function getTopRightBottomLeftHost(prefix, suffix, zeroX, zeroY) {
5161
                    suffix = suffix || _strEmpty;
5162
                    prefix = prefix || _strEmpty;
5163
                    return {
5164
                        t: zeroY ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strTop + suffix)),
5165
                        r: zeroX ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strRight + suffix)),
5166
                        b: zeroY ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strBottom + suffix)),
5167
                        l: zeroX ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strLeft + suffix))
5168
                    };
5169
                }
5170

5171
                /**
5172
                 * Returns the computed CSS transition string from the given element.
5173
                 * @param element The element from which the transition string shall be returned.
5174
                 * @returns {string} The CSS transition string from the given element.
5175
                 */
5176
                function getCSSTransitionString(element) {
5177
                    var transitionStr = VENDORS._cssProperty('transition');
5178
                    var assembledValue = element.css(transitionStr);
5179
                    if (assembledValue)
5180
                        return assembledValue;
5181
                    var regExpString = '\\s*(' + '([^,(]+(\\(.+?\\))?)+' + ')[\\s,]*';
5182
                    var regExpMain = new RegExp(regExpString);
5183
                    var regExpValidate = new RegExp('^(' + regExpString + ')+$');
5184
                    var properties = 'property duration timing-function delay'.split(' ');
5185
                    var result = [];
5186
                    var strResult;
5187
                    var valueArray;
5188
                    var i = 0;
5189
                    var j;
5190
                    var splitCssStyleByComma = function (str) {
5191
                        strResult = [];
5192
                        if (!str.match(regExpValidate))
5193
                            return str;
5194
                        while (str.match(regExpMain)) {
5195
                            strResult.push(RegExp.$1);
5196
                            str = str.replace(regExpMain, _strEmpty);
5197
                        }
5198

5199
                        return strResult;
5200
                    };
5201
                    for (; i < properties[LEXICON.l]; i++) {
5202
                        valueArray = splitCssStyleByComma(element.css(transitionStr + '-' + properties[i]));
5203
                        for (j = 0; j < valueArray[LEXICON.l]; j++)
5204
                            result[j] = (result[j] ? result[j] + _strSpace : _strEmpty) + valueArray[j];
5205
                    }
5206
                    return result.join(', ');
5207
                }
5208

5209
                /**
5210
                 * Generates a Regular Expression which matches with a string which starts with 'os-host'.
5211
                 * @param {boolean} withCurrClassNameOption The Regular Expression also matches if the string is the current ClassName option (multiple values splitted by space possible).
5212
                 * @param {boolean} withOldClassNameOption The Regular Expression also matches if the string is the old ClassName option (multiple values splitted by space possible).
5213
                 */
5214
                function createHostClassNameRegExp(withCurrClassNameOption, withOldClassNameOption) {
5215
                    var i;
5216
                    var split;
5217
                    var appendix;
5218
                    var appendClasses = function (classes, condition) {
5219
                        appendix = '';
5220
                        if (condition && typeof classes == TYPES.s) {
5221
                            split = classes.split(_strSpace);
5222
                            for (i = 0; i < split[LEXICON.l]; i++)
5223
                                appendix += '|' + split[i] + '$';
5224
                            // split[i].replace(/[.*+?^${}()|[\]\\]/g, '\\$&') for escaping regex characters
5225
                        }
5226
                        return appendix;
5227
                    };
5228

5229
                    return new RegExp(
5230
                        '(^' + _classNameHostElement + '([-_].+|)$)' +
5231
                        appendClasses(_classNameCache, withCurrClassNameOption) +
5232
                        appendClasses(_oldClassName, withOldClassNameOption), 'g');
5233
                }
5234

5235
                /**
5236
                 * Calculates the host-elements inverted scale. (invertedScale = 1 / scale)
5237
                 * @returns {{x: number, y: number}} The scale of the host-element.
5238
                 */
5239
                function getHostElementInvertedScale() {
5240
                    var rect = _paddingElementNative[LEXICON.bCR]();
5241
                    return {
5242
                        x: _supportTransform ? 1 / (MATH.round(rect.width) / _paddingElementNative[LEXICON.oW]) || 1 : 1,
5243
                        y: _supportTransform ? 1 / (MATH.round(rect.height) / _paddingElementNative[LEXICON.oH]) || 1 : 1
5244
                    };
5245
                }
5246

5247
                /**
5248
                 * Checks whether the given object is a HTMLElement.
5249
                 * @param o The object which shall be checked.
5250
                 * @returns {boolean} True the given object is a HTMLElement, false otherwise.
5251
                 */
5252
                function isHTMLElement(o) {
5253
                    var strOwnerDocument = 'ownerDocument';
5254
                    var strHTMLElement = 'HTMLElement';
5255
                    var wnd = o && o[strOwnerDocument] ? (o[strOwnerDocument].parentWindow || window) : window;
5256
                    return (
5257
                        typeof wnd[strHTMLElement] == TYPES.o ? o instanceof wnd[strHTMLElement] : //DOM2
5258
                            o && typeof o == TYPES.o && o !== null && o.nodeType === 1 && typeof o.nodeName == TYPES.s
5259
                    );
5260
                }
5261

5262
                /**
5263
                 * Compares 2 arrays and returns the differences between them as a array.
5264
                 * @param a1 The first array which shall be compared.
5265
                 * @param a2 The second array which shall be compared.
5266
                 * @returns {Array} The differences between the two arrays.
5267
                 */
5268
                function getArrayDifferences(a1, a2) {
5269
                    var a = [];
5270
                    var diff = [];
5271
                    var i;
5272
                    var k;
5273
                    for (i = 0; i < a1.length; i++)
5274
                        a[a1[i]] = true;
5275
                    for (i = 0; i < a2.length; i++) {
5276
                        if (a[a2[i]])
5277
                            delete a[a2[i]];
5278
                        else
5279
                            a[a2[i]] = true;
5280
                    }
5281
                    for (k in a)
5282
                        diff.push(k);
5283
                    return diff;
5284
                }
5285

5286
                /**
5287
                 * Returns Zero or the number to which the value can be parsed.
5288
                 * @param value The value which shall be parsed.
5289
                 * @param toFloat Indicates whether the number shall be parsed to a float.
5290
                 */
5291
                function parseToZeroOrNumber(value, toFloat) {
5292
                    var num = toFloat ? parseFloat(value) : parseInt(value, 10);
5293
                    return isNaN(num) ? 0 : num;
5294
                }
5295

5296
                /**
5297
                 * Gets several information of the textarea and returns them as a object or undefined if the browser doesn't support it.
5298
                 * @returns {{cursorRow: Number, cursorCol, rows: Number, cols: number, wRow: number, pos: number, max : number}} or undefined if not supported.
5299
                 */
5300
                function getTextareaInfo() {
5301
                    //read needed values
5302
                    var textareaCursorPosition = _targetElementNative.selectionStart;
5303
                    if (textareaCursorPosition === undefined)
5304
                        return;
5305

5306
                    var textareaValue = _targetElement.val();
5307
                    var textareaLength = textareaValue[LEXICON.l];
5308
                    var textareaRowSplit = textareaValue.split('\n');
5309
                    var textareaLastRow = textareaRowSplit[LEXICON.l];
5310
                    var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split('\n');
5311
                    var widestRow = 0;
5312
                    var textareaLastCol = 0;
5313
                    var cursorRow = textareaCurrentCursorRowSplit[LEXICON.l];
5314
                    var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[LEXICON.l] - 1][LEXICON.l];
5315
                    var rowCols;
5316
                    var i;
5317

5318
                    //get widest Row and the last column of the textarea
5319
                    for (i = 0; i < textareaRowSplit[LEXICON.l]; i++) {
5320
                        rowCols = textareaRowSplit[i][LEXICON.l];
5321
                        if (rowCols > textareaLastCol) {
5322
                            widestRow = i + 1;
5323
                            textareaLastCol = rowCols;
5324
                        }
5325
                    }
5326

5327
                    return {
5328
                        _cursorRow: cursorRow, //cursorRow
5329
                        _cursorColumn: cursorCol, //cursorCol
5330
                        _rows: textareaLastRow, //rows
5331
                        _columns: textareaLastCol, //cols
5332
                        _widestRow: widestRow, //wRow
5333
                        _cursorPosition: textareaCursorPosition, //pos
5334
                        _cursorMax: textareaLength //max
5335
                    };
5336
                }
5337

5338
                /**
5339
                 * Determines whether native overlay scrollbars are active.
5340
                 * @returns {boolean} True if native overlay scrollbars are active, false otherwise.
5341
                 */
5342
                function nativeOverlayScrollbarsAreActive() {
5343
                    return (_ignoreOverlayScrollbarHidingCache && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y));
5344
                }
5345

5346
                /**
5347
                 * Gets the element which is used to measure the content size.
5348
                 * @returns {*} TextareaCover if target element is textarea else the ContentElement.
5349
                 */
5350
                function getContentMeasureElement() {
5351
                    return _isTextarea ? _textareaCoverElement[0] : _contentElementNative;
5352
                }
5353

5354
                /**
5355
                 * Generates a string which represents a HTML div with the given classes or attributes.
5356
                 * @param classesOrAttrs The class of the div as string or a object which represents the attributes of the div. (The class attribute can also be written as "className".)
5357
                 * @param content The content of the div as string.
5358
                 * @returns {string} The concated string which represents a HTML div and its content.
5359
                 */
5360
                function generateDiv(classesOrAttrs, content) {
5361
                    return '<div ' + (classesOrAttrs ? type(classesOrAttrs) == TYPES.s ?
5362
                        'class="' + classesOrAttrs + '"' :
5363
                        (function () {
5364
                            var key;
5365
                            var attrs = _strEmpty;
5366
                            if (FRAMEWORK.isPlainObject(classesOrAttrs)) {
5367
                                for (key in classesOrAttrs)
5368
                                    attrs += (key === 'c' ? 'class' : key) + '="' + classesOrAttrs[key] + '" ';
5369
                            }
5370
                            return attrs;
5371
                        })() :
5372
                        _strEmpty) +
5373
                        '>' +
5374
                        (content || _strEmpty) +
5375
                        '</div>';
5376
                }
5377

5378
                /**
5379
                 * Selects or generates a div with the given class attribute.
5380
                 * @param className The class names (divided by spaces) of the div which shall be selected or generated.
5381
                 * @param selectParentOrOnlyChildren The parent element from which of the element shall be selected. (if undefined or boolean its hostElement)
5382
                 * If its a boolean it decides whether only the children of the host element shall be selected.
5383
                 * @returns {*} The generated or selected element.
5384
                 */
5385
                function selectOrGenerateDivByClass(className, selectParentOrOnlyChildren) {
5386
                    var onlyChildren = type(selectParentOrOnlyChildren) == TYPES.b;
5387
                    var selectParent = onlyChildren ? _hostElement : (selectParentOrOnlyChildren || _hostElement);
5388

5389
                    return (_domExists && !selectParent[LEXICON.l])
5390
                        ? null
5391
                        : _domExists
5392
                            ? selectParent[onlyChildren ? 'children' : 'find'](_strDot + className.replace(/\s/g, _strDot)).eq(0)
5393
                            : FRAMEWORK(generateDiv(className))
5394
                }
5395

5396
                /**
5397
                 * Gets the value of the given property from the given object.
5398
                 * @param obj The object from which the property value shall be got.
5399
                 * @param path The property of which the value shall be got.
5400
                 * @returns {*} Returns the value of the searched property or undefined of the property wasn't found.
5401
                 */
5402
                function getObjectPropVal(obj, path) {
5403
                    var splits = path.split(_strDot);
5404
                    var i = 0;
5405
                    var val;
5406
                    for (; i < splits.length; i++) {
5407
                        if (!obj[LEXICON.hOP](splits[i]))
5408
                            return;
5409
                        val = obj[splits[i]];
5410
                        if (i < splits.length && type(val) == TYPES.o)
5411
                            obj = val;
5412
                    }
5413
                    return val;
5414
                }
5415

5416
                /**
5417
                 * Sets the value of the given property from the given object.
5418
                 * @param obj The object from which the property value shall be set.
5419
                 * @param path The property of which the value shall be set.
5420
                 * @param val The value of the property which shall be set.
5421
                 */
5422
                function setObjectPropVal(obj, path, val) {
5423
                    var splits = path.split(_strDot);
5424
                    var splitsLength = splits.length;
5425
                    var i = 0;
5426
                    var extendObj = {};
5427
                    var extendObjRoot = extendObj;
5428
                    for (; i < splitsLength; i++)
5429
                        extendObj = extendObj[splits[i]] = i + 1 < splitsLength ? {} : val;
5430
                    FRAMEWORK.extend(obj, extendObjRoot, true);
5431
                }
5432

5433
                /**	
5434
                 * Runs a action for each selector inside the updateOnLoad option.	
5435
                 * @param {Function} action The action for each updateOnLoad selector, the arguments the function takes is the index and the value (the selector).	
5436
                 */
5437
                function eachUpdateOnLoad(action) {
5438
                    var updateOnLoad = _currentPreparedOptions.updateOnLoad;
5439
                    updateOnLoad = type(updateOnLoad) == TYPES.s ? updateOnLoad.split(_strSpace) : updateOnLoad;
5440

5441
                    if (COMPATIBILITY.isA(updateOnLoad) && !_destroyed) {
5442
                        each(updateOnLoad, action);
5443
                    }
5444
                }
5445

5446

5447
                //==== Utils Cache ====//
5448

5449
                /**
5450
                 * Compares two values or objects and returns true if they aren't equal.
5451
                 * @param current The first value or object which shall be compared.
5452
                 * @param cache The second value or object which shall be compared.
5453
                 * @param force If true the returned value is always true.
5454
                 * @returns {boolean} True if both values or objects aren't equal or force is true, false otherwise.
5455
                 */
5456
                function checkCache(current, cache, force) {
5457
                    if (force)
5458
                        return force;
5459
                    if (type(current) == TYPES.o && type(cache) == TYPES.o) {
5460
                        for (var prop in current) {
5461
                            if (prop !== 'c') {
5462
                                if (current[LEXICON.hOP](prop) && cache[LEXICON.hOP](prop)) {
5463
                                    if (checkCache(current[prop], cache[prop]))
5464
                                        return true;
5465
                                }
5466
                                else {
5467
                                    return true;
5468
                                }
5469
                            }
5470
                        }
5471
                    }
5472
                    else {
5473
                        return current !== cache;
5474
                    }
5475
                    return false;
5476
                }
5477

5478

5479
                //==== Shortcuts ====//
5480

5481
                /**
5482
                 * jQuery extend method shortcut with a appended "true" as first argument.
5483
                 */
5484
                function extendDeep() {
5485
                    return FRAMEWORK.extend.apply(this, [true].concat([].slice.call(arguments)));
5486
                }
5487

5488
                /**
5489
                 * jQuery addClass method shortcut.
5490
                 */
5491
                function addClass(el, classes) {
5492
                    return _frameworkProto.addClass.call(el, classes);
5493
                }
5494

5495
                /**
5496
                 * jQuery removeClass method shortcut.
5497
                 */
5498
                function removeClass(el, classes) {
5499
                    return _frameworkProto.removeClass.call(el, classes);
5500
                }
5501

5502
                /**
5503
                 * Adds or removes the given classes dependent on the boolean value. True for add, false for remove.
5504
                 */
5505
                function addRemoveClass(el, classes, doAdd) {
5506
                    return doAdd ? addClass(el, classes) : removeClass(el, classes);
5507
                }
5508

5509
                /**
5510
                 * jQuery remove method shortcut.
5511
                 */
5512
                function remove(el) {
5513
                    return _frameworkProto.remove.call(el);
5514
                }
5515

5516
                /**
5517
                 * Finds the first child element with the given selector of the given element.
5518
                 * @param el The root element from which the selector shall be valid.
5519
                 * @param selector The selector of the searched element.
5520
                 * @returns {*} The first element which is a child of the given element and matches the givens selector.
5521
                 */
5522
                function findFirst(el, selector) {
5523
                    return _frameworkProto.find.call(el, selector).eq(0);
5524
                }
5525

5526

5527
                //==== API ====//
5528

5529
                /**
5530
                 * Puts the instance to sleep. It wont respond to any changes in the DOM and won't update. Scrollbar Interactivity is also disabled as well as the resize handle.
5531
                 * This behavior can be reset by calling the update method.
5532
                 */
5533
                _base.sleep = function () {
5534
                    _sleeping = true;
5535
                };
5536

5537
                /**
5538
                 * Updates the plugin and DOM to the current options.
5539
                 * This method should only be called if a update is 100% required.
5540
                 * @param force True if every property shall be updated and the cache shall be ignored.
5541
                 * !INTERNAL USAGE! : force can be a string "auto", "sync" or "zoom" too
5542
                 * if "auto" then before a real update the content size and host element attributes gets checked, and if they changed only then the update method will be called.
5543
                 * if "sync" then the async update process (MutationObserver or UpdateLoop) gets synchronized and a corresponding update takes place if one was needed due to pending changes.
5544
                 * if "zoom" then a update takes place where it's assumed that content and host size changed
5545
                 * @returns {boolean|undefined} 
5546
                 * If force is "sync" then a boolean is returned which indicates whether a update was needed due to pending changes.
5547
                 * If force is "auto" then a boolean is returned whether a update was needed due to attribute or size changes.
5548
                 * undefined otherwise.
5549
                 */
5550
                _base.update = function (force) {
5551
                    if (_destroyed)
5552
                        return;
5553

5554
                    var attrsChanged;
5555
                    var contentSizeC;
5556
                    var isString = type(force) == TYPES.s;
5557
                    var doUpdateAuto;
5558
                    var mutHost;
5559
                    var mutContent;
5560

5561
                    if (isString) {
5562
                        if (force === _strAuto) {
5563
                            attrsChanged = meaningfulAttrsChanged();
5564
                            contentSizeC = updateAutoContentSizeChanged();
5565
                            doUpdateAuto = attrsChanged || contentSizeC;
5566
                            if (doUpdateAuto) {
5567
                                update({
5568
                                    _contentSizeChanged: contentSizeC,
5569
                                    _changedOptions: _initialized ? undefined : _currentPreparedOptions
5570
                                });
5571
                            }
5572
                        }
5573
                        else if (force === _strSync) {
5574
                            if (_mutationObserversConnected) {
5575
                                mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords());
5576
                                mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords());
5577
                            }
5578
                            else {
5579
                                mutHost = _base.update(_strAuto);
5580
                            }
5581
                        }
5582
                        else if (force === 'zoom') {
5583
                            update({
5584
                                _hostSizeChanged: true,
5585
                                _contentSizeChanged: true
5586
                            });
5587
                        }
5588
                    }
5589
                    else {
5590
                        force = _sleeping || force;
5591
                        _sleeping = false;
5592
                        if (!_base.update(_strSync) || force)
5593
                            update({ _force: force });
5594
                    }
5595

5596
                    updateElementsOnLoad();
5597

5598
                    return doUpdateAuto || mutHost || mutContent;
5599
                };
5600

5601
                /**
5602
                 Gets or sets the current options. The update method will be called automatically if new options were set.
5603
                 * @param newOptions If new options are given, then the new options will be set, if new options aren't given (undefined or a not a plain object) then the current options will be returned.
5604
                 * @param value If new options is a property path string, then this value will be used to set the option to which the property path string leads.
5605
                 * @returns {*}
5606
                 */
5607
                _base.options = function (newOptions, value) {
5608
                    var option = {};
5609
                    var changedOps;
5610

5611
                    //return current options if newOptions are undefined or empty
5612
                    if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) {
5613
                        if (type(newOptions) == TYPES.s) {
5614
                            if (arguments.length > 1) {
5615
                                setObjectPropVal(option, newOptions, value);
5616
                                changedOps = setOptions(option);
5617
                            }
5618
                            else
5619
                                return getObjectPropVal(_currentOptions, newOptions);
5620
                        }
5621
                        else
5622
                            return _currentOptions;
5623
                    }
5624
                    else {
5625
                        changedOps = setOptions(newOptions);
5626
                    }
5627

5628
                    if (!FRAMEWORK.isEmptyObject(changedOps)) {
5629
                        update({ _changedOptions: changedOps });
5630
                    }
5631
                };
5632

5633
                /**
5634
                 * Restore the DOM, disconnects all observers, remove all resize observers and put the instance to sleep.
5635
                 */
5636
                _base.destroy = function () {
5637
                    if (_destroyed)
5638
                        return;
5639

5640
                    //remove this instance from auto update loop
5641
                    autoUpdateLoop.remove(_base);
5642

5643
                    //disconnect all mutation observers
5644
                    disconnectMutationObservers();
5645

5646
                    //remove all resize observers
5647
                    setupResizeObserver(_sizeObserverElement);
5648
                    setupResizeObserver(_sizeAutoObserverElement);
5649

5650
                    //remove all extensions
5651
                    for (var extName in _extensions)
5652
                        _base.removeExt(extName);
5653

5654
                    //remove all 'destroy' events
5655
                    while (_destroyEvents[LEXICON.l] > 0)
5656
                        _destroyEvents.pop()();
5657

5658
                    //remove all events from host element
5659
                    setupHostMouseTouchEvents(true);
5660

5661
                    //remove all helper / detection elements
5662
                    if (_contentGlueElement)
5663
                        remove(_contentGlueElement);
5664
                    if (_contentArrangeElement)
5665
                        remove(_contentArrangeElement);
5666
                    if (_sizeAutoObserverAdded)
5667
                        remove(_sizeAutoObserverElement);
5668

5669
                    //remove all generated DOM
5670
                    setupScrollbarsDOM(true);
5671
                    setupScrollbarCornerDOM(true);
5672
                    setupStructureDOM(true);
5673

5674
                    //remove all generated image load events
5675
                    for (var i = 0; i < _updateOnLoadElms[LEXICON.l]; i++)
5676
                        FRAMEWORK(_updateOnLoadElms[i]).off(_updateOnLoadEventName, updateOnLoadCallback);
5677
                    _updateOnLoadElms = undefined;
5678

5679
                    _destroyed = true;
5680
                    _sleeping = true;
5681

5682
                    //remove this instance from the instances list
5683
                    INSTANCES(pluginTargetElement, 0);
5684
                    dispatchCallback('onDestroyed');
5685

5686
                    //remove all properties and methods
5687
                    //for (var property in _base)
5688
                    //    delete _base[property];
5689
                    //_base = undefined;
5690
                };
5691

5692
                /**
5693
                 * Scrolls to a given position or element.
5694
                 * @param coordinates
5695
                 * 1. Can be "coordinates" which looks like:
5696
                 *    { x : ?, y : ? } OR          Object with x and y properties
5697
                 *    { left : ?, top : ? } OR     Object with left and top properties
5698
                 *    { l : ?, t : ? } OR          Object with l and t properties
5699
                 *    [ ?, ? ] OR                  Array where the first two element are the coordinates (first is x, second is y)
5700
                 *    ?                            A single value which stays for both axis
5701
                 *    A value can be a number, a string or a calculation.
5702
                 *
5703
                 *    Operators:
5704
                 *    [NONE]  The current scroll will be overwritten by the value.
5705
                 *    '+='    The value will be added to the current scroll offset
5706
                 *    '-='    The value will be subtracted from the current scroll offset
5707
                 *    '*='    The current scroll wil be multiplicated by the value.
5708
                 *    '/='    The current scroll wil be divided by the value.
5709
                 *
5710
                 *    Units:
5711
                 *    [NONE]  The value is the final scroll amount.                   final = (value * 1)
5712
                 *    'px'    Same as none
5713
                 *    '%'     The value is dependent on the current scroll value.     final = ((currentScrollValue / 100) * value)
5714
                 *    'vw'    The value is multiplicated by the viewport width.       final = (value * viewportWidth)
5715
                 *    'vh'    The value is multiplicated by the viewport height.      final = (value * viewportHeight)
5716
                 *
5717
                 *    example final values:
5718
                 *    200, '200px', '50%', '1vw', '1vh', '+=200', '/=1vw', '*=2px', '-=5vh', '+=33%', '+= 50% - 2px', '-= 1vw - 50%'
5719
                 *
5720
                 * 2. Can be a HTML or jQuery element:
5721
                 *    The final scroll offset is the offset (without margin) of the given HTML / jQuery element.
5722
                 *
5723
                 * 3. Can be a object with a HTML or jQuery element with additional settings:
5724
                 *    {
5725
                 *      el : [HTMLElement, jQuery element],             MUST be specified, else this object isn't valid.
5726
                 *      scroll : [string, array, object],               Default value is 'always'.
5727
                 *      block : [string, array, object],                Default value is 'begin'.
5728
                 *      margin : [number, boolean, array, object]       Default value is false.
5729
                 *    }
5730
                 *
5731
                 *    Possible scroll settings are:
5732
                 *    'always'      Scrolls always.
5733
                 *    'ifneeded'    Scrolls only if the element isnt fully in view.
5734
                 *    'never'       Scrolls never.
5735
                 *
5736
                 *    Possible block settings are:
5737
                 *    'begin'   Both axis shall be docked to the "begin" edge. - The element will be docked to the top and left edge of the viewport.
5738
                 *    'end'     Both axis shall be docked to the "end" edge. - The element will be docked to the bottom and right edge of the viewport. (If direction is RTL to the bottom and left edge.)
5739
                 *    'center'  Both axis shall be docked to "center". - The element will be centered in the viewport.
5740
                 *    'nearest' The element will be docked to the nearest edge(s).
5741
                 *
5742
                 *    Possible margin settings are: -- The actual margin of the element wont be affect, this option affects only the final scroll offset.
5743
                 *    [BOOLEAN]                                         If true the css margin of the element will be used, if false no margin will be used.
5744
                 *    [NUMBER]                                          The margin will be used for all edges.
5745
                 *
5746
                 * @param duration The duration of the scroll animation, OR a jQuery animation configuration object.
5747
                 * @param easing The animation easing.
5748
                 * @param complete The animation complete callback.
5749
                 * @returns {{
5750
                 *   position: {x: number, y: number},
5751
                 *   ratio: {x: number, y: number},
5752
                 *   max: {x: number, y: number},
5753
                 *   handleOffset: {x: number, y: number},
5754
                 *   handleLength: {x: number, y: number},
5755
                 *   handleLengthRatio: {x: number, y: number}, t
5756
                 *   rackLength: {x: number, y: number},
5757
                 *   isRTL: boolean,
5758
                 *   isRTLNormalized: boolean
5759
                 *  }}
5760
                 */
5761
                _base.scroll = function (coordinates, duration, easing, complete) {
5762
                    if (arguments.length === 0 || coordinates === undefined) {
5763
                        var infoX = _scrollHorizontalInfo;
5764
                        var infoY = _scrollVerticalInfo;
5765
                        var normalizeInvert = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.i;
5766
                        var normalizeNegate = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.n;
5767
                        var scrollX = infoX._currentScroll;
5768
                        var scrollXRatio = infoX._currentScrollRatio;
5769
                        var maxScrollX = infoX._maxScroll;
5770
                        scrollXRatio = normalizeInvert ? 1 - scrollXRatio : scrollXRatio;
5771
                        scrollX = normalizeInvert ? maxScrollX - scrollX : scrollX;
5772
                        scrollX *= normalizeNegate ? -1 : 1;
5773
                        maxScrollX *= normalizeNegate ? -1 : 1;
5774

5775
                        return {
5776
                            position: {
5777
                                x: scrollX,
5778
                                y: infoY._currentScroll
5779
                            },
5780
                            ratio: {
5781
                                x: scrollXRatio,
5782
                                y: infoY._currentScrollRatio
5783
                            },
5784
                            max: {
5785
                                x: maxScrollX,
5786
                                y: infoY._maxScroll
5787
                            },
5788
                            handleOffset: {
5789
                                x: infoX._handleOffset,
5790
                                y: infoY._handleOffset
5791
                            },
5792
                            handleLength: {
5793
                                x: infoX._handleLength,
5794
                                y: infoY._handleLength
5795
                            },
5796
                            handleLengthRatio: {
5797
                                x: infoX._handleLengthRatio,
5798
                                y: infoY._handleLengthRatio
5799
                            },
5800
                            trackLength: {
5801
                                x: infoX._trackLength,
5802
                                y: infoY._trackLength
5803
                            },
5804
                            snappedHandleOffset: {
5805
                                x: infoX._snappedHandleOffset,
5806
                                y: infoY._snappedHandleOffset
5807
                            },
5808
                            isRTL: _isRTL,
5809
                            isRTLNormalized: _normalizeRTLCache
5810
                        };
5811
                    }
5812

5813
                    _base.update(_strSync);
5814

5815
                    var normalizeRTL = _normalizeRTLCache;
5816
                    var coordinatesXAxisProps = [_strX, _strLeft, 'l'];
5817
                    var coordinatesYAxisProps = [_strY, _strTop, 't'];
5818
                    var coordinatesOperators = ['+=', '-=', '*=', '/='];
5819
                    var durationIsObject = type(duration) == TYPES.o;
5820
                    var completeCallback = durationIsObject ? duration.complete : complete;
5821
                    var i;
5822
                    var finalScroll = {};
5823
                    var specialEasing = {};
5824
                    var doScrollLeft;
5825
                    var doScrollTop;
5826
                    var animationOptions;
5827
                    var strEnd = 'end';
5828
                    var strBegin = 'begin';
5829
                    var strCenter = 'center';
5830
                    var strNearest = 'nearest';
5831
                    var strAlways = 'always';
5832
                    var strNever = 'never';
5833
                    var strIfNeeded = 'ifneeded';
5834
                    var strLength = LEXICON.l;
5835
                    var settingsAxis;
5836
                    var settingsScroll;
5837
                    var settingsBlock;
5838
                    var settingsMargin;
5839
                    var finalElement;
5840
                    var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx'];
5841
                    var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest];
5842
                    var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded];
5843
                    var coordinatesIsElementObj = coordinates[LEXICON.hOP]('el');
5844
                    var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates;
5845
                    var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false;
5846
                    var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement);
5847
                    var updateScrollbarInfos = function () {
5848
                        if (doScrollLeft)
5849
                            refreshScrollbarHandleOffset(true);
5850
                        if (doScrollTop)
5851
                            refreshScrollbarHandleOffset(false);
5852
                    };
5853
                    var proxyCompleteCallback = type(completeCallback) != TYPES.f ? undefined : function () {
5854
                        updateScrollbarInfos();
5855
                        completeCallback();
5856
                    };
5857
                    function checkSettingsStringValue(currValue, allowedValues) {
5858
                        for (i = 0; i < allowedValues[strLength]; i++) {
5859
                            if (currValue === allowedValues[i])
5860
                                return true;
5861
                        }
5862
                        return false;
5863
                    }
5864
                    function getRawScroll(isX, coordinates) {
5865
                        var coordinateProps = isX ? coordinatesXAxisProps : coordinatesYAxisProps;
5866
                        coordinates = type(coordinates) == TYPES.s || type(coordinates) == TYPES.n ? [coordinates, coordinates] : coordinates;
5867

5868
                        if (COMPATIBILITY.isA(coordinates))
5869
                            return isX ? coordinates[0] : coordinates[1];
5870
                        else if (type(coordinates) == TYPES.o) {
5871
                            //decides RTL normalization "hack" with .n
5872
                            //normalizeRTL = type(coordinates.n) == TYPES.b ? coordinates.n : normalizeRTL; 
5873
                            for (i = 0; i < coordinateProps[strLength]; i++)
5874
                                if (coordinateProps[i] in coordinates)
5875
                                    return coordinates[coordinateProps[i]];
5876
                        }
5877
                    }
5878
                    function getFinalScroll(isX, rawScroll) {
5879
                        var isString = type(rawScroll) == TYPES.s;
5880
                        var operator;
5881
                        var amount;
5882
                        var scrollInfo = isX ? _scrollHorizontalInfo : _scrollVerticalInfo;
5883
                        var currScroll = scrollInfo._currentScroll;
5884
                        var maxScroll = scrollInfo._maxScroll;
5885
                        var mult = ' * ';
5886
                        var finalValue;
5887
                        var isRTLisX = _isRTL && isX;
5888
                        var normalizeShortcuts = isRTLisX && _rtlScrollBehavior.n && !normalizeRTL;
5889
                        var strReplace = 'replace';
5890
                        var evalFunc = eval;
5891
                        var possibleOperator;
5892
                        if (isString) {
5893
                            //check operator
5894
                            if (rawScroll[strLength] > 2) {
5895
                                possibleOperator = rawScroll.substr(0, 2);
5896
                                if (inArray(possibleOperator, coordinatesOperators) > -1)
5897
                                    operator = possibleOperator;
5898
                            }
5899

5900
                            //calculate units and shortcuts
5901
                            rawScroll = operator ? rawScroll.substr(2) : rawScroll;
5902
                            rawScroll = rawScroll
5903
                            [strReplace](/min/g, 0) //'min' = 0%
5904
                            [strReplace](/</g, 0)   //'<'   = 0%
5905
                            [strReplace](/max/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent)    //'max' = 100%
5906
                            [strReplace](/>/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent)      //'>'   = 100%
5907
                            [strReplace](/px/g, _strEmpty)
5908
                            [strReplace](/%/g, mult + (maxScroll * (isRTLisX && _rtlScrollBehavior.n ? -1 : 1) / 100.0))
5909
                            [strReplace](/vw/g, mult + _viewportSize.w)
5910
                            [strReplace](/vh/g, mult + _viewportSize.h);
5911
                            amount = parseToZeroOrNumber(isNaN(rawScroll) ? parseToZeroOrNumber(evalFunc(rawScroll), true).toFixed() : rawScroll);
5912
                        }
5913
                        else {
5914
                            amount = rawScroll;
5915
                        }
5916

5917
                        if (amount !== undefined && !isNaN(amount) && type(amount) == TYPES.n) {
5918
                            var normalizeIsRTLisX = normalizeRTL && isRTLisX;
5919
                            var operatorCurrScroll = currScroll * (normalizeIsRTLisX && _rtlScrollBehavior.n ? -1 : 1);
5920
                            var invert = normalizeIsRTLisX && _rtlScrollBehavior.i;
5921
                            var negate = normalizeIsRTLisX && _rtlScrollBehavior.n;
5922
                            operatorCurrScroll = invert ? (maxScroll - operatorCurrScroll) : operatorCurrScroll;
5923
                            switch (operator) {
5924
                                case '+=':
5925
                                    finalValue = operatorCurrScroll + amount;
5926
                                    break;
5927
                                case '-=':
5928
                                    finalValue = operatorCurrScroll - amount;
5929
                                    break;
5930
                                case '*=':
5931
                                    finalValue = operatorCurrScroll * amount;
5932
                                    break;
5933
                                case '/=':
5934
                                    finalValue = operatorCurrScroll / amount;
5935
                                    break;
5936
                                default:
5937
                                    finalValue = amount;
5938
                                    break;
5939
                            }
5940
                            finalValue = invert ? maxScroll - finalValue : finalValue;
5941
                            finalValue *= negate ? -1 : 1;
5942
                            finalValue = isRTLisX && _rtlScrollBehavior.n ? MATH.min(0, MATH.max(maxScroll, finalValue)) : MATH.max(0, MATH.min(maxScroll, finalValue));
5943
                        }
5944
                        return finalValue === currScroll ? undefined : finalValue;
5945
                    }
5946
                    function getPerAxisValue(value, valueInternalType, defaultValue, allowedValues) {
5947
                        var resultDefault = [defaultValue, defaultValue];
5948
                        var valueType = type(value);
5949
                        var valueArrLength;
5950
                        var valueArrItem;
5951

5952
                        //value can be [ string, or array of two strings ]
5953
                        if (valueType == valueInternalType) {
5954
                            value = [value, value];
5955
                        }
5956
                        else if (valueType == TYPES.a) {
5957
                            valueArrLength = value[strLength];
5958
                            if (valueArrLength > 2 || valueArrLength < 1)
5959
                                value = resultDefault;
5960
                            else {
5961
                                if (valueArrLength === 1)
5962
                                    value[1] = defaultValue;
5963
                                for (i = 0; i < valueArrLength; i++) {
5964
                                    valueArrItem = value[i];
5965
                                    if (type(valueArrItem) != valueInternalType || !checkSettingsStringValue(valueArrItem, allowedValues)) {
5966
                                        value = resultDefault;
5967
                                        break;
5968
                                    }
5969
                                }
5970
                            }
5971
                        }
5972
                        else if (valueType == TYPES.o)
5973
                            value = [value[_strX] || defaultValue, value[_strY] || defaultValue];
5974
                        else
5975
                            value = resultDefault;
5976
                        return { x: value[0], y: value[1] };
5977
                    }
5978
                    function generateMargin(marginTopRightBottomLeftArray) {
5979
                        var result = [];
5980
                        var currValue;
5981
                        var currValueType;
5982
                        var valueDirections = [_strTop, _strRight, _strBottom, _strLeft];
5983
                        for (i = 0; i < marginTopRightBottomLeftArray[strLength]; i++) {
5984
                            if (i === valueDirections[strLength])
5985
                                break;
5986
                            currValue = marginTopRightBottomLeftArray[i];
5987
                            currValueType = type(currValue);
5988
                            if (currValueType == TYPES.b)
5989
                                result.push(currValue ? parseToZeroOrNumber(finalElement.css(_strMarginMinus + valueDirections[i])) : 0);
5990
                            else
5991
                                result.push(currValueType == TYPES.n ? currValue : 0);
5992
                        }
5993
                        return result;
5994
                    }
5995

5996
                    if (possibleElementIsJQuery || possibleElementIsHTMLElement) {
5997
                        //get settings
5998
                        var margin = coordinatesIsElementObj ? coordinates.margin : 0;
5999
                        var axis = coordinatesIsElementObj ? coordinates.axis : 0;
6000
                        var scroll = coordinatesIsElementObj ? coordinates.scroll : 0;
6001
                        var block = coordinatesIsElementObj ? coordinates.block : 0;
6002
                        var marginDefault = [0, 0, 0, 0];
6003
                        var marginType = type(margin);
6004
                        var marginLength;
6005
                        finalElement = possibleElementIsJQuery ? possibleElement : FRAMEWORK(possibleElement);
6006

6007
                        if (finalElement[strLength] > 0) {
6008
                            //margin can be [ boolean, number, array of 2, array of 4, object ]
6009
                            if (marginType == TYPES.n || marginType == TYPES.b)
6010
                                margin = generateMargin([margin, margin, margin, margin]);
6011
                            else if (marginType == TYPES.a) {
6012
                                marginLength = margin[strLength];
6013
                                if (marginLength === 2)
6014
                                    margin = generateMargin([margin[0], margin[1], margin[0], margin[1]]);
6015
                                else if (marginLength >= 4)
6016
                                    margin = generateMargin(margin);
6017
                                else
6018
                                    margin = marginDefault;
6019
                            }
6020
                            else if (marginType == TYPES.o)
6021
                                margin = generateMargin([margin[_strTop], margin[_strRight], margin[_strBottom], margin[_strLeft]]);
6022
                            else
6023
                                margin = marginDefault;
6024

6025
                            //block = type(block) === TYPES.b ? block ? [ strNearest, strBegin ] : [ strNearest, strEnd ] : block;
6026
                            settingsAxis = checkSettingsStringValue(axis, elementObjSettingsAxisValues) ? axis : 'xy';
6027
                            settingsScroll = getPerAxisValue(scroll, TYPES.s, strAlways, elementObjSettingsScrollValues);
6028
                            settingsBlock = getPerAxisValue(block, TYPES.s, strBegin, elementObjSettingsBlockValues);
6029
                            settingsMargin = margin;
6030

6031
                            var viewportScroll = {
6032
                                l: _scrollHorizontalInfo._currentScroll,
6033
                                t: _scrollVerticalInfo._currentScroll
6034
                            };
6035
                            // use padding element instead of viewport element because padding element has never padding, margin or position applied.
6036
                            var viewportOffset = _paddingElement.offset();
6037

6038
                            //get coordinates
6039
                            var elementOffset = finalElement.offset();
6040
                            var doNotScroll = {
6041
                                x: settingsScroll.x == strNever || settingsAxis == _strY,
6042
                                y: settingsScroll.y == strNever || settingsAxis == _strX
6043
                            };
6044
                            elementOffset[_strTop] -= settingsMargin[0];
6045
                            elementOffset[_strLeft] -= settingsMargin[3];
6046
                            var elementScrollCoordinates = {
6047
                                x: MATH.round(elementOffset[_strLeft] - viewportOffset[_strLeft] + viewportScroll.l),
6048
                                y: MATH.round(elementOffset[_strTop] - viewportOffset[_strTop] + viewportScroll.t)
6049
                            };
6050
                            if (_isRTL) {
6051
                                if (!_rtlScrollBehavior.n && !_rtlScrollBehavior.i)
6052
                                    elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + viewportScroll.l);
6053
                                if (_rtlScrollBehavior.n && normalizeRTL)
6054
                                    elementScrollCoordinates.x *= -1;
6055
                                if (_rtlScrollBehavior.i && normalizeRTL)
6056
                                    elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + (_scrollHorizontalInfo._maxScroll - viewportScroll.l));
6057
                            }
6058

6059
                            //measuring is required
6060
                            if (settingsBlock.x != strBegin || settingsBlock.y != strBegin || settingsScroll.x == strIfNeeded || settingsScroll.y == strIfNeeded || _isRTL) {
6061
                                var measuringElm = finalElement[0];
6062
                                var rawElementSize = _supportTransform ? measuringElm[LEXICON.bCR]() : {
6063
                                    width: measuringElm[LEXICON.oW],
6064
                                    height: measuringElm[LEXICON.oH]
6065
                                };
6066
                                var elementSize = {
6067
                                    w: rawElementSize[_strWidth] + settingsMargin[3] + settingsMargin[1],
6068
                                    h: rawElementSize[_strHeight] + settingsMargin[0] + settingsMargin[2]
6069
                                };
6070
                                var finalizeBlock = function (isX) {
6071
                                    var vars = getScrollbarVars(isX);
6072
                                    var wh = vars._w_h;
6073
                                    var lt = vars._left_top;
6074
                                    var xy = vars._x_y;
6075
                                    var blockIsEnd = settingsBlock[xy] == (isX ? _isRTL ? strBegin : strEnd : strEnd);
6076
                                    var blockIsCenter = settingsBlock[xy] == strCenter;
6077
                                    var blockIsNearest = settingsBlock[xy] == strNearest;
6078
                                    var scrollNever = settingsScroll[xy] == strNever;
6079
                                    var scrollIfNeeded = settingsScroll[xy] == strIfNeeded;
6080
                                    var vpSize = _viewportSize[wh];
6081
                                    var vpOffset = viewportOffset[lt];
6082
                                    var elSize = elementSize[wh];
6083
                                    var elOffset = elementOffset[lt];
6084
                                    var divide = blockIsCenter ? 2 : 1;
6085
                                    var elementCenterOffset = elOffset + (elSize / 2);
6086
                                    var viewportCenterOffset = vpOffset + (vpSize / 2);
6087
                                    var isInView =
6088
                                        elSize <= vpSize
6089
                                        && elOffset >= vpOffset
6090
                                        && elOffset + elSize <= vpOffset + vpSize;
6091

6092
                                    if (scrollNever)
6093
                                        doNotScroll[xy] = true;
6094
                                    else if (!doNotScroll[xy]) {
6095
                                        if (blockIsNearest || scrollIfNeeded) {
6096
                                            doNotScroll[xy] = scrollIfNeeded ? isInView : false;
6097
                                            blockIsEnd = elSize < vpSize ? elementCenterOffset > viewportCenterOffset : elementCenterOffset < viewportCenterOffset;
6098
                                        }
6099
                                        elementScrollCoordinates[xy] -= blockIsEnd || blockIsCenter ? ((vpSize / divide) - (elSize / divide)) * (isX && _isRTL && normalizeRTL ? -1 : 1) : 0;
6100
                                    }
6101
                                };
6102
                                finalizeBlock(true);
6103
                                finalizeBlock(false);
6104
                            }
6105

6106
                            if (doNotScroll.y)
6107
                                delete elementScrollCoordinates.y;
6108
                            if (doNotScroll.x)
6109
                                delete elementScrollCoordinates.x;
6110

6111
                            coordinates = elementScrollCoordinates;
6112
                        }
6113
                    }
6114

6115
                    finalScroll[_strScrollLeft] = getFinalScroll(true, getRawScroll(true, coordinates));
6116
                    finalScroll[_strScrollTop] = getFinalScroll(false, getRawScroll(false, coordinates));
6117
                    doScrollLeft = finalScroll[_strScrollLeft] !== undefined;
6118
                    doScrollTop = finalScroll[_strScrollTop] !== undefined;
6119

6120
                    if ((doScrollLeft || doScrollTop) && (duration > 0 || durationIsObject)) {
6121
                        if (durationIsObject) {
6122
                            duration.complete = proxyCompleteCallback;
6123
                            _viewportElement.animate(finalScroll, duration);
6124
                        }
6125
                        else {
6126
                            animationOptions = {
6127
                                duration: duration,
6128
                                complete: proxyCompleteCallback
6129
                            };
6130
                            if (COMPATIBILITY.isA(easing) || FRAMEWORK.isPlainObject(easing)) {
6131
                                specialEasing[_strScrollLeft] = easing[0] || easing.x;
6132
                                specialEasing[_strScrollTop] = easing[1] || easing.y;
6133
                                animationOptions.specialEasing = specialEasing;
6134
                            }
6135
                            else {
6136
                                animationOptions.easing = easing;
6137
                            }
6138
                            _viewportElement.animate(finalScroll, animationOptions);
6139
                        }
6140
                    }
6141
                    else {
6142
                        if (doScrollLeft)
6143
                            _viewportElement[_strScrollLeft](finalScroll[_strScrollLeft]);
6144
                        if (doScrollTop)
6145
                            _viewportElement[_strScrollTop](finalScroll[_strScrollTop]);
6146
                        updateScrollbarInfos();
6147
                    }
6148
                };
6149

6150
                /**
6151
                 * Stops all scroll animations.
6152
                 * @returns {*} The current OverlayScrollbars instance (for chaining).
6153
                 */
6154
                _base.scrollStop = function (param1, param2, param3) {
6155
                    _viewportElement.stop(param1, param2, param3);
6156
                    return _base;
6157
                };
6158

6159
                /**
6160
                 * Returns all relevant elements.
6161
                 * @param elementName The name of the element which shall be returned.
6162
                 * @returns {{target: *, host: *, padding: *, viewport: *, content: *, scrollbarHorizontal: {scrollbar: *, track: *, handle: *}, scrollbarVertical: {scrollbar: *, track: *, handle: *}, scrollbarCorner: *} | *}
6163
                 */
6164
                _base.getElements = function (elementName) {
6165
                    var obj = {
6166
                        target: _targetElementNative,
6167
                        host: _hostElementNative,
6168
                        padding: _paddingElementNative,
6169
                        viewport: _viewportElementNative,
6170
                        content: _contentElementNative,
6171
                        scrollbarHorizontal: {
6172
                            scrollbar: _scrollbarHorizontalElement[0],
6173
                            track: _scrollbarHorizontalTrackElement[0],
6174
                            handle: _scrollbarHorizontalHandleElement[0]
6175
                        },
6176
                        scrollbarVertical: {
6177
                            scrollbar: _scrollbarVerticalElement[0],
6178
                            track: _scrollbarVerticalTrackElement[0],
6179
                            handle: _scrollbarVerticalHandleElement[0]
6180
                        },
6181
                        scrollbarCorner: _scrollbarCornerElement[0]
6182
                    };
6183
                    return type(elementName) == TYPES.s ? getObjectPropVal(obj, elementName) : obj;
6184
                };
6185

6186
                /**
6187
                 * Returns a object which describes the current state of this instance.
6188
                 * @param stateProperty A specific property from the state object which shall be returned.
6189
                 * @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *}
6190
                 */
6191
                _base.getState = function (stateProperty) {
6192
                    function prepare(obj) {
6193
                        if (!FRAMEWORK.isPlainObject(obj))
6194
                            return obj;
6195
                        var extended = extendDeep({}, obj);
6196
                        var changePropertyName = function (from, to) {
6197
                            if (extended[LEXICON.hOP](from)) {
6198
                                extended[to] = extended[from];
6199
                                delete extended[from];
6200
                            }
6201
                        };
6202
                        changePropertyName('w', _strWidth); //change w to width
6203
                        changePropertyName('h', _strHeight); //change h to height
6204
                        delete extended.c; //delete c (the 'changed' prop)
6205
                        return extended;
6206
                    };
6207
                    var obj = {
6208
                        destroyed: !!prepare(_destroyed),
6209
                        sleeping: !!prepare(_sleeping),
6210
                        autoUpdate: prepare(!_mutationObserversConnected),
6211
                        widthAuto: prepare(_widthAutoCache),
6212
                        heightAuto: prepare(_heightAutoCache),
6213
                        padding: prepare(_cssPaddingCache),
6214
                        overflowAmount: prepare(_overflowAmountCache),
6215
                        hideOverflow: prepare(_hideOverflowCache),
6216
                        hasOverflow: prepare(_hasOverflowCache),
6217
                        contentScrollSize: prepare(_contentScrollSizeCache),
6218
                        viewportSize: prepare(_viewportSize),
6219
                        hostSize: prepare(_hostSizeCache),
6220
                        documentMixed: prepare(_documentMixed)
6221
                    };
6222
                    return type(stateProperty) == TYPES.s ? getObjectPropVal(obj, stateProperty) : obj;
6223
                };
6224

6225
                /**
6226
                 * Gets all or specific extension instance.
6227
                 * @param extName The name of the extension from which the instance shall be got.
6228
                 * @returns {{}} The instance of the extension with the given name or undefined if the instance couldn't be found.
6229
                 */
6230
                _base.ext = function (extName) {
6231
                    var result;
6232
                    var privateMethods = _extensionsPrivateMethods.split(' ');
6233
                    var i = 0;
6234
                    if (type(extName) == TYPES.s) {
6235
                        if (_extensions[LEXICON.hOP](extName)) {
6236
                            result = extendDeep({}, _extensions[extName]);
6237
                            for (; i < privateMethods.length; i++)
6238
                                delete result[privateMethods[i]];
6239
                        }
6240
                    }
6241
                    else {
6242
                        result = {};
6243
                        for (i in _extensions)
6244
                            result[i] = extendDeep({}, _base.ext(i));
6245
                    }
6246
                    return result;
6247
                };
6248

6249
                /**
6250
                 * Adds a extension to this instance.
6251
                 * @param extName The name of the extension which shall be added.
6252
                 * @param extensionOptions The extension options which shall be used.
6253
                 * @returns {{}} The instance of the added extension or undefined if the extension couldn't be added properly.
6254
                 */
6255
                _base.addExt = function (extName, extensionOptions) {
6256
                    var registeredExtensionObj = _plugin.extension(extName);
6257
                    var instance;
6258
                    var instanceAdded;
6259
                    var instanceContract;
6260
                    var contractResult;
6261
                    var contractFulfilled = true;
6262
                    if (registeredExtensionObj) {
6263
                        if (!_extensions[LEXICON.hOP](extName)) {
6264
                            instance = registeredExtensionObj.extensionFactory.call(_base,
6265
                                extendDeep({}, registeredExtensionObj.defaultOptions),
6266
                                FRAMEWORK,
6267
                                COMPATIBILITY);
6268

6269
                            if (instance) {
6270
                                instanceContract = instance.contract;
6271
                                if (type(instanceContract) == TYPES.f) {
6272
                                    contractResult = instanceContract(window);
6273
                                    contractFulfilled = type(contractResult) == TYPES.b ? contractResult : contractFulfilled;
6274
                                }
6275
                                if (contractFulfilled) {
6276
                                    _extensions[extName] = instance;
6277
                                    instanceAdded = instance.added;
6278
                                    if (type(instanceAdded) == TYPES.f)
6279
                                        instanceAdded(extensionOptions);
6280

6281
                                    return _base.ext(extName);
6282
                                }
6283
                            }
6284
                        }
6285
                        else
6286
                            return _base.ext(extName);
6287
                    }
6288
                    else
6289
                        console.warn("A extension with the name \"" + extName + "\" isn't registered.");
6290
                };
6291

6292
                /**
6293
                 * Removes a extension from this instance.
6294
                 * @param extName The name of the extension which shall be removed.
6295
                 * @returns {boolean} True if the extension was removed, false otherwise e.g. if the extension wasn't added before.
6296
                 */
6297
                _base.removeExt = function (extName) {
6298
                    var instance = _extensions[extName];
6299
                    var instanceRemoved;
6300
                    if (instance) {
6301
                        delete _extensions[extName];
6302

6303
                        instanceRemoved = instance.removed;
6304
                        if (type(instanceRemoved) == TYPES.f)
6305
                            instanceRemoved();
6306

6307
                        return true;
6308
                    }
6309
                    return false;
6310
                };
6311

6312
                /**
6313
                 * Constructs the plugin.
6314
                 * @param targetElement The element to which the plugin shall be applied.
6315
                 * @param options The initial options of the plugin.
6316
                 * @param extensions The extension(s) which shall be added right after the initialization.
6317
                 * @returns {boolean} True if the plugin was successfully initialized, false otherwise.
6318
                 */
6319
                function construct(targetElement, options, extensions) {
6320
                    _defaultOptions = globals.defaultOptions;
6321
                    _nativeScrollbarStyling = globals.nativeScrollbarStyling;
6322
                    _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
6323
                    _nativeScrollbarIsOverlaid = extendDeep({}, globals.nativeScrollbarIsOverlaid);
6324
                    _overlayScrollbarDummySize = extendDeep({}, globals.overlayScrollbarDummySize);
6325
                    _rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior);
6326

6327
                    //parse & set options but don't update
6328
                    setOptions(extendDeep({}, _defaultOptions, options));
6329

6330
                    _cssCalc = globals.cssCalc;
6331
                    _msieVersion = globals.msie;
6332
                    _autoUpdateRecommended = globals.autoUpdateRecommended;
6333
                    _supportTransition = globals.supportTransition;
6334
                    _supportTransform = globals.supportTransform;
6335
                    _supportPassiveEvents = globals.supportPassiveEvents;
6336
                    _supportResizeObserver = globals.supportResizeObserver;
6337
                    _supportMutationObserver = globals.supportMutationObserver;
6338
                    _restrictedMeasuring = globals.restrictedMeasuring;
6339
                    _documentElement = FRAMEWORK(targetElement.ownerDocument);
6340
                    _documentElementNative = _documentElement[0];
6341
                    _windowElement = FRAMEWORK(_documentElementNative.defaultView || _documentElementNative.parentWindow);
6342
                    _windowElementNative = _windowElement[0];
6343
                    _htmlElement = findFirst(_documentElement, 'html');
6344
                    _bodyElement = findFirst(_htmlElement, 'body');
6345
                    _targetElement = FRAMEWORK(targetElement);
6346
                    _targetElementNative = _targetElement[0];
6347
                    _isTextarea = _targetElement.is('textarea');
6348
                    _isBody = _targetElement.is('body');
6349
                    _documentMixed = _documentElementNative !== document;
6350

6351
                    /* On a div Element The if checks only whether:
6352
                     * - the targetElement has the class "os-host"
6353
                     * - the targetElement has a a child with the class "os-padding"
6354
                     * 
6355
                     * If that's the case, its assumed the DOM has already the following structure:
6356
                     * (The ".os-host" element is the targetElement)
6357
                     *
6358
                     *  <div class="os-host">
6359
                     *      <div class="os-resize-observer-host"></div>
6360
                     *      <div class="os-padding">
6361
                     *          <div class="os-viewport">
6362
                     *              <div class="os-content"></div>
6363
                     *          </div>
6364
                     *      </div>
6365
                     *      <div class="os-scrollbar os-scrollbar-horizontal ">
6366
                     *          <div class="os-scrollbar-track">
6367
                     *              <div class="os-scrollbar-handle"></div>
6368
                     *          </div>
6369
                     *      </div>
6370
                     *      <div class="os-scrollbar os-scrollbar-vertical">
6371
                     *          <div class="os-scrollbar-track">
6372
                     *              <div class="os-scrollbar-handle"></div>
6373
                     *          </div>
6374
                     *      </div>
6375
                     *      <div class="os-scrollbar-corner"></div>
6376
                     *  </div>
6377
                     *
6378
                     * =====================================================================================
6379
                     * 
6380
                     * On a Textarea Element The if checks only whether:
6381
                     * - the targetElement has the class "os-textarea" 
6382
                     * - the targetElement is inside a element with the class "os-content" 
6383
                     * 
6384
                     * If that's the case, its assumed the DOM has already the following structure:
6385
                     * (The ".os-textarea" (textarea) element is the targetElement)
6386
                     *
6387
                     *  <div class="os-host-textarea">
6388
                     *      <div class="os-resize-observer-host"></div>
6389
                     *      <div class="os-padding os-text-inherit">
6390
                     *          <div class="os-viewport os-text-inherit">
6391
                     *              <div class="os-content os-text-inherit">
6392
                     *                  <div class="os-textarea-cover"></div>
6393
                     *                  <textarea class="os-textarea os-text-inherit"></textarea>
6394
                     *              </div>
6395
                     *          </div>
6396
                     *      </div>
6397
                     *      <div class="os-scrollbar os-scrollbar-horizontal ">
6398
                     *          <div class="os-scrollbar-track">
6399
                     *              <div class="os-scrollbar-handle"></div>
6400
                     *          </div>
6401
                     *      </div>
6402
                     *      <div class="os-scrollbar os-scrollbar-vertical">
6403
                     *          <div class="os-scrollbar-track">
6404
                     *              <div class="os-scrollbar-handle"></div>
6405
                     *          </div>
6406
                     *      </div>
6407
                     *      <div class="os-scrollbar-corner"></div>
6408
                     *  </div>
6409
                     */
6410
                    _domExists = _isTextarea
6411
                        ? _targetElement.hasClass(_classNameTextareaElement) && _targetElement.parent().hasClass(_classNameContentElement)
6412
                        : _targetElement.hasClass(_classNameHostElement) && _targetElement.children(_strDot + _classNamePaddingElement)[LEXICON.l];
6413

6414
                    var initBodyScroll;
6415
                    var bodyMouseTouchDownListener;
6416

6417
                    //check if the plugin hasn't to be initialized
6418
                    if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) {
6419
                        dispatchCallback('onInitializationWithdrawn');
6420
                        if (_domExists) {
6421
                            setupStructureDOM(true);
6422
                            setupScrollbarsDOM(true);
6423
                            setupScrollbarCornerDOM(true);
6424
                        }
6425

6426
                        _destroyed = true;
6427
                        _sleeping = true;
6428

6429
                        return _base;
6430
                    }
6431

6432
                    if (_isBody) {
6433
                        initBodyScroll = {};
6434
                        initBodyScroll.l = MATH.max(_targetElement[_strScrollLeft](), _htmlElement[_strScrollLeft](), _windowElement[_strScrollLeft]());
6435
                        initBodyScroll.t = MATH.max(_targetElement[_strScrollTop](), _htmlElement[_strScrollTop](), _windowElement[_strScrollTop]());
6436

6437
                        bodyMouseTouchDownListener = function () {
6438
                            _viewportElement.removeAttr(LEXICON.ti);
6439
                            setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, true, true);
6440
                        }
6441
                    }
6442

6443
                    //build OverlayScrollbars DOM
6444
                    setupStructureDOM();
6445
                    setupScrollbarsDOM();
6446
                    setupScrollbarCornerDOM();
6447

6448
                    //create OverlayScrollbars events
6449
                    setupStructureEvents();
6450
                    setupScrollbarEvents(true);
6451
                    setupScrollbarEvents(false);
6452
                    setupScrollbarCornerEvents();
6453

6454
                    //create mutation observers
6455
                    createMutationObservers();
6456

6457
                    //build resize observer for the host element
6458
                    setupResizeObserver(_sizeObserverElement, hostOnResized);
6459

6460
                    if (_isBody) {
6461
                        //apply the body scroll to handle it right in the update method
6462
                        _viewportElement[_strScrollLeft](initBodyScroll.l)[_strScrollTop](initBodyScroll.t);
6463

6464
                        //set the focus on the viewport element so you dont have to click on the page to use keyboard keys (up / down / space) for scrolling
6465
                        if (document.activeElement == targetElement && _viewportElementNative.focus) {
6466
                            //set a tabindex to make the viewportElement focusable
6467
                            _viewportElement.attr(LEXICON.ti, '-1');
6468
                            _viewportElementNative.focus();
6469

6470
                            /* the tabindex has to be removed due to;
6471
                             * If you set the tabindex attribute on an <div>, then its child content cannot be scrolled with the arrow keys unless you set tabindex on the content, too
6472
                             * https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
6473
                             */
6474
                            setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, false, true);
6475
                        }
6476
                    }
6477

6478
                    //update for the first time & initialize cache
6479
                    _base.update(_strAuto);
6480

6481
                    //the plugin is initialized now!
6482
                    _initialized = true;
6483
                    dispatchCallback('onInitialized');
6484

6485
                    //call all callbacks which would fire before the initialized was complete
6486
                    each(_callbacksInitQeueue, function (index, value) { dispatchCallback(value.n, value.a); });
6487
                    _callbacksInitQeueue = [];
6488

6489
                    //add extensions
6490
                    if (type(extensions) == TYPES.s)
6491
                        extensions = [extensions];
6492
                    if (COMPATIBILITY.isA(extensions))
6493
                        each(extensions, function (index, value) { _base.addExt(value); });
6494
                    else if (FRAMEWORK.isPlainObject(extensions))
6495
                        each(extensions, function (key, value) { _base.addExt(key, value); });
6496

6497
                    //add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions)
6498
                    setTimeout(function () {
6499
                        if (_supportTransition && !_destroyed)
6500
                            addClass(_hostElement, _classNameHostTransition);
6501
                    }, 333);
6502

6503
                    return _base;
6504
                }
6505

6506
                if (_plugin.valid(construct(pluginTargetElement, options, extensions))) {
6507
                    INSTANCES(pluginTargetElement, _base);
6508
                }
6509

6510
                return _base;
6511
            }
6512

6513
            /**
6514
             * Initializes a new OverlayScrollbarsInstance object or changes options if already initialized or returns the current instance.
6515
             * @param pluginTargetElements The elements to which the Plugin shall be initialized.
6516
             * @param options The custom options with which the plugin shall be initialized.
6517
             * @param extensions The extension(s) which shall be added right after initialization.
6518
             * @returns {*}
6519
             */
6520
            _plugin = window[PLUGINNAME] = function (pluginTargetElements, options, extensions) {
6521
                if (arguments[LEXICON.l] === 0)
6522
                    return this;
6523

6524
                var arr = [];
6525
                var optsIsPlainObj = FRAMEWORK.isPlainObject(options);
6526
                var inst;
6527
                var result;
6528

6529
                //pluginTargetElements is null or undefined
6530
                if (!pluginTargetElements)
6531
                    return optsIsPlainObj || !options ? result : arr;
6532

6533
                /*
6534
                   pluginTargetElements will be converted to:
6535
                   1. A jQueryElement Array
6536
                   2. A HTMLElement Array
6537
                   3. A Array with a single HTML Element
6538
                   so pluginTargetElements is always a array.
6539
                */
6540
                pluginTargetElements = pluginTargetElements[LEXICON.l] != undefined ? pluginTargetElements : [pluginTargetElements[0] || pluginTargetElements];
6541
                initOverlayScrollbarsStatics();
6542

6543
                if (pluginTargetElements[LEXICON.l] > 0) {
6544
                    if (optsIsPlainObj) {
6545
                        FRAMEWORK.each(pluginTargetElements, function (i, v) {
6546
                            inst = v;
6547
                            if (inst !== undefined)
6548
                                arr.push(OverlayScrollbarsInstance(inst, options, extensions, _pluginsGlobals, _pluginsAutoUpdateLoop));
6549
                        });
6550
                    }
6551
                    else {
6552
                        FRAMEWORK.each(pluginTargetElements, function (i, v) {
6553
                            inst = INSTANCES(v);
6554
                            if ((options === '!' && _plugin.valid(inst)) || (COMPATIBILITY.type(options) == TYPES.f && options(v, inst)))
6555
                                arr.push(inst);
6556
                            else if (options === undefined)
6557
                                arr.push(inst);
6558
                        });
6559
                    }
6560
                    result = arr[LEXICON.l] === 1 ? arr[0] : arr;
6561
                }
6562
                return result;
6563
            };
6564

6565
            /**
6566
             * Returns a object which contains global information about the plugin and each instance of it.
6567
             * The returned object is just a copy, that means that changes to the returned object won't have any effect to the original object.
6568
             */
6569
            _plugin.globals = function () {
6570
                initOverlayScrollbarsStatics();
6571
                var globals = FRAMEWORK.extend(true, {}, _pluginsGlobals);
6572
                delete globals['msie'];
6573
                return globals;
6574
            };
6575

6576
            /**
6577
             * Gets or Sets the default options for each new plugin initialization.
6578
             * @param newDefaultOptions The object with which the default options shall be extended.
6579
             */
6580
            _plugin.defaultOptions = function (newDefaultOptions) {
6581
                initOverlayScrollbarsStatics();
6582
                var currDefaultOptions = _pluginsGlobals.defaultOptions;
6583
                if (newDefaultOptions === undefined)
6584
                    return FRAMEWORK.extend(true, {}, currDefaultOptions);
6585

6586
                //set the new default options
6587
                _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, {}, currDefaultOptions, _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true, currDefaultOptions)._default);
6588
            };
6589

6590
            /**
6591
             * Checks whether the passed instance is a non-destroyed OverlayScrollbars instance.
6592
             * @param osInstance The potential OverlayScrollbars instance which shall be checked.
6593
             * @returns {boolean} True if the passed value is a non-destroyed OverlayScrollbars instance, false otherwise.
6594
             */
6595
            _plugin.valid = function (osInstance) {
6596
                return osInstance instanceof _plugin && !osInstance.getState().destroyed;
6597
            };
6598

6599
            /**
6600
             * Registers, Unregisters or returns a extension.
6601
             * Register: Pass the name and the extension. (defaultOptions is optional)
6602
             * Unregister: Pass the name and anything except a function as extension parameter.
6603
             * Get extension: Pass the name of the extension which shall be got.
6604
             * Get all extensions: Pass no arguments.
6605
             * @param extensionName The name of the extension which shall be registered, unregistered or returned.
6606
             * @param extension A function which generates the instance of the extension or anything other to remove a already registered extension.
6607
             * @param defaultOptions The default options which shall be used for the registered extension.
6608
             */
6609
            _plugin.extension = function (extensionName, extension, defaultOptions) {
6610
                var extNameTypeString = COMPATIBILITY.type(extensionName) == TYPES.s;
6611
                var argLen = arguments[LEXICON.l];
6612
                var i = 0;
6613
                if (argLen < 1 || !extNameTypeString) {
6614
                    //return a copy of all extension objects
6615
                    return FRAMEWORK.extend(true, { length: _pluginsExtensions[LEXICON.l] }, _pluginsExtensions);
6616
                }
6617
                else if (extNameTypeString) {
6618
                    if (COMPATIBILITY.type(extension) == TYPES.f) {
6619
                        //register extension
6620
                        _pluginsExtensions.push({
6621
                            name: extensionName,
6622
                            extensionFactory: extension,
6623
                            defaultOptions: defaultOptions
6624
                        });
6625
                    }
6626
                    else {
6627
                        for (; i < _pluginsExtensions[LEXICON.l]; i++) {
6628
                            if (_pluginsExtensions[i].name === extensionName) {
6629
                                if (argLen > 1)
6630
                                    _pluginsExtensions.splice(i, 1); //remove extension
6631
                                else
6632
                                    return FRAMEWORK.extend(true, {}, _pluginsExtensions[i]); //return extension with the given name
6633
                            }
6634
                        }
6635
                    }
6636
                }
6637
            };
6638

6639
            return _plugin;
6640
        })();
6641

6642
        if (JQUERY && JQUERY.fn) {
6643
            /**
6644
             * The jQuery initialization interface.
6645
             * @param options The initial options for the construction of the plugin. To initialize the plugin, this option has to be a object! If it isn't a object, the instance(s) are returned and the plugin wont be initialized.
6646
             * @param extensions The extension(s) which shall be added right after initialization.
6647
             * @returns {*} After initialization it returns the jQuery element array, else it returns the instance(s) of the elements which are selected.
6648
             */
6649
            JQUERY.fn.overlayScrollbars = function (options, extensions) {
6650
                var _elements = this;
6651
                if (JQUERY.isPlainObject(options)) {
6652
                    JQUERY.each(_elements, function () { PLUGIN(this, options, extensions); });
6653
                    return _elements;
6654
                }
6655
                else
6656
                    return PLUGIN(_elements, options);
6657
            };
6658
        }
6659
        return PLUGIN;
6660
    }
6661
));

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

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

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

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