LaravelTest
5578 строк · 310.6 Кб
1/*!
2* OverlayScrollbars
3* https://github.com/KingSora/OverlayScrollbars
4*
5* Version: 1.13.0
6*
7* Copyright KingSora | Rene Haas.
8* https://github.com/KingSora
9*
10* Released under the MIT license.
11* Date: 02.08.2020
12*/
13
14(function (global, factory) {15if (typeof define === 'function' && define.amd)16define(['jquery'], function (framework) { return factory(global, global.document, undefined, framework); });17else if (typeof module === 'object' && typeof module.exports === 'object')18module.exports = factory(global, global.document, undefined, require('jquery'));19else20factory(global, global.document, undefined, global.jQuery);21}(typeof window !== 'undefined' ? window : this,22function (window, document, undefined, framework) {23'use strict';24var PLUGINNAME = 'OverlayScrollbars';25var TYPES = {26o: 'object',27f: 'function',28a: 'array',29s: 'string',30b: 'boolean',31n: 'number',32u: 'undefined',33z: 'null'34//d : 'date',35//e : 'error',36//r : 'regexp',37//y : 'symbol'38};39var LEXICON = {40c: 'class',41s: 'style',42i: 'id',43l: 'length',44p: 'prototype',45ti: 'tabindex',46oH: 'offsetHeight',47cH: 'clientHeight',48sH: 'scrollHeight',49oW: 'offsetWidth',50cW: 'clientWidth',51sW: 'scrollWidth',52hOP: 'hasOwnProperty',53bCR: 'getBoundingClientRect'54};55var VENDORS = (function () {56//https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix57var jsCache = {};58var cssCache = {};59var cssPrefixes = ['-webkit-', '-moz-', '-o-', '-ms-'];60var jsPrefixes = ['WebKit', 'Moz', 'O', 'MS'];61function firstLetterToUpper(str) {62return str.charAt(0).toUpperCase() + str.slice(1);63}64
65return {66_cssPrefixes: cssPrefixes,67_jsPrefixes: jsPrefixes,68_cssProperty: function (name) {69var result = cssCache[name];70
71if (cssCache[LEXICON.hOP](name))72return result;73
74var uppercasedName = firstLetterToUpper(name);75var elmStyle = document.createElement('div')[LEXICON.s];76var resultPossibilities;77var i = 0;78var v;79var currVendorWithoutDashes;80
81for (; i < cssPrefixes.length; i++) {82currVendorWithoutDashes = cssPrefixes[i].replace(/-/g, '');83resultPossibilities = [84name, //transition85cssPrefixes[i] + name, //-webkit-transition86currVendorWithoutDashes + uppercasedName, //webkitTransition87firstLetterToUpper(currVendorWithoutDashes) + uppercasedName //WebkitTransition88];89for (v = 0; v < resultPossibilities[LEXICON.l]; v++) {90if (elmStyle[resultPossibilities[v]] !== undefined) {91result = resultPossibilities[v];92break;93}94}95}96
97cssCache[name] = result;98return result;99},100_cssPropertyValue: function (property, values, suffix) {101var name = property + ' ' + values;102var result = cssCache[name];103
104if (cssCache[LEXICON.hOP](name))105return result;106
107var dummyStyle = document.createElement('div')[LEXICON.s];108var possbleValues = values.split(' ');109var preparedSuffix = suffix || '';110var i = 0;111var v = -1;112var prop;113
114for (; i < possbleValues[LEXICON.l]; i++) {115for (; v < VENDORS._cssPrefixes[LEXICON.l]; v++) {116prop = v < 0 ? possbleValues[i] : VENDORS._cssPrefixes[v] + possbleValues[i];117dummyStyle.cssText = property + ':' + prop + preparedSuffix;118if (dummyStyle[LEXICON.l]) {119result = prop;120break;121}122}123}124
125cssCache[name] = result;126return result;127},128_jsAPI: function (name, isInterface, fallback) {129var i = 0;130var result = jsCache[name];131
132if (!jsCache[LEXICON.hOP](name)) {133result = window[name];134for (; i < jsPrefixes[LEXICON.l]; i++)135result = result || window[(isInterface ? jsPrefixes[i] : jsPrefixes[i].toLowerCase()) + firstLetterToUpper(name)];136jsCache[name] = result;137}138return result || fallback;139}140}141})();142var COMPATIBILITY = (function () {143function windowSize(x) {144return x ? window.innerWidth || document.documentElement[LEXICON.cW] || document.body[LEXICON.cW] : window.innerHeight || document.documentElement[LEXICON.cH] || document.body[LEXICON.cH];145}146function bind(func, thisObj) {147if (typeof func != TYPES.f) {148throw "Can't bind function!";149// closest thing possible to the ECMAScript 5150// internal IsCallable function151//throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');152}153var proto = LEXICON.p;154var aArgs = Array[proto].slice.call(arguments, 2);155var fNOP = function () { };156var fBound = function () { return func.apply(this instanceof fNOP ? this : thisObj, aArgs.concat(Array[proto].slice.call(arguments))); };157
158if (func[proto])159fNOP[proto] = func[proto]; // Function.prototype doesn't have a prototype property160fBound[proto] = new fNOP();161
162return fBound;163}164
165return {166/**167* Gets the current window width.
168* @returns {Number|number} The current window width in pixel.
169*/
170wW: bind(windowSize, 0, true),171
172/**173* Gets the current window height.
174* @returns {Number|number} The current window height in pixel.
175*/
176wH: bind(windowSize, 0),177
178/**179* Gets the MutationObserver Object or undefined if not supported.
180* @returns {MutationObserver|*|undefined} The MutationsObserver Object or undefined.
181*/
182mO: bind(VENDORS._jsAPI, 0, 'MutationObserver', true),183
184/**185* Gets the ResizeObserver Object or undefined if not supported.
186* @returns {MutationObserver|*|undefined} The ResizeObserver Object or undefined.
187*/
188rO: bind(VENDORS._jsAPI, 0, 'ResizeObserver', true),189
190/**191* Gets the RequestAnimationFrame method or it's corresponding polyfill.
192* @returns {*|Function} The RequestAnimationFrame method or it's corresponding polyfill.
193*/
194rAF: bind(VENDORS._jsAPI, 0, 'requestAnimationFrame', false, function (func) { return window.setTimeout(func, 1000 / 60); }),195
196/**197* Gets the CancelAnimationFrame method or it's corresponding polyfill.
198* @returns {*|Function} The CancelAnimationFrame method or it's corresponding polyfill.
199*/
200cAF: bind(VENDORS._jsAPI, 0, 'cancelAnimationFrame', false, function (id) { return window.clearTimeout(id); }),201
202/**203* Gets the current time.
204* @returns {number} The current time.
205*/
206now: function () {207return Date.now && Date.now() || new Date().getTime();208},209
210/**211* Stops the propagation of the given event.
212* @param event The event of which the propagation shall be stoped.
213*/
214stpP: function (event) {215if (event.stopPropagation)216event.stopPropagation();217else218event.cancelBubble = true;219},220
221/**222* Prevents the default action of the given event.
223* @param event The event of which the default action shall be prevented.
224*/
225prvD: function (event) {226if (event.preventDefault && event.cancelable)227event.preventDefault();228else229event.returnValue = false;230},231
232/**233* Gets the pageX and pageY values of the given mouse event.
234* @param event The mouse event of which the pageX and pageX shall be got.
235* @returns {{x: number, y: number}} x = pageX value, y = pageY value.
236*/
237page: function (event) {238event = event.originalEvent || event;239
240var strPage = 'page';241var strClient = 'client';242var strX = 'X';243var strY = 'Y';244var target = event.target || event.srcElement || document;245var eventDoc = target.ownerDocument || document;246var doc = eventDoc.documentElement;247var body = eventDoc.body;248
249//if touch event return return pageX/Y of it250if (event.touches !== undefined) {251var touch = event.touches[0];252return {253x: touch[strPage + strX],254y: touch[strPage + strY]255}256}257
258// Calculate pageX/Y if not native supported259if (!event[strPage + strX] && event[strClient + strX] && event[strClient + strX] != null) {260
261return {262x: event[strClient + strX] +263(doc && doc.scrollLeft || body && body.scrollLeft || 0) -264(doc && doc.clientLeft || body && body.clientLeft || 0),265y: event[strClient + strY] +266(doc && doc.scrollTop || body && body.scrollTop || 0) -267(doc && doc.clientTop || body && body.clientTop || 0)268}269}270return {271x: event[strPage + strX],272y: event[strPage + strY]273};274},275
276/**277* Gets the clicked mouse button of the given mouse event.
278* @param event The mouse event of which the clicked button shal be got.
279* @returns {number} The number of the clicked mouse button. (0 : none | 1 : leftButton | 2 : middleButton | 3 : rightButton)
280*/
281mBtn: function (event) {282var button = event.button;283if (!event.which && button !== undefined)284return (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));285else286return event.which;287},288
289/**290* Checks whether a item is in the given array and returns its index.
291* @param item The item of which the position in the array shall be determined.
292* @param arr The array.
293* @returns {number} The zero based index of the item or -1 if the item isn't in the array.
294*/
295inA: function (item, arr) {296for (var i = 0; i < arr[LEXICON.l]; i++)297//Sometiems in IE a "SCRIPT70" Permission denied error occurs if HTML elements in a iFrame are compared298try {299if (arr[i] === item)300return i;301}302catch (e) { }303return -1;304},305
306/**307* Returns true if the given value is a array.
308* @param arr The potential array.
309* @returns {boolean} True if the given value is a array, false otherwise.
310*/
311isA: function (arr) {312var def = Array.isArray;313return def ? def(arr) : this.type(arr) == TYPES.a;314},315
316/**317* Determine the internal JavaScript [[Class]] of the given object.
318* @param obj The object of which the type shall be determined.
319* @returns {string} The type of the given object.
320*/
321type: function (obj) {322if (obj === undefined)323return obj + '';324if (obj === null)325return obj + '';326return Object[LEXICON.p].toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();327},328
329
330bind: bind331
332/**333* Gets the vendor-prefixed CSS property by the given name.
334* For example the given name is "transform" and you're using a old Firefox browser then the returned value would be "-moz-transform".
335* If the browser doesn't need a vendor-prefix, then the returned string is the given name.
336* If the browser doesn't support the given property name at all (not even with a vendor-prefix) the returned value is null.
337* @param propName The unprefixed CSS property name.
338* @returns {string|null} The vendor-prefixed CSS property or null if the browser doesn't support the given CSS property.
339
340cssProp: function(propName) {
341return VENDORS._cssProperty(propName);
342}
343*/
344}345})();346
347var MATH = Math;348var JQUERY = framework;349var EASING = framework.easing;350var FRAMEWORK = framework;351var INSTANCES = (function () {352var _targets = [];353var _instancePropertyString = '__overlayScrollbars__';354
355/**356* Register, unregister or get a certain (or all) instances.
357* Register: Pass the target and the instance.
358* Unregister: Pass the target and null.
359* Get Instance: Pass the target from which the instance shall be got.
360* Get Targets: Pass no arguments.
361* @param target The target to which the instance shall be registered / from which the instance shall be unregistered / the instance shall be got
362* @param instance The instance.
363* @returns {*|void} Returns the instance from the given target.
364*/
365return function (target, instance) {366var argLen = arguments[LEXICON.l];367if (argLen < 1) {368//return all targets369return _targets;370}371else {372if (instance) {373//register instance374target[_instancePropertyString] = instance;375_targets.push(target);376}377else {378var index = COMPATIBILITY.inA(target, _targets);379if (index > -1) {380if (argLen > 1) {381//unregister instance382delete target[_instancePropertyString];383_targets.splice(index, 1);384}385else {386//get instance from target387return _targets[index][_instancePropertyString];388}389}390}391}392}393})();394var PLUGIN = (function () {395var _plugin;396var _pluginsGlobals;397var _pluginsAutoUpdateLoop;398var _pluginsExtensions = [];399var _pluginsOptions = (function () {400var type = COMPATIBILITY.type;401var possibleTemplateTypes = [402TYPES.b, //boolean403TYPES.n, //number404TYPES.s, //string405TYPES.a, //array406TYPES.o, //object407TYPES.f, //function408TYPES.z //null409];410var restrictedStringsSplit = ' ';411var restrictedStringsPossibilitiesSplit = ':';412var classNameAllowedValues = [TYPES.z, TYPES.s];413var numberAllowedValues = TYPES.n;414var booleanNullAllowedValues = [TYPES.z, TYPES.b];415var booleanTrueTemplate = [true, TYPES.b];416var booleanFalseTemplate = [false, TYPES.b];417var callbackTemplate = [null, [TYPES.z, TYPES.f]];418var updateOnLoadTemplate = [['img'], [TYPES.s, TYPES.a, TYPES.z]];419var inheritedAttrsTemplate = [['style', 'class'], [TYPES.s, TYPES.a, TYPES.z]];420var resizeAllowedValues = 'n:none b:both h:horizontal v:vertical';421var overflowBehaviorAllowedValues = 'v-h:visible-hidden v-s:visible-scroll s:scroll h:hidden';422var scrollbarsVisibilityAllowedValues = 'v:visible h:hidden a:auto';423var scrollbarsAutoHideAllowedValues = 'n:never s:scroll l:leave m:move';424var optionsDefaultsAndTemplate = {425className: ['os-theme-dark', classNameAllowedValues], //null || string426resize: ['none', resizeAllowedValues], //none || both || horizontal || vertical || n || b || h || v427sizeAutoCapable: booleanTrueTemplate, //true || false428clipAlways: booleanTrueTemplate, //true || false429normalizeRTL: booleanTrueTemplate, //true || false430paddingAbsolute: booleanFalseTemplate, //true || false431autoUpdate: [null, booleanNullAllowedValues], //true || false || null432autoUpdateInterval: [33, numberAllowedValues], //number433updateOnLoad: updateOnLoadTemplate, //string || array || null434nativeScrollbarsOverlaid: {435showNativeScrollbars: booleanFalseTemplate, //true || false436initialize: booleanTrueTemplate //true || false437},438overflowBehavior: {439x: ['scroll', overflowBehaviorAllowedValues], //visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s440y: ['scroll', overflowBehaviorAllowedValues] //visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s441},442scrollbars: {443visibility: ['auto', scrollbarsVisibilityAllowedValues], //visible || hidden || auto || v || h || a444autoHide: ['never', scrollbarsAutoHideAllowedValues], //never || scroll || leave || move || n || s || l || m445autoHideDelay: [800, numberAllowedValues], //number446dragScrolling: booleanTrueTemplate, //true || false447clickScrolling: booleanFalseTemplate, //true || false448touchSupport: booleanTrueTemplate, //true || false449snapHandle: booleanFalseTemplate //true || false450},451textarea: {452dynWidth: booleanFalseTemplate, //true || false453dynHeight: booleanFalseTemplate, //true || false454inheritedAttrs: inheritedAttrsTemplate //string || array || null455},456callbacks: {457onInitialized: callbackTemplate, //null || function458onInitializationWithdrawn: callbackTemplate, //null || function459onDestroyed: callbackTemplate, //null || function460onScrollStart: callbackTemplate, //null || function461onScroll: callbackTemplate, //null || function462onScrollStop: callbackTemplate, //null || function463onOverflowChanged: callbackTemplate, //null || function464onOverflowAmountChanged: callbackTemplate, //null || function465onDirectionChanged: callbackTemplate, //null || function466onContentSizeChanged: callbackTemplate, //null || function467onHostSizeChanged: callbackTemplate, //null || function468onUpdated: callbackTemplate //null || function469}470};471var convert = function (template) {472var recursive = function (obj) {473var key;474var val;475var valType;476for (key in obj) {477if (!obj[LEXICON.hOP](key))478continue;479val = obj[key];480valType = type(val);481if (valType == TYPES.a)482obj[key] = val[template ? 1 : 0];483else if (valType == TYPES.o)484obj[key] = recursive(val);485}486return obj;487};488return recursive(FRAMEWORK.extend(true, {}, optionsDefaultsAndTemplate));489};490
491return {492_defaults: convert(),493
494_template: convert(true),495
496/**497* Validates the passed object by the passed template.
498* @param obj The object which shall be validated.
499* @param template The template which defines the allowed values and types.
500* @param writeErrors True if errors shall be logged to the console.
501* @param diffObj If a object is passed then only valid differences to this object will be returned.
502* @returns {{}} A object which contains two objects called "default" and "prepared" which contains only the valid properties of the passed original object and discards not different values compared to the passed diffObj.
503*/
504_validate: function (obj, template, writeErrors, diffObj) {505var validatedOptions = {};506var validatedOptionsPrepared = {};507var objectCopy = FRAMEWORK.extend(true, {}, obj);508var inArray = FRAMEWORK.inArray;509var isEmptyObj = FRAMEWORK.isEmptyObject;510var checkObjectProps = function (data, template, diffData, validatedOptions, validatedOptionsPrepared, prevPropName) {511for (var prop in template) {512if (template[LEXICON.hOP](prop) && data[LEXICON.hOP](prop)) {513var isValid = false;514var isDiff = false;515var templateValue = template[prop];516var templateValueType = type(templateValue);517var templateIsComplex = templateValueType == TYPES.o;518var templateTypes = !COMPATIBILITY.isA(templateValue) ? [templateValue] : templateValue;519var dataDiffValue = diffData[prop];520var dataValue = data[prop];521var dataValueType = type(dataValue);522var propPrefix = prevPropName ? prevPropName + '.' : '';523var error = "The option \"" + propPrefix + prop + "\" wasn't set, because";524var errorPossibleTypes = [];525var errorRestrictedStrings = [];526var restrictedStringValuesSplit;527var restrictedStringValuesPossibilitiesSplit;528var isRestrictedValue;529var mainPossibility;530var currType;531var i;532var v;533var j;534
535dataDiffValue = dataDiffValue === undefined ? {} : dataDiffValue;536
537//if the template has a object as value, it means that the options are complex (verschachtelt)538if (templateIsComplex && dataValueType == TYPES.o) {539validatedOptions[prop] = {};540validatedOptionsPrepared[prop] = {};541checkObjectProps(dataValue, templateValue, dataDiffValue, validatedOptions[prop], validatedOptionsPrepared[prop], propPrefix + prop);542FRAMEWORK.each([data, validatedOptions, validatedOptionsPrepared], function (index, value) {543if (isEmptyObj(value[prop])) {544delete value[prop];545}546});547}548else if (!templateIsComplex) {549for (i = 0; i < templateTypes[LEXICON.l]; i++) {550currType = templateTypes[i];551templateValueType = type(currType);552//if currtype is string and starts with restrictedStringPrefix and end with restrictedStringSuffix553isRestrictedValue = templateValueType == TYPES.s && inArray(currType, possibleTemplateTypes) === -1;554if (isRestrictedValue) {555errorPossibleTypes.push(TYPES.s);556
557//split it into a array which contains all possible values for example: ["y:yes", "n:no", "m:maybe"]558restrictedStringValuesSplit = currType.split(restrictedStringsSplit);559errorRestrictedStrings = errorRestrictedStrings.concat(restrictedStringValuesSplit);560for (v = 0; v < restrictedStringValuesSplit[LEXICON.l]; v++) {561//split the possible values into their possibiliteis for example: ["y", "yes"] -> the first is always the mainPossibility562restrictedStringValuesPossibilitiesSplit = restrictedStringValuesSplit[v].split(restrictedStringsPossibilitiesSplit);563mainPossibility = restrictedStringValuesPossibilitiesSplit[0];564for (j = 0; j < restrictedStringValuesPossibilitiesSplit[LEXICON.l]; j++) {565//if any possibility matches with the dataValue, its valid566if (dataValue === restrictedStringValuesPossibilitiesSplit[j]) {567isValid = true;568break;569}570}571if (isValid)572break;573}574}575else {576errorPossibleTypes.push(currType);577
578if (dataValueType === currType) {579isValid = true;580break;581}582}583}584
585if (isValid) {586isDiff = dataValue !== dataDiffValue;587
588if (isDiff)589validatedOptions[prop] = dataValue;590
591if (isRestrictedValue ? inArray(dataDiffValue, restrictedStringValuesPossibilitiesSplit) < 0 : isDiff)592validatedOptionsPrepared[prop] = isRestrictedValue ? mainPossibility : dataValue;593}594else if (writeErrors) {595console.warn(error + " it doesn't accept the type [ " + dataValueType.toUpperCase() + " ] with the value of \"" + dataValue + "\".\r\n" +596"Accepted types are: [ " + errorPossibleTypes.join(', ').toUpperCase() + " ]." +597(errorRestrictedStrings[length] > 0 ? "\r\nValid strings are: [ " + errorRestrictedStrings.join(', ').split(restrictedStringsPossibilitiesSplit).join(', ') + " ]." : ''));598}599delete data[prop];600}601}602}603};604checkObjectProps(objectCopy, template, diffObj || {}, validatedOptions, validatedOptionsPrepared);605
606//add values which aren't specified in the template to the finished validated object to prevent them from being discarded607/*608if(keepForeignProps) {
609FRAMEWORK.extend(true, validatedOptions, objectCopy);
610FRAMEWORK.extend(true, validatedOptionsPrepared, objectCopy);
611}
612*/
613
614if (!isEmptyObj(objectCopy) && writeErrors)615console.warn('The following options are discarded due to invalidity:\r\n' + window.JSON.stringify(objectCopy, null, 2));616
617return {618_default: validatedOptions,619_prepared: validatedOptionsPrepared620};621}622}623}());624
625/**626* Initializes the object which contains global information about the plugin and each instance of it.
627*/
628function initOverlayScrollbarsStatics() {629if (!_pluginsGlobals)630_pluginsGlobals = new OverlayScrollbarsGlobals(_pluginsOptions._defaults);631if (!_pluginsAutoUpdateLoop)632_pluginsAutoUpdateLoop = new OverlayScrollbarsAutoUpdateLoop(_pluginsGlobals);633}634
635/**636* The global object for the OverlayScrollbars objects. It contains resources which every OverlayScrollbars object needs. This object is initialized only once: if the first OverlayScrollbars object gets initialized.
637* @param defaultOptions
638* @constructor
639*/
640function OverlayScrollbarsGlobals(defaultOptions) {641var _base = this;642var strOverflow = 'overflow';643var strHidden = 'hidden';644var strScroll = 'scroll';645var bodyElement = FRAMEWORK('body');646var scrollbarDummyElement = FRAMEWORK('<div id="os-dummy-scrollbar-size"><div></div></div>');647var scrollbarDummyElement0 = scrollbarDummyElement[0];648var dummyContainerChild = FRAMEWORK(scrollbarDummyElement.children('div').eq(0));649
650bodyElement.append(scrollbarDummyElement);651scrollbarDummyElement.hide().show(); //fix IE8 bug (incorrect measuring)652
653var nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement0);654var nativeScrollbarIsOverlaid = {655x: nativeScrollbarSize.x === 0,656y: nativeScrollbarSize.y === 0657};658var msie = (function () {659var ua = window.navigator.userAgent;660var strIndexOf = 'indexOf';661var strSubString = 'substring';662var msie = ua[strIndexOf]('MSIE ');663var trident = ua[strIndexOf]('Trident/');664var edge = ua[strIndexOf]('Edge/');665var rv = ua[strIndexOf]('rv:');666var result;667var parseIntFunc = parseInt;668
669// IE 10 or older => return version number670if (msie > 0)671result = parseIntFunc(ua[strSubString](msie + 5, ua[strIndexOf]('.', msie)), 10);672
673// IE 11 => return version number674else if (trident > 0)675result = parseIntFunc(ua[strSubString](rv + 3, ua[strIndexOf]('.', rv)), 10);676
677// Edge (IE 12+) => return version number678else if (edge > 0)679result = parseIntFunc(ua[strSubString](edge + 5, ua[strIndexOf]('.', edge)), 10);680
681// other browser682return result;683})();684
685FRAMEWORK.extend(_base, {686defaultOptions: defaultOptions,687msie: msie,688autoUpdateLoop: false,689autoUpdateRecommended: !COMPATIBILITY.mO(),690nativeScrollbarSize: nativeScrollbarSize,691nativeScrollbarIsOverlaid: nativeScrollbarIsOverlaid,692nativeScrollbarStyling: (function () {693var result = false;694scrollbarDummyElement.addClass('os-viewport-native-scrollbars-invisible');695try {696result = (scrollbarDummyElement.css('scrollbar-width') === 'none' && (msie > 9 || !msie)) || window.getComputedStyle(scrollbarDummyElement0, '::-webkit-scrollbar').getPropertyValue('display') === 'none';697} catch (ex) { }698
699//fix opera bug: scrollbar styles will only appear if overflow value is scroll or auto during the activation of the style.700//and set overflow to scroll701//scrollbarDummyElement.css(strOverflow, strHidden).hide().css(strOverflow, strScroll).show();702//return (scrollbarDummyElement0[LEXICON.oH] - scrollbarDummyElement0[LEXICON.cH]) === 0 && (scrollbarDummyElement0[LEXICON.oW] - scrollbarDummyElement0[LEXICON.cW]) === 0;703
704return result;705})(),706overlayScrollbarDummySize: { x: 30, y: 30 },707cssCalc: VENDORS._cssPropertyValue('width', 'calc', '(1px)') || null,708restrictedMeasuring: (function () {709//https://bugzilla.mozilla.org/show_bug.cgi?id=1439305710//since 1.11.0 always false -> fixed via CSS (hopefully)711scrollbarDummyElement.css(strOverflow, strHidden);712var scrollSize = {713w: scrollbarDummyElement0[LEXICON.sW],714h: scrollbarDummyElement0[LEXICON.sH]715};716scrollbarDummyElement.css(strOverflow, 'visible');717var scrollSize2 = {718w: scrollbarDummyElement0[LEXICON.sW],719h: scrollbarDummyElement0[LEXICON.sH]720};721return (scrollSize.w - scrollSize2.w) !== 0 || (scrollSize.h - scrollSize2.h) !== 0;722})(),723rtlScrollBehavior: (function () {724scrollbarDummyElement.css({ 'overflow-y': strHidden, 'overflow-x': strScroll, 'direction': 'rtl' }).scrollLeft(0);725var dummyContainerOffset = scrollbarDummyElement.offset();726var dummyContainerChildOffset = dummyContainerChild.offset();727//https://github.com/KingSora/OverlayScrollbars/issues/187728scrollbarDummyElement.scrollLeft(-999);729var dummyContainerChildOffsetAfterScroll = dummyContainerChild.offset();730return {731//origin direction = determines if the zero scroll position is on the left or right side732//'i' means 'invert' (i === true means that the axis must be inverted to be correct)733//true = on the left side734//false = on the right side735i: dummyContainerOffset.left === dummyContainerChildOffset.left,736//negative = determines if the maximum scroll is positive or negative737//'n' means 'negate' (n === true means that the axis must be negated to be correct)738//true = negative739//false = positive740n: dummyContainerChildOffset.left !== dummyContainerChildOffsetAfterScroll.left741};742})(),743supportTransform: !!VENDORS._cssProperty('transform'),744supportTransition: !!VENDORS._cssProperty('transition'),745supportPassiveEvents: (function () {746var supportsPassive = false;747try {748window.addEventListener('test', null, Object.defineProperty({}, 'passive', {749get: function () {750supportsPassive = true;751}752}));753} catch (e) { }754return supportsPassive;755})(),756supportResizeObserver: !!COMPATIBILITY.rO(),757supportMutationObserver: !!COMPATIBILITY.mO()758});759
760scrollbarDummyElement.removeAttr(LEXICON.s).remove();761
762//Catch zoom event:763(function () {764if (nativeScrollbarIsOverlaid.x && nativeScrollbarIsOverlaid.y)765return;766
767var abs = MATH.abs;768var windowWidth = COMPATIBILITY.wW();769var windowHeight = COMPATIBILITY.wH();770var windowDpr = getWindowDPR();771var onResize = function () {772if (INSTANCES().length > 0) {773var newW = COMPATIBILITY.wW();774var newH = COMPATIBILITY.wH();775var deltaW = newW - windowWidth;776var deltaH = newH - windowHeight;777
778if (deltaW === 0 && deltaH === 0)779return;780
781var deltaWRatio = MATH.round(newW / (windowWidth / 100.0));782var deltaHRatio = MATH.round(newH / (windowHeight / 100.0));783var absDeltaW = abs(deltaW);784var absDeltaH = abs(deltaH);785var absDeltaWRatio = abs(deltaWRatio);786var absDeltaHRatio = abs(deltaHRatio);787var newDPR = getWindowDPR();788
789var deltaIsBigger = absDeltaW > 2 && absDeltaH > 2;790var difference = !differenceIsBiggerThanOne(absDeltaWRatio, absDeltaHRatio);791var dprChanged = newDPR !== windowDpr && windowDpr > 0;792var isZoom = deltaIsBigger && difference && dprChanged;793var oldScrollbarSize = _base.nativeScrollbarSize;794var newScrollbarSize;795
796if (isZoom) {797bodyElement.append(scrollbarDummyElement);798newScrollbarSize = _base.nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement[0]);799scrollbarDummyElement.remove();800if (oldScrollbarSize.x !== newScrollbarSize.x || oldScrollbarSize.y !== newScrollbarSize.y) {801FRAMEWORK.each(INSTANCES(), function () {802if (INSTANCES(this))803INSTANCES(this).update('zoom');804});805}806}807
808windowWidth = newW;809windowHeight = newH;810windowDpr = newDPR;811}812};813
814function differenceIsBiggerThanOne(valOne, valTwo) {815var absValOne = abs(valOne);816var absValTwo = abs(valTwo);817return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);818}819
820function getWindowDPR() {821var dDPI = window.screen.deviceXDPI || 0;822var sDPI = window.screen.logicalXDPI || 1;823return window.devicePixelRatio || (dDPI / sDPI);824}825
826FRAMEWORK(window).on('resize', onResize);827})();828
829function calcNativeScrollbarSize(measureElement) {830return {831x: measureElement[LEXICON.oH] - measureElement[LEXICON.cH],832y: measureElement[LEXICON.oW] - measureElement[LEXICON.cW]833};834}835}836
837/**838* The object which manages the auto update loop for all OverlayScrollbars objects. This object is initialized only once: if the first OverlayScrollbars object gets initialized.
839* @constructor
840*/
841function OverlayScrollbarsAutoUpdateLoop(globals) {842var _base = this;843var _inArray = FRAMEWORK.inArray;844var _getNow = COMPATIBILITY.now;845var _strAutoUpdate = 'autoUpdate';846var _strAutoUpdateInterval = _strAutoUpdate + 'Interval';847var _strLength = LEXICON.l;848var _loopingInstances = [];849var _loopingInstancesIntervalCache = [];850var _loopIsActive = false;851var _loopIntervalDefault = 33;852var _loopInterval = _loopIntervalDefault;853var _loopTimeOld = _getNow();854var _loopID;855
856
857/**858* The auto update loop which will run every 50 milliseconds or less if the update interval of a instance is lower than 50 milliseconds.
859*/
860var loop = function () {861if (_loopingInstances[_strLength] > 0 && _loopIsActive) {862_loopID = COMPATIBILITY.rAF()(function () {863loop();864});865var timeNew = _getNow();866var timeDelta = timeNew - _loopTimeOld;867var lowestInterval;868var instance;869var instanceOptions;870var instanceAutoUpdateAllowed;871var instanceAutoUpdateInterval;872var now;873
874if (timeDelta > _loopInterval) {875_loopTimeOld = timeNew - (timeDelta % _loopInterval);876lowestInterval = _loopIntervalDefault;877for (var i = 0; i < _loopingInstances[_strLength]; i++) {878instance = _loopingInstances[i];879if (instance !== undefined) {880instanceOptions = instance.options();881instanceAutoUpdateAllowed = instanceOptions[_strAutoUpdate];882instanceAutoUpdateInterval = MATH.max(1, instanceOptions[_strAutoUpdateInterval]);883now = _getNow();884
885if ((instanceAutoUpdateAllowed === true || instanceAutoUpdateAllowed === null) && (now - _loopingInstancesIntervalCache[i]) > instanceAutoUpdateInterval) {886instance.update('auto');887_loopingInstancesIntervalCache[i] = new Date(now += instanceAutoUpdateInterval);888}889
890lowestInterval = MATH.max(1, MATH.min(lowestInterval, instanceAutoUpdateInterval));891}892}893_loopInterval = lowestInterval;894}895} else {896_loopInterval = _loopIntervalDefault;897}898};899
900/**901* Add OverlayScrollbars instance to the auto update loop. Only successful if the instance isn't already added.
902* @param instance The instance which shall be updated in a loop automatically.
903*/
904_base.add = function (instance) {905if (_inArray(instance, _loopingInstances) === -1) {906_loopingInstances.push(instance);907_loopingInstancesIntervalCache.push(_getNow());908if (_loopingInstances[_strLength] > 0 && !_loopIsActive) {909_loopIsActive = true;910globals.autoUpdateLoop = _loopIsActive;911loop();912}913}914};915
916/**917* Remove OverlayScrollbars instance from the auto update loop. Only successful if the instance was added before.
918* @param instance The instance which shall be updated in a loop automatically.
919*/
920_base.remove = function (instance) {921var index = _inArray(instance, _loopingInstances);922if (index > -1) {923//remove from loopingInstances list924_loopingInstancesIntervalCache.splice(index, 1);925_loopingInstances.splice(index, 1);926
927//correct update loop behavior928if (_loopingInstances[_strLength] === 0 && _loopIsActive) {929_loopIsActive = false;930globals.autoUpdateLoop = _loopIsActive;931if (_loopID !== undefined) {932COMPATIBILITY.cAF()(_loopID);933_loopID = -1;934}935}936}937};938}939
940/**941* A object which manages the scrollbars visibility of the target element.
942* @param pluginTargetElement The element from which the scrollbars shall be hidden.
943* @param options The custom options.
944* @param extensions The custom extensions.
945* @param globals
946* @param autoUpdateLoop
947* @returns {*}
948* @constructor
949*/
950function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) {951//shortcuts952var type = COMPATIBILITY.type;953var inArray = FRAMEWORK.inArray;954var each = FRAMEWORK.each;955
956//make correct instanceof957var _base = new _plugin();958var _frameworkProto = FRAMEWORK[LEXICON.p];959
960//if passed element is no HTML element: skip and return961if (!isHTMLElement(pluginTargetElement))962return;963
964//if passed element is already initialized: set passed options if there are any and return its instance965if (INSTANCES(pluginTargetElement)) {966var inst = INSTANCES(pluginTargetElement);967inst.options(options);968return inst;969}970
971//globals:972var _nativeScrollbarIsOverlaid;973var _overlayScrollbarDummySize;974var _rtlScrollBehavior;975var _autoUpdateRecommended;976var _msieVersion;977var _nativeScrollbarStyling;978var _cssCalc;979var _nativeScrollbarSize;980var _supportTransition;981var _supportTransform;982var _supportPassiveEvents;983var _supportResizeObserver;984var _supportMutationObserver;985var _restrictedMeasuring;986
987//general readonly:988var _initialized;989var _destroyed;990var _isTextarea;991var _isBody;992var _documentMixed;993var _domExists;994
995//general:996var _isBorderBox;997var _sizeAutoObserverAdded;998var _paddingX;999var _paddingY;1000var _borderX;1001var _borderY;1002var _marginX;1003var _marginY;1004var _isRTL;1005var _sleeping;1006var _contentBorderSize = {};1007var _scrollHorizontalInfo = {};1008var _scrollVerticalInfo = {};1009var _viewportSize = {};1010var _nativeScrollbarMinSize = {};1011
1012//naming:1013var _strMinusHidden = '-hidden';1014var _strMarginMinus = 'margin-';1015var _strPaddingMinus = 'padding-';1016var _strBorderMinus = 'border-';1017var _strTop = 'top';1018var _strRight = 'right';1019var _strBottom = 'bottom';1020var _strLeft = 'left';1021var _strMinMinus = 'min-';1022var _strMaxMinus = 'max-';1023var _strWidth = 'width';1024var _strHeight = 'height';1025var _strFloat = 'float';1026var _strEmpty = '';1027var _strAuto = 'auto';1028var _strSync = 'sync';1029var _strScroll = 'scroll';1030var _strHundredPercent = '100%';1031var _strX = 'x';1032var _strY = 'y';1033var _strDot = '.';1034var _strSpace = ' ';1035var _strScrollbar = 'scrollbar';1036var _strMinusHorizontal = '-horizontal';1037var _strMinusVertical = '-vertical';1038var _strScrollLeft = _strScroll + 'Left';1039var _strScrollTop = _strScroll + 'Top';1040var _strMouseTouchDownEvent = 'mousedown touchstart';1041var _strMouseTouchUpEvent = 'mouseup touchend touchcancel';1042var _strMouseTouchMoveEvent = 'mousemove touchmove';1043var _strMouseEnter = 'mouseenter';1044var _strMouseLeave = 'mouseleave';1045var _strKeyDownEvent = 'keydown';1046var _strKeyUpEvent = 'keyup';1047var _strSelectStartEvent = 'selectstart';1048var _strTransitionEndEvent = 'transitionend webkitTransitionEnd oTransitionEnd';1049var _strResizeObserverProperty = '__overlayScrollbarsRO__';1050
1051//class names:1052var _cassNamesPrefix = 'os-';1053var _classNameHTMLElement = _cassNamesPrefix + 'html';1054var _classNameHostElement = _cassNamesPrefix + 'host';1055var _classNameHostElementForeign = _classNameHostElement + '-foreign';1056var _classNameHostTextareaElement = _classNameHostElement + '-textarea';1057var _classNameHostScrollbarHorizontalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusHorizontal + _strMinusHidden;1058var _classNameHostScrollbarVerticalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusVertical + _strMinusHidden;1059var _classNameHostTransition = _classNameHostElement + '-transition';1060var _classNameHostRTL = _classNameHostElement + '-rtl';1061var _classNameHostResizeDisabled = _classNameHostElement + '-resize-disabled';1062var _classNameHostScrolling = _classNameHostElement + '-scrolling';1063var _classNameHostOverflow = _classNameHostElement + '-overflow';1064var _classNameHostOverflow = _classNameHostElement + '-overflow';1065var _classNameHostOverflowX = _classNameHostOverflow + '-x';1066var _classNameHostOverflowY = _classNameHostOverflow + '-y';1067var _classNameTextareaElement = _cassNamesPrefix + 'textarea';1068var _classNameTextareaCoverElement = _classNameTextareaElement + '-cover';1069var _classNamePaddingElement = _cassNamesPrefix + 'padding';1070var _classNameViewportElement = _cassNamesPrefix + 'viewport';1071var _classNameViewportNativeScrollbarsInvisible = _classNameViewportElement + '-native-scrollbars-invisible';1072var _classNameViewportNativeScrollbarsOverlaid = _classNameViewportElement + '-native-scrollbars-overlaid';1073var _classNameContentElement = _cassNamesPrefix + 'content';1074var _classNameContentArrangeElement = _cassNamesPrefix + 'content-arrange';1075var _classNameContentGlueElement = _cassNamesPrefix + 'content-glue';1076var _classNameSizeAutoObserverElement = _cassNamesPrefix + 'size-auto-observer';1077var _classNameResizeObserverElement = _cassNamesPrefix + 'resize-observer';1078var _classNameResizeObserverItemElement = _cassNamesPrefix + 'resize-observer-item';1079var _classNameResizeObserverItemFinalElement = _classNameResizeObserverItemElement + '-final';1080var _classNameTextInherit = _cassNamesPrefix + 'text-inherit';1081var _classNameScrollbar = _cassNamesPrefix + _strScrollbar;1082var _classNameScrollbarTrack = _classNameScrollbar + '-track';1083var _classNameScrollbarTrackOff = _classNameScrollbarTrack + '-off';1084var _classNameScrollbarHandle = _classNameScrollbar + '-handle';1085var _classNameScrollbarHandleOff = _classNameScrollbarHandle + '-off';1086var _classNameScrollbarUnusable = _classNameScrollbar + '-unusable';1087var _classNameScrollbarAutoHidden = _classNameScrollbar + '-' + _strAuto + _strMinusHidden;1088var _classNameScrollbarCorner = _classNameScrollbar + '-corner';1089var _classNameScrollbarCornerResize = _classNameScrollbarCorner + '-resize';1090var _classNameScrollbarCornerResizeB = _classNameScrollbarCornerResize + '-both';1091var _classNameScrollbarCornerResizeH = _classNameScrollbarCornerResize + _strMinusHorizontal;1092var _classNameScrollbarCornerResizeV = _classNameScrollbarCornerResize + _strMinusVertical;1093var _classNameScrollbarHorizontal = _classNameScrollbar + _strMinusHorizontal;1094var _classNameScrollbarVertical = _classNameScrollbar + _strMinusVertical;1095var _classNameDragging = _cassNamesPrefix + 'dragging';1096var _classNameThemeNone = _cassNamesPrefix + 'theme-none';1097var _classNamesDynamicDestroy = [1098_classNameViewportNativeScrollbarsInvisible,1099_classNameViewportNativeScrollbarsOverlaid,1100_classNameScrollbarTrackOff,1101_classNameScrollbarHandleOff,1102_classNameScrollbarUnusable,1103_classNameScrollbarAutoHidden,1104_classNameScrollbarCornerResize,1105_classNameScrollbarCornerResizeB,1106_classNameScrollbarCornerResizeH,1107_classNameScrollbarCornerResizeV,1108_classNameDragging].join(_strSpace);1109
1110//callbacks:1111var _callbacksInitQeueue = [];1112
1113//attrs viewport shall inherit from target1114var _viewportAttrsFromTarget = [LEXICON.ti];1115
1116//options:1117var _defaultOptions;1118var _currentOptions;1119var _currentPreparedOptions;1120
1121//extensions:1122var _extensions = {};1123var _extensionsPrivateMethods = 'added removed on contract';1124
1125//update1126var _lastUpdateTime;1127var _swallowedUpdateHints = {};1128var _swallowedUpdateTimeout;1129var _swallowUpdateLag = 42;1130var _updateOnLoadEventName = 'load';1131var _updateOnLoadElms = [];1132
1133//DOM elements:1134var _windowElement;1135var _documentElement;1136var _htmlElement;1137var _bodyElement;1138var _targetElement; //the target element of this OverlayScrollbars object1139var _hostElement; //the host element of this OverlayScrollbars object -> may be the same as targetElement1140var _sizeAutoObserverElement; //observes size auto changes1141var _sizeObserverElement; //observes size and padding changes1142var _paddingElement; //manages the padding1143var _viewportElement; //is the viewport of our scrollbar model1144var _contentElement; //the element which holds the content1145var _contentArrangeElement; //is needed for correct sizing of the content element (only if native scrollbars are overlays)1146var _contentGlueElement; //has always the size of the content element1147var _textareaCoverElement; //only applied if target is a textarea element. Used for correct size calculation and for prevention of uncontrolled scrolling1148var _scrollbarCornerElement;1149var _scrollbarHorizontalElement;1150var _scrollbarHorizontalTrackElement;1151var _scrollbarHorizontalHandleElement;1152var _scrollbarVerticalElement;1153var _scrollbarVerticalTrackElement;1154var _scrollbarVerticalHandleElement;1155var _windowElementNative;1156var _documentElementNative;1157var _targetElementNative;1158var _hostElementNative;1159var _sizeAutoObserverElementNative;1160var _sizeObserverElementNative;1161var _paddingElementNative;1162var _viewportElementNative;1163var _contentElementNative;1164
1165//Cache:1166var _hostSizeCache;1167var _contentScrollSizeCache;1168var _arrangeContentSizeCache;1169var _hasOverflowCache;1170var _hideOverflowCache;1171var _widthAutoCache;1172var _heightAutoCache;1173var _cssBoxSizingCache;1174var _cssPaddingCache;1175var _cssBorderCache;1176var _cssMarginCache;1177var _cssDirectionCache;1178var _cssDirectionDetectedCache;1179var _paddingAbsoluteCache;1180var _clipAlwaysCache;1181var _contentGlueSizeCache;1182var _overflowBehaviorCache;1183var _overflowAmountCache;1184var _ignoreOverlayScrollbarHidingCache;1185var _autoUpdateCache;1186var _sizeAutoCapableCache;1187var _contentElementScrollSizeChangeDetectedCache;1188var _hostElementSizeChangeDetectedCache;1189var _scrollbarsVisibilityCache;1190var _scrollbarsAutoHideCache;1191var _scrollbarsClickScrollingCache;1192var _scrollbarsDragScrollingCache;1193var _resizeCache;1194var _normalizeRTLCache;1195var _classNameCache;1196var _oldClassName;1197var _textareaAutoWrappingCache;1198var _textareaInfoCache;1199var _textareaSizeCache;1200var _textareaDynHeightCache;1201var _textareaDynWidthCache;1202var _bodyMinSizeCache;1203var _updateAutoCache = {};1204
1205//MutationObserver:1206var _mutationObserverHost;1207var _mutationObserverContent;1208var _mutationObserverHostCallback;1209var _mutationObserverContentCallback;1210var _mutationObserversConnected;1211var _mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows'];1212var _mutationObserverAttrsHost = [LEXICON.i, LEXICON.c, LEXICON.s, 'open'].concat(_viewportAttrsFromTarget);1213
1214//events:1215var _destroyEvents = [];1216
1217//textarea:1218var _textareaHasFocus;1219
1220//scrollbars:1221var _scrollbarsAutoHideTimeoutId;1222var _scrollbarsAutoHideMoveTimeoutId;1223var _scrollbarsAutoHideDelay;1224var _scrollbarsAutoHideNever;1225var _scrollbarsAutoHideScroll;1226var _scrollbarsAutoHideMove;1227var _scrollbarsAutoHideLeave;1228var _scrollbarsHandleHovered;1229var _scrollbarsHandlesDefineScrollPos;1230
1231//resize1232var _resizeNone;1233var _resizeBoth;1234var _resizeHorizontal;1235var _resizeVertical;1236
1237
1238//==== Event Listener ====//1239
1240/**1241* Adds or removes a event listener from the given element.
1242* @param element The element to which the event listener shall be applied or removed.
1243* @param eventNames The name(s) of the events.
1244* @param listener The method which shall be called.
1245* @param remove True if the handler shall be removed, false or undefined if the handler shall be added.
1246* @param passiveOrOptions The options for the event.
1247*/
1248function setupResponsiveEventListener(element, eventNames, listener, remove, passiveOrOptions) {1249var collected = COMPATIBILITY.isA(eventNames) && COMPATIBILITY.isA(listener);1250var method = remove ? 'removeEventListener' : 'addEventListener';1251var onOff = remove ? 'off' : 'on';1252var events = collected ? false : eventNames.split(_strSpace)1253var i = 0;1254
1255var passiveOrOptionsIsObj = FRAMEWORK.isPlainObject(passiveOrOptions);1256var passive = (_supportPassiveEvents && (passiveOrOptionsIsObj ? (passiveOrOptions._passive) : passiveOrOptions)) || false;1257var capture = passiveOrOptionsIsObj && (passiveOrOptions._capture || false);1258var nativeParam = _supportPassiveEvents ? {1259passive: passive,1260capture: capture,1261} : capture;1262
1263if (collected) {1264for (; i < eventNames[LEXICON.l]; i++)1265setupResponsiveEventListener(element, eventNames[i], listener[i], remove, passiveOrOptions);1266}1267else {1268for (; i < events[LEXICON.l]; i++) {1269if(_supportPassiveEvents) {1270element[0][method](events[i], listener, nativeParam);1271}1272else {1273element[onOff](events[i], listener);1274}1275}1276}1277}1278
1279
1280function addDestroyEventListener(element, eventNames, listener, passive) {1281setupResponsiveEventListener(element, eventNames, listener, false, passive);1282_destroyEvents.push(COMPATIBILITY.bind(setupResponsiveEventListener, 0, element, eventNames, listener, true, passive));1283}1284
1285//==== Resize Observer ====//1286
1287/**1288* Adds or removes a resize observer from the given element.
1289* @param targetElement The element to which the resize observer shall be added or removed.
1290* @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change or false / undefined if the resizeObserver shall be removed.
1291*/
1292function setupResizeObserver(targetElement, onElementResizedCallback) {1293if (targetElement) {1294var resizeObserver = COMPATIBILITY.rO();1295var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart';1296var strChildNodes = 'childNodes';1297var constScroll = 3333333;1298var callback = function () {1299targetElement[_strScrollTop](constScroll)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll : constScroll);1300onElementResizedCallback();1301};1302//add resize observer:1303if (onElementResizedCallback) {1304if (_supportResizeObserver) {1305var element = targetElement.addClass('observed').append(generateDiv(_classNameResizeObserverElement)).contents()[0];1306var observer = element[_strResizeObserverProperty] = new resizeObserver(callback);1307observer.observe(element);1308}1309else {1310if (_msieVersion > 9 || !_autoUpdateRecommended) {1311targetElement.prepend(1312generateDiv(_classNameResizeObserverElement,1313generateDiv({ c: _classNameResizeObserverItemElement, dir: 'ltr' },1314generateDiv(_classNameResizeObserverItemElement,1315generateDiv(_classNameResizeObserverItemFinalElement)1316) +1317generateDiv(_classNameResizeObserverItemElement,1318generateDiv({ c: _classNameResizeObserverItemFinalElement, style: 'width: 200%; height: 200%' })1319)1320)1321)1322);1323
1324var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0];1325var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]);1326var expandElement = FRAMEWORK(observerElement[strChildNodes][0]);1327var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]);1328var widthCache = observerElement[LEXICON.oW];1329var heightCache = observerElement[LEXICON.oH];1330var isDirty;1331var rAFId;1332var currWidth;1333var currHeight;1334var factor = 2;1335var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!!1336var reset = function () {1337/*1338var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
1339var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
1340var expandChildCSS = {};
1341expandChildCSS[_strWidth] = sizeResetWidth;
1342expandChildCSS[_strHeight] = sizeResetHeight;
1343expandElementChild.css(expandChildCSS);
1344
1345
1346expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
1347shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
1348*/
1349expandElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);1350shrinkElement[_strScrollLeft](constScroll)[_strScrollTop](constScroll);1351};1352var onResized = function () {1353rAFId = 0;1354if (!isDirty)1355return;1356
1357widthCache = currWidth;1358heightCache = currHeight;1359callback();1360};1361var onScroll = function (event) {1362currWidth = observerElement[LEXICON.oW];1363currHeight = observerElement[LEXICON.oH];1364isDirty = currWidth != widthCache || currHeight != heightCache;1365
1366if (event && isDirty && !rAFId) {1367COMPATIBILITY.cAF()(rAFId);1368rAFId = COMPATIBILITY.rAF()(onResized);1369}1370else if (!event)1371onResized();1372
1373reset();1374if (event) {1375COMPATIBILITY.prvD(event);1376COMPATIBILITY.stpP(event);1377}1378return false;1379};1380var expandChildCSS = {};1381var observerElementCSS = {};1382
1383setTopRightBottomLeft(observerElementCSS, _strEmpty, [1384-((nativeScrollbarSize.y + 1) * factor),1385nativeScrollbarSize.x * -factor,1386nativeScrollbarSize.y * -factor,1387-((nativeScrollbarSize.x + 1) * factor)1388]);1389
1390FRAMEWORK(observerElement).css(observerElementCSS);1391expandElement.on(_strScroll, onScroll);1392shrinkElement.on(_strScroll, onScroll);1393targetElement.on(strAnimationStartEvent, function () {1394onScroll(false);1395});1396//lets assume that the divs will never be that large and a constant value is enough1397expandChildCSS[_strWidth] = constScroll;1398expandChildCSS[_strHeight] = constScroll;1399expandElementChild.css(expandChildCSS);1400
1401reset();1402}1403else {1404var attachEvent = _documentElementNative.attachEvent;1405var isIE = _msieVersion !== undefined;1406if (attachEvent) {1407targetElement.prepend(generateDiv(_classNameResizeObserverElement));1408findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback);1409}1410else {1411var obj = _documentElementNative.createElement(TYPES.o);1412obj.setAttribute(LEXICON.ti, '-1');1413obj.setAttribute(LEXICON.c, _classNameResizeObserverElement);1414obj.onload = function () {1415var wnd = this.contentDocument.defaultView;1416wnd.addEventListener('resize', callback);1417wnd.document.documentElement.style.display = 'none';1418};1419obj.type = 'text/html';1420if (isIE)1421targetElement.prepend(obj);1422obj.data = 'about:blank';1423if (!isIE)1424targetElement.prepend(obj);1425targetElement.on(strAnimationStartEvent, callback);1426}1427}1428}1429
1430if (targetElement[0] === _sizeObserverElementNative) {1431var directionChanged = function () {1432var dir = _hostElement.css('direction');1433var css = {};1434var scrollLeftValue = 0;1435var result = false;1436if (dir !== _cssDirectionDetectedCache) {1437if (dir === 'ltr') {1438css[_strLeft] = 0;1439css[_strRight] = _strAuto;1440scrollLeftValue = constScroll;1441}1442else {1443css[_strLeft] = _strAuto;1444css[_strRight] = 0;1445scrollLeftValue = _rtlScrollBehavior.n ? -constScroll : _rtlScrollBehavior.i ? 0 : constScroll;1446}1447//execution order is important for IE!!!1448_sizeObserverElement.children().eq(0).css(css);1449_sizeObserverElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constScroll);1450_cssDirectionDetectedCache = dir;1451result = true;1452}1453return result;1454};1455directionChanged();1456addDestroyEventListener(targetElement, _strScroll, function (event) {1457if (directionChanged())1458update();1459COMPATIBILITY.prvD(event);1460COMPATIBILITY.stpP(event);1461return false;1462});1463}1464}1465//remove resize observer:1466else {1467if (_supportResizeObserver) {1468var element = targetElement.contents()[0];1469var resizeObserverObj = element[_strResizeObserverProperty];1470if (resizeObserverObj) {1471resizeObserverObj.disconnect();1472delete element[_strResizeObserverProperty];1473}1474}1475else {1476remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0));1477}1478}1479}1480}1481
1482/**1483* Freezes or unfreezes the given resize observer.
1484* @param targetElement The element to which the target resize observer is applied.
1485* @param freeze True if the resize observer shall be frozen, false otherwise.
1486
1487function freezeResizeObserver(targetElement, freeze) {
1488if (targetElement !== undefined) {
1489if(freeze) {
1490if (_supportResizeObserver) {
1491var element = targetElement.contents()[0];
1492element[_strResizeObserverProperty].unobserve(element);
1493}
1494else {
1495targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0);
1496var w = targetElement.css(_strWidth);
1497var h = targetElement.css(_strHeight);
1498var css = {};
1499css[_strWidth] = w;
1500css[_strHeight] = h;
1501targetElement.css(css);
1502}
1503}
1504else {
1505if (_supportResizeObserver) {
1506var element = targetElement.contents()[0];
1507element[_strResizeObserverProperty].observe(element);
1508}
1509else {
1510var css = { };
1511css[_strHeight] = _strEmpty;
1512css[_strWidth] = _strEmpty;
1513targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css);
1514}
1515}
1516}
1517}
1518*/
1519
1520
1521//==== Mutation Observers ====//1522
1523/**1524* Creates MutationObservers for the host and content Element if they are supported.
1525*/
1526function createMutationObservers() {1527if (_supportMutationObserver) {1528var mutationObserverContentLag = 11;1529var mutationObserver = COMPATIBILITY.mO();1530var contentLastUpdate = COMPATIBILITY.now();1531var mutationTarget;1532var mutationAttrName;1533var mutationIsClass;1534var oldMutationVal;1535var newClassVal;1536var hostClassNameRegex;1537var contentTimeout;1538var now;1539var sizeAuto;1540var action;1541
1542_mutationObserverHostCallback = function (mutations) {1543
1544var doUpdate = false;1545var doUpdateForce = false;1546var mutation;1547var mutatedAttrs = [];1548
1549if (_initialized && !_sleeping) {1550each(mutations, function () {1551mutation = this;1552mutationTarget = mutation.target;1553mutationAttrName = mutation.attributeName;1554mutationIsClass = mutationAttrName === LEXICON.c;1555oldMutationVal = mutation.oldValue;1556newClassVal = mutationTarget.className;1557
1558if (_domExists && mutationIsClass && !doUpdateForce) {1559// if old class value contains _classNameHostElementForeign and new class value doesn't1560if (oldMutationVal.indexOf(_classNameHostElementForeign) > -1 && newClassVal.indexOf(_classNameHostElementForeign) < 0) {1561hostClassNameRegex = createHostClassNameRegExp(true);1562_hostElementNative.className = newClassVal.split(_strSpace).concat(oldMutationVal.split(_strSpace).filter(function (name) {1563return name.match(hostClassNameRegex);1564})).join(_strSpace);1565doUpdate = doUpdateForce = true;1566}1567}1568
1569if (!doUpdate) {1570doUpdate = mutationIsClass1571? hostClassNamesChanged(oldMutationVal, newClassVal)1572: mutationAttrName === LEXICON.s1573? oldMutationVal !== mutationTarget[LEXICON.s].cssText1574: true;1575}1576
1577mutatedAttrs.push(mutationAttrName);1578});1579
1580updateViewportAttrsFromTarget(mutatedAttrs);1581
1582if (doUpdate)1583_base.update(doUpdateForce || _strAuto);1584}1585return doUpdate;1586};1587_mutationObserverContentCallback = function (mutations) {1588var doUpdate = false;1589var mutation;1590
1591if (_initialized && !_sleeping) {1592each(mutations, function () {1593mutation = this;1594doUpdate = isUnknownMutation(mutation);1595return !doUpdate;1596});1597
1598if (doUpdate) {1599now = COMPATIBILITY.now();1600sizeAuto = (_heightAutoCache || _widthAutoCache);1601action = function () {1602if (!_destroyed) {1603contentLastUpdate = now;1604
1605//if cols, rows or wrap attr was changed1606if (_isTextarea)1607textareaUpdate();1608
1609if (sizeAuto)1610update();1611else1612_base.update(_strAuto);1613}1614};1615clearTimeout(contentTimeout);1616if (mutationObserverContentLag <= 0 || now - contentLastUpdate > mutationObserverContentLag || !sizeAuto)1617action();1618else1619contentTimeout = setTimeout(action, mutationObserverContentLag);1620}1621}1622return doUpdate;1623}1624
1625_mutationObserverHost = new mutationObserver(_mutationObserverHostCallback);1626_mutationObserverContent = new mutationObserver(_mutationObserverContentCallback);1627}1628}1629
1630/**1631* Connects the MutationObservers if they are supported.
1632*/
1633function connectMutationObservers() {1634if (_supportMutationObserver && !_mutationObserversConnected) {1635_mutationObserverHost.observe(_hostElementNative, {1636attributes: true,1637attributeOldValue: true,1638attributeFilter: _mutationObserverAttrsHost1639});1640
1641_mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, {1642attributes: true,1643attributeOldValue: true,1644subtree: !_isTextarea,1645childList: !_isTextarea,1646characterData: !_isTextarea,1647attributeFilter: _isTextarea ? _mutationObserverAttrsTextarea : _mutationObserverAttrsHost1648});1649
1650_mutationObserversConnected = true;1651}1652}1653
1654/**1655* Disconnects the MutationObservers if they are supported.
1656*/
1657function disconnectMutationObservers() {1658if (_supportMutationObserver && _mutationObserversConnected) {1659_mutationObserverHost.disconnect();1660_mutationObserverContent.disconnect();1661
1662_mutationObserversConnected = false;1663}1664}1665
1666
1667//==== Events of elements ====//1668
1669/**1670* This method gets called every time the host element gets resized. IMPORTANT: Padding changes are detected too!!
1671* It refreshes the hostResizedEventArgs and the hostSizeResizeCache.
1672* If there are any size changes, the update method gets called.
1673*/
1674function hostOnResized() {1675if (!_sleeping) {1676var changed;1677var hostSize = {1678w: _sizeObserverElementNative[LEXICON.sW],1679h: _sizeObserverElementNative[LEXICON.sH]1680};1681
1682changed = checkCache(hostSize, _hostElementSizeChangeDetectedCache);1683_hostElementSizeChangeDetectedCache = hostSize;1684if (changed)1685update({ _hostSizeChanged: true });1686}1687}1688
1689/**1690* The mouse enter event of the host element. This event is only needed for the autoHide feature.
1691*/
1692function hostOnMouseEnter() {1693if (_scrollbarsAutoHideLeave)1694refreshScrollbarsAutoHide(true);1695}1696
1697/**1698* The mouse leave event of the host element. This event is only needed for the autoHide feature.
1699*/
1700function hostOnMouseLeave() {1701if (_scrollbarsAutoHideLeave && !_bodyElement.hasClass(_classNameDragging))1702refreshScrollbarsAutoHide(false);1703}1704
1705/**1706* The mouse move event of the host element. This event is only needed for the autoHide "move" feature.
1707*/
1708function hostOnMouseMove() {1709if (_scrollbarsAutoHideMove) {1710refreshScrollbarsAutoHide(true);1711clearTimeout(_scrollbarsAutoHideMoveTimeoutId);1712_scrollbarsAutoHideMoveTimeoutId = setTimeout(function () {1713if (_scrollbarsAutoHideMove && !_destroyed)1714refreshScrollbarsAutoHide(false);1715}, 100);1716}1717}1718
1719/**1720* Prevents text from deselection if attached to the document element on the mousedown event of a DOM element.
1721* @param event The select start event.
1722*/
1723function documentOnSelectStart(event) {1724COMPATIBILITY.prvD(event);1725return false;1726}1727
1728/**1729* A callback which will be called after a element has loaded.
1730*/
1731function updateOnLoadCallback(event) {1732var elm = FRAMEWORK(event.target);1733
1734eachUpdateOnLoad(function (i, updateOnLoadSelector) {1735if (elm.is(updateOnLoadSelector)) {1736update({ _contentSizeChanged: true });1737}1738});1739}1740
1741/**1742* Adds or removes mouse & touch events of the host element. (for handling auto-hiding of the scrollbars)
1743* @param destroy Indicates whether the events shall be added or removed.
1744*/
1745function setupHostMouseTouchEvents(destroy) {1746if (!destroy)1747setupHostMouseTouchEvents(true);1748
1749setupResponsiveEventListener(_hostElement,1750_strMouseTouchMoveEvent.split(_strSpace)[0],1751hostOnMouseMove,1752(!_scrollbarsAutoHideMove || destroy), true);1753setupResponsiveEventListener(_hostElement,1754[_strMouseEnter, _strMouseLeave],1755[hostOnMouseEnter, hostOnMouseLeave],1756(!_scrollbarsAutoHideLeave || destroy), true);1757
1758//if the plugin is initialized and the mouse is over the host element, make the scrollbars visible1759if (!_initialized && !destroy)1760_hostElement.one('mouseover', hostOnMouseEnter);1761}1762
1763
1764//==== Update Detection ====//1765
1766/**1767* Measures the min width and min height of the body element and refreshes the related cache.
1768* @returns {boolean} True if the min width or min height has changed, false otherwise.
1769*/
1770function bodyMinSizeChanged() {1771var bodyMinSize = {};1772if (_isBody && _contentArrangeElement) {1773bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth));1774bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight));1775bodyMinSize.c = checkCache(bodyMinSize, _bodyMinSizeCache);1776bodyMinSize.f = true; //flag for "measured at least once"1777}1778_bodyMinSizeCache = bodyMinSize;1779return !!bodyMinSize.c;1780}1781
1782/**1783* Returns true if the class names really changed (new class without plugin host prefix)
1784* @param oldClassNames The old ClassName string or array.
1785* @param newClassNames The new ClassName string or array.
1786* @returns {boolean} True if the class names has really changed, false otherwise.
1787*/
1788function hostClassNamesChanged(oldClassNames, newClassNames) {1789var currClasses = typeof newClassNames == TYPES.s ? newClassNames.split(_strSpace) : [];1790var oldClasses = typeof oldClassNames == TYPES.s ? oldClassNames.split(_strSpace) : [];1791var diff = getArrayDifferences(oldClasses, currClasses);1792
1793// remove none theme from diff list to prevent update1794var idx = inArray(_classNameThemeNone, diff);1795var i;1796var regex;1797
1798if (idx > -1)1799diff.splice(idx, 1);1800
1801if (diff[LEXICON.l] > 0) {1802regex = createHostClassNameRegExp(true, true);1803for (i = 0; i < diff.length; i++) {1804if (!diff[i].match(regex)) {1805return true;1806}1807}1808}1809return false;1810}1811
1812/**1813* Returns true if the given mutation is not from a from the plugin generated element. If the target element is a textarea the mutation is always unknown.
1814* @param mutation The mutation which shall be checked.
1815* @returns {boolean} True if the mutation is from a unknown element, false otherwise.
1816*/
1817function isUnknownMutation(mutation) {1818var attributeName = mutation.attributeName;1819var mutationTarget = mutation.target;1820var mutationType = mutation.type;1821var strClosest = 'closest';1822
1823if (mutationTarget === _contentElementNative)1824return attributeName === null;1825if (mutationType === 'attributes' && (attributeName === LEXICON.c || attributeName === LEXICON.s) && !_isTextarea) {1826//ignore className changes by the plugin1827if (attributeName === LEXICON.c && FRAMEWORK(mutationTarget).hasClass(_classNameHostElement))1828return hostClassNamesChanged(mutation.oldValue, mutationTarget.className);1829
1830//only do it of browser support it natively1831if (typeof mutationTarget[strClosest] != TYPES.f)1832return true;1833if (mutationTarget[strClosest](_strDot + _classNameResizeObserverElement) !== null ||1834mutationTarget[strClosest](_strDot + _classNameScrollbar) !== null ||1835mutationTarget[strClosest](_strDot + _classNameScrollbarCorner) !== null)1836return false;1837}1838return true;1839}1840
1841/**1842* Returns true if the content size was changed since the last time this method was called.
1843* @returns {boolean} True if the content size was changed, false otherwise.
1844*/
1845function updateAutoContentSizeChanged() {1846if (_sleeping)1847return false;1848
1849var contentMeasureElement = getContentMeasureElement();1850var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0;1851var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea;1852var css = {};1853var float;1854var bodyMinSizeC;1855var changed;1856var contentElementScrollSize;1857
1858if (setCSS) {1859float = _contentElement.css(_strFloat);1860css[_strFloat] = _isRTL ? _strRight : _strLeft;1861css[_strWidth] = _strAuto;1862_contentElement.css(css);1863}1864contentElementScrollSize = {1865w: contentMeasureElement[LEXICON.sW] + textareaValueLength,1866h: contentMeasureElement[LEXICON.sH] + textareaValueLength1867};1868if (setCSS) {1869css[_strFloat] = float;1870css[_strWidth] = _strHundredPercent;1871_contentElement.css(css);1872}1873
1874bodyMinSizeC = bodyMinSizeChanged();1875changed = checkCache(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache);1876
1877_contentElementScrollSizeChangeDetectedCache = contentElementScrollSize;1878
1879return changed || bodyMinSizeC;1880}1881
1882/**1883* Returns true when a attribute which the MutationObserver would observe has changed.
1884* @returns {boolean} True if one of the attributes which a MutationObserver would observe has changed, false or undefined otherwise.
1885*/
1886function meaningfulAttrsChanged() {1887if (_sleeping || _mutationObserversConnected)1888return;1889
1890var elem;1891var curr;1892var cache;1893var changedAttrs = [];1894var checks = [1895{1896_elem: _hostElement,1897_attrs: _mutationObserverAttrsHost.concat(':visible')1898},1899{1900_elem: _isTextarea ? _targetElement : undefined,1901_attrs: _mutationObserverAttrsTextarea1902}1903];1904
1905each(checks, function (index, check) {1906elem = check._elem;1907if (elem) {1908each(check._attrs, function (index, attr) {1909curr = attr.charAt(0) === ':' ? elem.is(attr) : elem.attr(attr);1910cache = _updateAutoCache[attr];1911
1912if (checkCache(curr, cache)) {1913changedAttrs.push(attr);1914}1915
1916_updateAutoCache[attr] = curr;1917});1918}1919});1920
1921updateViewportAttrsFromTarget(changedAttrs);1922
1923return changedAttrs[LEXICON.l] > 0;1924}1925
1926/**1927* Checks is a CSS Property of a child element is affecting the scroll size of the content.
1928* @param propertyName The CSS property name.
1929* @returns {boolean} True if the property is affecting the content scroll size, false otherwise.
1930*/
1931function isSizeAffectingCSSProperty(propertyName) {1932if (!_initialized)1933return true;1934var flexGrow = 'flex-grow';1935var flexShrink = 'flex-shrink';1936var flexBasis = 'flex-basis';1937var affectingPropsX = [1938_strWidth,1939_strMinMinus + _strWidth,1940_strMaxMinus + _strWidth,1941_strMarginMinus + _strLeft,1942_strMarginMinus + _strRight,1943_strLeft,1944_strRight,1945'font-weight',1946'word-spacing',1947flexGrow,1948flexShrink,1949flexBasis
1950];1951var affectingPropsXContentBox = [1952_strPaddingMinus + _strLeft,1953_strPaddingMinus + _strRight,1954_strBorderMinus + _strLeft + _strWidth,1955_strBorderMinus + _strRight + _strWidth1956];1957var affectingPropsY = [1958_strHeight,1959_strMinMinus + _strHeight,1960_strMaxMinus + _strHeight,1961_strMarginMinus + _strTop,1962_strMarginMinus + _strBottom,1963_strTop,1964_strBottom,1965'line-height',1966flexGrow,1967flexShrink,1968flexBasis
1969];1970var affectingPropsYContentBox = [1971_strPaddingMinus + _strTop,1972_strPaddingMinus + _strBottom,1973_strBorderMinus + _strTop + _strWidth,1974_strBorderMinus + _strBottom + _strWidth1975];1976var _strS = 's';1977var _strVS = 'v-s';1978var checkX = _overflowBehaviorCache.x === _strS || _overflowBehaviorCache.x === _strVS;1979var checkY = _overflowBehaviorCache.y === _strS || _overflowBehaviorCache.y === _strVS;1980var sizeIsAffected = false;1981var checkPropertyName = function (arr, name) {1982for (var i = 0; i < arr[LEXICON.l]; i++) {1983if (arr[i] === name)1984return true;1985}1986return false;1987};1988
1989if (checkY) {1990sizeIsAffected = checkPropertyName(affectingPropsY, propertyName);1991if (!sizeIsAffected && !_isBorderBox)1992sizeIsAffected = checkPropertyName(affectingPropsYContentBox, propertyName);1993}1994if (checkX && !sizeIsAffected) {1995sizeIsAffected = checkPropertyName(affectingPropsX, propertyName);1996if (!sizeIsAffected && !_isBorderBox)1997sizeIsAffected = checkPropertyName(affectingPropsXContentBox, propertyName);1998}1999return sizeIsAffected;2000}2001
2002
2003//==== Update ====//2004
2005/**2006* Sets the attribute values of the viewport element to the values from the target element.
2007* The value of a attribute is only set if the attribute is whitelisted.
2008* @attrs attrs The array of attributes which shall be set or undefined if all whitelisted shall be set.
2009*/
2010function updateViewportAttrsFromTarget(attrs) {2011attrs = attrs || _viewportAttrsFromTarget;2012each(attrs, function (index, attr) {2013if (COMPATIBILITY.inA(attr, _viewportAttrsFromTarget) > -1) {2014var targetAttr = _targetElement.attr(attr);2015if (type(targetAttr) == TYPES.s) {2016_viewportElement.attr(attr, targetAttr);2017}2018else {2019_viewportElement.removeAttr(attr);2020}2021}2022});2023}2024
2025/**2026* Updates the variables and size of the textarea element, and manages the scroll on new line or new character.
2027*/
2028function textareaUpdate() {2029if (!_sleeping) {2030var wrapAttrOff = !_textareaAutoWrappingCache;2031var minWidth = _viewportSize.w;2032var minHeight = _viewportSize.h;2033var css = {};2034var doMeasure = _widthAutoCache || wrapAttrOff;2035var origWidth;2036var width;2037var origHeight;2038var height;2039
2040//reset min size2041css[_strMinMinus + _strWidth] = _strEmpty;2042css[_strMinMinus + _strHeight] = _strEmpty;2043
2044//set width auto2045css[_strWidth] = _strAuto;2046_targetElement.css(css);2047
2048//measure width2049origWidth = _targetElementNative[LEXICON.oW];2050width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1;2051/*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/2052
2053//set measured width2054css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent;2055css[_strMinMinus + _strWidth] = _strHundredPercent;2056
2057//set height auto2058css[_strHeight] = _strAuto;2059_targetElement.css(css);2060
2061//measure height2062origHeight = _targetElementNative[LEXICON.oH];2063height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1);2064
2065//append correct size values2066css[_strWidth] = width;2067css[_strHeight] = height;2068_textareaCoverElement.css(css);2069
2070//apply min width / min height to prevent textarea collapsing2071css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/;2072css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/;2073_targetElement.css(css);2074
2075return {2076_originalWidth: origWidth,2077_originalHeight: origHeight,2078_dynamicWidth: width,2079_dynamicHeight: height2080};2081}2082}2083
2084/**2085* Updates the plugin and DOM to the current options.
2086* This method should only be called if a update is 100% required.
2087* @param updateHints A objects which contains hints for this update:
2088* {
2089* _hostSizeChanged : boolean,
2090* _contentSizeChanged : boolean,
2091* _force : boolean, == preventSwallowing
2092* _changedOptions : { }, == preventSwallowing && preventSleep
2093* }
2094*/
2095function update(updateHints) {2096clearTimeout(_swallowedUpdateTimeout);2097updateHints = updateHints || {};2098_swallowedUpdateHints._hostSizeChanged |= updateHints._hostSizeChanged;2099_swallowedUpdateHints._contentSizeChanged |= updateHints._contentSizeChanged;2100_swallowedUpdateHints._force |= updateHints._force;2101
2102var now = COMPATIBILITY.now();2103var hostSizeChanged = !!_swallowedUpdateHints._hostSizeChanged;2104var contentSizeChanged = !!_swallowedUpdateHints._contentSizeChanged;2105var force = !!_swallowedUpdateHints._force;2106var changedOptions = updateHints._changedOptions;2107var swallow = _swallowUpdateLag > 0 && _initialized && !_destroyed && !force && !changedOptions && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache);2108var displayIsHidden;2109
2110if (swallow)2111_swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag);2112
2113//abort update due to:2114//destroyed2115//swallowing2116//sleeping2117//host is hidden or has false display2118if (_destroyed || swallow || (_sleeping && !changedOptions) || (_initialized && !force && (displayIsHidden = _hostElement.is(':hidden'))) || _hostElement.css('display') === 'inline')2119return;2120
2121_lastUpdateTime = now;2122_swallowedUpdateHints = {};2123
2124//if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely.2125if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {2126//native scrollbars are hidden, so change the values to zero2127_nativeScrollbarSize.x = 0;2128_nativeScrollbarSize.y = 0;2129}2130else {2131//refresh native scrollbar size (in case of zoom)2132_nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);2133}2134
2135// Scrollbar padding is needed for firefox, because firefox hides scrollbar automatically if the size of the div is too small.2136// The calculation: [scrollbar size +3 *3]2137// (+3 because of possible decoration e.g. borders, margins etc., but only if native scrollbar is NOT a overlaid scrollbar)2138// (*3 because (1)increase / (2)decrease -button and (3)resize handle)2139_nativeScrollbarMinSize = {2140x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3,2141y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 32142};2143
2144changedOptions = changedOptions || {};2145//freezeResizeObserver(_sizeObserverElement, true);2146//freezeResizeObserver(_sizeAutoObserverElement, true);2147
2148var checkCacheAutoForce = function () {2149return checkCache.apply(this, [].slice.call(arguments).concat([force]));2150};2151
2152//save current scroll offset2153var currScroll = {2154x: _viewportElement[_strScrollLeft](),2155y: _viewportElement[_strScrollTop]()2156};2157
2158var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars;2159var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea;2160
2161//scrollbars visibility:2162var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility;2163var scrollbarsVisibilityChanged = checkCacheAutoForce(scrollbarsVisibility, _scrollbarsVisibilityCache);2164
2165//scrollbars autoHide:2166var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide;2167var scrollbarsAutoHideChanged = checkCacheAutoForce(scrollbarsAutoHide, _scrollbarsAutoHideCache);2168
2169//scrollbars click scrolling2170var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling;2171var scrollbarsClickScrollingChanged = checkCacheAutoForce(scrollbarsClickScrolling, _scrollbarsClickScrollingCache);2172
2173//scrollbars drag scrolling2174var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling;2175var scrollbarsDragScrollingChanged = checkCacheAutoForce(scrollbarsDragScrolling, _scrollbarsDragScrollingCache);2176
2177//className2178var className = _currentPreparedOptions.className;2179var classNameChanged = checkCacheAutoForce(className, _classNameCache);2180
2181//resize2182var resize = _currentPreparedOptions.resize;2183var resizeChanged = checkCacheAutoForce(resize, _resizeCache) && !_isBody; //body can't be resized since the window itself acts as resize possibility.2184
2185//paddingAbsolute2186var paddingAbsolute = _currentPreparedOptions.paddingAbsolute;2187var paddingAbsoluteChanged = checkCacheAutoForce(paddingAbsolute, _paddingAbsoluteCache);2188
2189//clipAlways2190var clipAlways = _currentPreparedOptions.clipAlways;2191var clipAlwaysChanged = checkCacheAutoForce(clipAlways, _clipAlwaysCache);2192
2193//sizeAutoCapable2194var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport.2195var sizeAutoCapableChanged = checkCacheAutoForce(sizeAutoCapable, _sizeAutoCapableCache);2196
2197//showNativeScrollbars2198var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars;2199var ignoreOverlayScrollbarHidingChanged = checkCacheAutoForce(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache);2200
2201//autoUpdate2202var autoUpdate = _currentPreparedOptions.autoUpdate;2203var autoUpdateChanged = checkCacheAutoForce(autoUpdate, _autoUpdateCache);2204
2205//overflowBehavior2206var overflowBehavior = _currentPreparedOptions.overflowBehavior;2207var overflowBehaviorChanged = checkCacheAutoForce(overflowBehavior, _overflowBehaviorCache, force);2208
2209//dynWidth:2210var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth;2211var textareaDynWidthChanged = checkCacheAutoForce(_textareaDynWidthCache, textareaDynWidth);2212
2213//dynHeight:2214var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight;2215var textareaDynHeightChanged = checkCacheAutoForce(_textareaDynHeightCache, textareaDynHeight);2216
2217//scrollbars visibility2218_scrollbarsAutoHideNever = scrollbarsAutoHide === 'n';2219_scrollbarsAutoHideScroll = scrollbarsAutoHide === 's';2220_scrollbarsAutoHideMove = scrollbarsAutoHide === 'm';2221_scrollbarsAutoHideLeave = scrollbarsAutoHide === 'l';2222
2223//scrollbars autoHideDelay2224_scrollbarsAutoHideDelay = currentPreparedOptionsScrollbars.autoHideDelay;2225
2226//old className2227_oldClassName = _classNameCache;2228
2229//resize2230_resizeNone = resize === 'n';2231_resizeBoth = resize === 'b';2232_resizeHorizontal = resize === 'h';2233_resizeVertical = resize === 'v';2234
2235//normalizeRTL2236_normalizeRTLCache = _currentPreparedOptions.normalizeRTL;2237
2238//ignore overlay scrollbar hiding2239ignoreOverlayScrollbarHiding = ignoreOverlayScrollbarHiding && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y);2240
2241//refresh options cache2242_scrollbarsVisibilityCache = scrollbarsVisibility;2243_scrollbarsAutoHideCache = scrollbarsAutoHide;2244_scrollbarsClickScrollingCache = scrollbarsClickScrolling;2245_scrollbarsDragScrollingCache = scrollbarsDragScrolling;2246_classNameCache = className;2247_resizeCache = resize;2248_paddingAbsoluteCache = paddingAbsolute;2249_clipAlwaysCache = clipAlways;2250_sizeAutoCapableCache = sizeAutoCapable;2251_ignoreOverlayScrollbarHidingCache = ignoreOverlayScrollbarHiding;2252_autoUpdateCache = autoUpdate;2253_overflowBehaviorCache = extendDeep({}, overflowBehavior);2254_textareaDynWidthCache = textareaDynWidth;2255_textareaDynHeightCache = textareaDynHeight;2256_hasOverflowCache = _hasOverflowCache || { x: false, y: false };2257
2258//set correct class name to the host element2259if (classNameChanged) {2260removeClass(_hostElement, _oldClassName + _strSpace + _classNameThemeNone);2261addClass(_hostElement, className !== undefined && className !== null && className.length > 0 ? className : _classNameThemeNone);2262}2263
2264//set correct auto Update2265if (autoUpdateChanged) {2266if (autoUpdate === true || (autoUpdate === null && _autoUpdateRecommended)) {2267disconnectMutationObservers();2268autoUpdateLoop.add(_base);2269}2270else {2271autoUpdateLoop.remove(_base);2272connectMutationObservers();2273}2274}2275
2276//activate or deactivate size auto capability2277if (sizeAutoCapableChanged) {2278if (sizeAutoCapable) {2279if (_contentGlueElement) {2280_contentGlueElement.show();2281}2282else {2283_contentGlueElement = FRAMEWORK(generateDiv(_classNameContentGlueElement));2284_paddingElement.before(_contentGlueElement);2285}2286if (_sizeAutoObserverAdded) {2287_sizeAutoObserverElement.show();2288}2289else {2290_sizeAutoObserverElement = FRAMEWORK(generateDiv(_classNameSizeAutoObserverElement));2291_sizeAutoObserverElementNative = _sizeAutoObserverElement[0];2292
2293_contentGlueElement.before(_sizeAutoObserverElement);2294var oldSize = { w: -1, h: -1 };2295setupResizeObserver(_sizeAutoObserverElement, function () {2296var newSize = {2297w: _sizeAutoObserverElementNative[LEXICON.oW],2298h: _sizeAutoObserverElementNative[LEXICON.oH]2299};2300if (checkCache(newSize, oldSize)) {2301if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) {2302update();2303}2304else if (_initialized && (!_heightAutoCache && newSize.h === 0) || (!_widthAutoCache && newSize.w === 0)) {2305update();2306}2307}2308oldSize = newSize;2309});2310_sizeAutoObserverAdded = true;2311//fix heightAuto detector bug if height is fixed but contentHeight is 0.2312//the probability this bug will ever happen is very very low, thats why its ok if we use calc which isn't supported in IE8.2313if (_cssCalc !== null)2314_sizeAutoObserverElement.css(_strHeight, _cssCalc + '(100% + 1px)');2315}2316}2317else {2318if (_sizeAutoObserverAdded)2319_sizeAutoObserverElement.hide();2320if (_contentGlueElement)2321_contentGlueElement.hide();2322}2323}2324
2325//if force, update all resizeObservers too2326if (force) {2327_sizeObserverElement.find('*').trigger(_strScroll);2328if (_sizeAutoObserverAdded)2329_sizeAutoObserverElement.find('*').trigger(_strScroll);2330}2331
2332//display hidden:2333displayIsHidden = displayIsHidden === undefined ? _hostElement.is(':hidden') : displayIsHidden;2334
2335//textarea AutoWrapping:2336var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false;2337var textareaAutoWrappingChanged = checkCacheAutoForce(textareaAutoWrapping, _textareaAutoWrappingCache);2338
2339//detect direction:2340var cssDirection = _hostElement.css('direction');2341var cssDirectionChanged = checkCacheAutoForce(cssDirection, _cssDirectionCache);2342
2343//detect box-sizing:2344var boxSizing = _hostElement.css('box-sizing');2345var boxSizingChanged = checkCacheAutoForce(boxSizing, _cssBoxSizingCache);2346
2347//detect padding:2348var padding = getTopRightBottomLeftHost(_strPaddingMinus);2349
2350//width + height auto detecting var:2351var sizeAutoObserverElementBCRect;2352//exception occurs in IE8 sometimes (unknown exception)2353try {2354sizeAutoObserverElementBCRect = _sizeAutoObserverAdded ? _sizeAutoObserverElementNative[LEXICON.bCR]() : null;2355} catch (ex) {2356return;2357}2358
2359_isRTL = cssDirection === 'rtl';2360_isBorderBox = (boxSizing === 'border-box');2361var isRTLLeft = _isRTL ? _strLeft : _strRight;2362var isRTLRight = _isRTL ? _strRight : _strLeft;2363
2364//detect width auto:2365var widthAutoResizeDetection = false;2366var widthAutoObserverDetection = (_sizeAutoObserverAdded && (_hostElement.css(_strFloat) !== 'none' /*|| _isTextarea */)) ? (MATH.round(sizeAutoObserverElementBCRect.right - sizeAutoObserverElementBCRect.left) === 0) && (!paddingAbsolute ? (_hostElementNative[LEXICON.cW] - _paddingX) > 0 : true) : false;2367if (sizeAutoCapable && !widthAutoObserverDetection) {2368var tmpCurrHostWidth = _hostElementNative[LEXICON.oW];2369var tmpCurrContentGlueWidth = _contentGlueElement.css(_strWidth);2370_contentGlueElement.css(_strWidth, _strAuto);2371
2372var tmpNewHostWidth = _hostElementNative[LEXICON.oW];2373_contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);2374widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;2375if (!widthAutoResizeDetection) {2376_contentGlueElement.css(_strWidth, tmpCurrHostWidth + 1);2377tmpNewHostWidth = _hostElementNative[LEXICON.oW];2378_contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);2379widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;2380}2381}2382var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden;2383var widthAutoChanged = checkCacheAutoForce(widthAuto, _widthAutoCache);2384var wasWidthAuto = !widthAuto && _widthAutoCache;2385
2386//detect height auto:2387var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false;2388var heightAutoChanged = checkCacheAutoForce(heightAuto, _heightAutoCache);2389var wasHeightAuto = !heightAuto && _heightAutoCache;2390
2391//detect border:2392//we need the border only if border box and auto size2393var updateBorderX = (widthAuto && _isBorderBox) || !_isBorderBox;2394var updateBorderY = (heightAuto && _isBorderBox) || !_isBorderBox;2395var border = getTopRightBottomLeftHost(_strBorderMinus, '-' + _strWidth, !updateBorderX, !updateBorderY)2396
2397//detect margin:2398var margin = getTopRightBottomLeftHost(_strMarginMinus);2399
2400//vars to apply correct css2401var contentElementCSS = {};2402var contentGlueElementCSS = {};2403
2404//funcs2405var getHostSize = function () {2406//has to be clientSize because offsetSize respect borders2407return {2408w: _hostElementNative[LEXICON.cW],2409h: _hostElementNative[LEXICON.cH]2410};2411};2412var getViewportSize = function () {2413//viewport size is padding container because it never has padding, margin and a border2414//determine zoom rounding error -> sometimes scrollWidth/Height is smaller than clientWidth/Height2415//if this happens add the difference to the viewportSize to compensate the rounding error2416return {2417w: _paddingElementNative[LEXICON.oW] + MATH.max(0, _contentElementNative[LEXICON.cW] - _contentElementNative[LEXICON.sW]),2418h: _paddingElementNative[LEXICON.oH] + MATH.max(0, _contentElementNative[LEXICON.cH] - _contentElementNative[LEXICON.sH])2419};2420};2421
2422//set info for padding2423var paddingAbsoluteX = _paddingX = padding.l + padding.r;2424var paddingAbsoluteY = _paddingY = padding.t + padding.b;2425paddingAbsoluteX *= paddingAbsolute ? 1 : 0;2426paddingAbsoluteY *= paddingAbsolute ? 1 : 0;2427padding.c = checkCacheAutoForce(padding, _cssPaddingCache);2428
2429//set info for border2430_borderX = border.l + border.r;2431_borderY = border.t + border.b;2432border.c = checkCacheAutoForce(border, _cssBorderCache);2433
2434//set info for margin2435_marginX = margin.l + margin.r;2436_marginY = margin.t + margin.b;2437margin.c = checkCacheAutoForce(margin, _cssMarginCache);2438
2439//refresh cache2440_textareaAutoWrappingCache = textareaAutoWrapping;2441_cssDirectionCache = cssDirection;2442_cssBoxSizingCache = boxSizing;2443_widthAutoCache = widthAuto;2444_heightAutoCache = heightAuto;2445_cssPaddingCache = padding;2446_cssBorderCache = border;2447_cssMarginCache = margin;2448
2449//IEFix direction changed2450if (cssDirectionChanged && _sizeAutoObserverAdded)2451_sizeAutoObserverElement.css(_strFloat, isRTLRight);2452
2453//apply padding:2454if (padding.c || cssDirectionChanged || paddingAbsoluteChanged || widthAutoChanged || heightAutoChanged || boxSizingChanged || sizeAutoCapableChanged) {2455var paddingElementCSS = {};2456var textareaCSS = {};2457var paddingValues = [padding.t, padding.r, padding.b, padding.l];2458
2459setTopRightBottomLeft(contentGlueElementCSS, _strMarginMinus, [-padding.t, -padding.r, -padding.b, -padding.l]);2460if (paddingAbsolute) {2461setTopRightBottomLeft(paddingElementCSS, _strEmpty, paddingValues);2462setTopRightBottomLeft(_isTextarea ? textareaCSS : contentElementCSS, _strPaddingMinus);2463}2464else {2465setTopRightBottomLeft(paddingElementCSS, _strEmpty);2466setTopRightBottomLeft(_isTextarea ? textareaCSS : contentElementCSS, _strPaddingMinus, paddingValues);2467}2468
2469_paddingElement.css(paddingElementCSS);2470_targetElement.css(textareaCSS);2471}2472
2473//viewport size is padding container because it never has padding, margin and a border.2474_viewportSize = getViewportSize();2475
2476//update Textarea2477var textareaSize = _isTextarea ? textareaUpdate() : false;2478var textareaSizeChanged = _isTextarea && checkCacheAutoForce(textareaSize, _textareaSizeCache);2479var textareaDynOrigSize = _isTextarea && textareaSize ? {2480w: textareaDynWidth ? textareaSize._dynamicWidth : textareaSize._originalWidth,2481h: textareaDynHeight ? textareaSize._dynamicHeight : textareaSize._originalHeight2482} : {};2483_textareaSizeCache = textareaSize;2484
2485//fix height auto / width auto in cooperation with current padding & boxSizing behavior:2486if (heightAuto && (heightAutoChanged || paddingAbsoluteChanged || boxSizingChanged || padding.c || border.c)) {2487contentElementCSS[_strHeight] = _strAuto;2488}2489else if (heightAutoChanged || paddingAbsoluteChanged) {2490contentElementCSS[_strHeight] = _strHundredPercent;2491}2492if (widthAuto && (widthAutoChanged || paddingAbsoluteChanged || boxSizingChanged || padding.c || border.c || cssDirectionChanged)) {2493contentElementCSS[_strWidth] = _strAuto;2494contentGlueElementCSS[_strMaxMinus + _strWidth] = _strHundredPercent; //IE Fix2495}2496else if (widthAutoChanged || paddingAbsoluteChanged) {2497contentElementCSS[_strWidth] = _strHundredPercent;2498contentElementCSS[_strFloat] = _strEmpty;2499contentGlueElementCSS[_strMaxMinus + _strWidth] = _strEmpty; //IE Fix2500}2501if (widthAuto) {2502//textareaDynOrigSize.w || _strAuto :: doesnt works because applied margin will shift width2503contentGlueElementCSS[_strWidth] = _strAuto;2504
2505contentElementCSS[_strWidth] = VENDORS._cssPropertyValue(_strWidth, 'max-content intrinsic') || _strAuto;2506contentElementCSS[_strFloat] = isRTLRight;2507}2508else {2509contentGlueElementCSS[_strWidth] = _strEmpty;2510}2511if (heightAuto) {2512//textareaDynOrigSize.h || _contentElementNative[LEXICON.cH] :: use for anti scroll jumping2513contentGlueElementCSS[_strHeight] = textareaDynOrigSize.h || _contentElementNative[LEXICON.cH];2514}2515else {2516contentGlueElementCSS[_strHeight] = _strEmpty;2517}2518if (sizeAutoCapable)2519_contentGlueElement.css(contentGlueElementCSS);2520_contentElement.css(contentElementCSS);2521
2522//CHECKPOINT HERE ~2523contentElementCSS = {};2524contentGlueElementCSS = {};2525
2526//if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true2527if (hostSizeChanged || contentSizeChanged || textareaSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged) {2528var strOverflow = 'overflow';2529var strOverflowX = strOverflow + '-x';2530var strOverflowY = strOverflow + '-y';2531var strHidden = 'hidden';2532var strVisible = 'visible';2533
2534//Reset the viewport (very important for natively overlaid scrollbars and zoom change2535//don't change the overflow prop as it is very expensive and affects performance !A LOT!2536if (!_nativeScrollbarStyling) {2537var viewportElementResetCSS = {};2538var resetXTmp = _hasOverflowCache.y && _hideOverflowCache.ys && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.y ? _viewportElement.css(isRTLLeft) : -_nativeScrollbarSize.y) : 0;2539var resetBottomTmp = _hasOverflowCache.x && _hideOverflowCache.xs && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.x ? _viewportElement.css(_strBottom) : -_nativeScrollbarSize.x) : 0;2540setTopRightBottomLeft(viewportElementResetCSS, _strEmpty);2541_viewportElement.css(viewportElementResetCSS);2542}2543
2544//measure several sizes:2545var contentMeasureElement = getContentMeasureElement();2546//in Firefox content element has to have overflow hidden, else element margins aren't calculated properly, this element prevents this bug, but only if scrollbars aren't overlaid2547var contentSize = {2548//use clientSize because natively overlaidScrollbars add borders2549w: textareaDynOrigSize.w || contentMeasureElement[LEXICON.cW],2550h: textareaDynOrigSize.h || contentMeasureElement[LEXICON.cH]2551};2552var scrollSize = {2553w: contentMeasureElement[LEXICON.sW],2554h: contentMeasureElement[LEXICON.sH]2555};2556
2557//apply the correct viewport style and measure viewport size2558if (!_nativeScrollbarStyling) {2559viewportElementResetCSS[_strBottom] = wasHeightAuto ? _strEmpty : resetBottomTmp;2560viewportElementResetCSS[isRTLLeft] = wasWidthAuto ? _strEmpty : resetXTmp;2561_viewportElement.css(viewportElementResetCSS);2562}2563_viewportSize = getViewportSize();2564
2565//measure and correct several sizes2566var hostSize = getHostSize();2567var hostAbsoluteRectSize = {2568w: hostSize.w - _marginX - _borderX - (_isBorderBox ? 0 : _paddingX),2569h: hostSize.h - _marginY - _borderY - (_isBorderBox ? 0 : _paddingY)2570};2571var contentGlueSize = {2572//client/scrollSize + AbsolutePadding -> because padding is only applied to the paddingElement if its absolute, so you have to add it manually2573//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 padding2574w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostAbsoluteRectSize.w),2575h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostAbsoluteRectSize.h)2576};2577contentGlueSize.c = checkCacheAutoForce(contentGlueSize, _contentGlueSizeCache);2578_contentGlueSizeCache = contentGlueSize;2579
2580//apply correct contentGlue size2581if (sizeAutoCapable) {2582//size contentGlue correctly to make sure the element has correct size if the sizing switches to auto2583if (contentGlueSize.c || (heightAuto || widthAuto)) {2584contentGlueElementCSS[_strWidth] = contentGlueSize.w;2585contentGlueElementCSS[_strHeight] = contentGlueSize.h;2586
2587//textarea-sizes are already calculated correctly at this point2588if (!_isTextarea) {2589contentSize = {2590//use clientSize because natively overlaidScrollbars add borders2591w: contentMeasureElement[LEXICON.cW],2592h: contentMeasureElement[LEXICON.cH]2593};2594}2595}2596var textareaCoverCSS = {};2597var setContentGlueElementCSSfunction = function (horizontal) {2598var scrollbarVars = getScrollbarVars(horizontal);2599var wh = scrollbarVars._w_h;2600var strWH = scrollbarVars._width_height;2601var autoSize = horizontal ? widthAuto : heightAuto;2602var borderSize = horizontal ? _borderX : _borderY;2603var paddingSize = horizontal ? _paddingX : _paddingY;2604var marginSize = horizontal ? _marginX : _marginY;2605var viewportSize = _viewportSize[wh] - borderSize - marginSize - (_isBorderBox ? 0 : paddingSize);2606
2607//make contentGlue size -1 if element is not auto sized, to make sure that a resize event happens when the element shrinks2608if (!autoSize || (!autoSize && border.c))2609contentGlueElementCSS[strWH] = hostAbsoluteRectSize[wh] - 1;2610
2611//if size is auto and host is smaller than size as min size, make content glue size -1 to make sure size changes will be detected (this is only needed if padding is 0)2612if (autoSize && (contentSize[wh] < viewportSize) && (horizontal && _isTextarea ? !textareaAutoWrapping : true)) {2613if (_isTextarea)2614textareaCoverCSS[strWH] = parseToZeroOrNumber(_textareaCoverElement.css(strWH)) - 1;2615contentGlueElementCSS[strWH] -= 1;2616}2617
2618//make sure content glue size is at least 12619if (contentSize[wh] > 0)2620contentGlueElementCSS[strWH] = MATH.max(1, contentGlueElementCSS[strWH]);2621};2622setContentGlueElementCSSfunction(true);2623setContentGlueElementCSSfunction(false);2624
2625if (_isTextarea)2626_textareaCoverElement.css(textareaCoverCSS);2627_contentGlueElement.css(contentGlueElementCSS);2628}2629if (widthAuto)2630contentElementCSS[_strWidth] = _strHundredPercent;2631if (widthAuto && !_isBorderBox && !_mutationObserversConnected)2632contentElementCSS[_strFloat] = 'none';2633
2634//apply and reset content style2635_contentElement.css(contentElementCSS);2636contentElementCSS = {};2637
2638//measure again, but this time all correct sizes:2639var contentScrollSize = {2640w: contentMeasureElement[LEXICON.sW],2641h: contentMeasureElement[LEXICON.sH],2642};2643contentScrollSize.c = contentSizeChanged = checkCacheAutoForce(contentScrollSize, _contentScrollSizeCache);2644_contentScrollSizeCache = contentScrollSize;2645
2646//refresh viewport size after correct measuring2647_viewportSize = getViewportSize();2648
2649hostSize = getHostSize();2650hostSizeChanged = checkCacheAutoForce(hostSize, _hostSizeCache);2651_hostSizeCache = hostSize;2652
2653var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0);2654var previousOverflowAmount = _overflowAmountCache;2655var overflowBehaviorIsVS = {};2656var overflowBehaviorIsVH = {};2657var overflowBehaviorIsS = {};2658var overflowAmount = {};2659var hasOverflow = {};2660var hideOverflow = {};2661var canScroll = {};2662var viewportRect = _paddingElementNative[LEXICON.bCR]();2663var setOverflowVariables = function (horizontal) {2664var scrollbarVars = getScrollbarVars(horizontal);2665var scrollbarVarsInverted = getScrollbarVars(!horizontal);2666var xyI = scrollbarVarsInverted._x_y;2667var xy = scrollbarVars._x_y;2668var wh = scrollbarVars._w_h;2669var widthHeight = scrollbarVars._width_height;2670var scrollMax = _strScroll + scrollbarVars._Left_Top + 'Max';2671var fractionalOverflowAmount = viewportRect[widthHeight] ? MATH.abs(viewportRect[widthHeight] - _viewportSize[wh]) : 0;2672var checkFractionalOverflowAmount = previousOverflowAmount && previousOverflowAmount[xy] > 0 && _viewportElementNative[scrollMax] === 0;2673overflowBehaviorIsVS[xy] = overflowBehavior[xy] === 'v-s';2674overflowBehaviorIsVH[xy] = overflowBehavior[xy] === 'v-h';2675overflowBehaviorIsS[xy] = overflowBehavior[xy] === 's';2676overflowAmount[xy] = MATH.max(0, MATH.round((contentScrollSize[wh] - _viewportSize[wh]) * 100) / 100);2677overflowAmount[xy] *= (hideOverflowForceTextarea || (checkFractionalOverflowAmount && fractionalOverflowAmount > 0 && fractionalOverflowAmount < 1)) ? 0 : 1;2678hasOverflow[xy] = overflowAmount[xy] > 0;2679
2680//hideOverflow:2681//x || y : true === overflow is hidden by "overflow: scroll" OR "overflow: hidden"2682//xs || ys : true === overflow is hidden by "overflow: scroll"2683hideOverflow[xy] = overflowBehaviorIsVS[xy] || overflowBehaviorIsVH[xy] ? (hasOverflow[xyI] && !overflowBehaviorIsVS[xyI] && !overflowBehaviorIsVH[xyI]) : hasOverflow[xy];2684hideOverflow[xy + 's'] = hideOverflow[xy] ? (overflowBehaviorIsS[xy] || overflowBehaviorIsVS[xy]) : false;2685
2686canScroll[xy] = hasOverflow[xy] && hideOverflow[xy + 's'];2687};2688setOverflowVariables(true);2689setOverflowVariables(false);2690
2691overflowAmount.c = checkCacheAutoForce(overflowAmount, _overflowAmountCache);2692_overflowAmountCache = overflowAmount;2693hasOverflow.c = checkCacheAutoForce(hasOverflow, _hasOverflowCache);2694_hasOverflowCache = hasOverflow;2695hideOverflow.c = checkCacheAutoForce(hideOverflow, _hideOverflowCache);2696_hideOverflowCache = hideOverflow;2697
2698//if native scrollbar is overlay at x OR y axis, prepare DOM2699if (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) {2700var borderDesign = 'px solid transparent';2701var contentArrangeElementCSS = {};2702var arrangeContent = {};2703var arrangeChanged = force;2704var setContentElementCSS;2705
2706if (hasOverflow.x || hasOverflow.y) {2707arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty;2708arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty;2709arrangeChanged = checkCacheAutoForce(arrangeContent, _arrangeContentSizeCache);2710_arrangeContentSizeCache = arrangeContent;2711}2712
2713if (hasOverflow.c || hideOverflow.c || contentScrollSize.c || cssDirectionChanged || widthAutoChanged || heightAutoChanged || widthAuto || heightAuto || ignoreOverlayScrollbarHidingChanged) {2714contentElementCSS[_strMarginMinus + isRTLRight] = contentElementCSS[_strBorderMinus + isRTLRight] = _strEmpty;2715setContentElementCSS = function (horizontal) {2716var scrollbarVars = getScrollbarVars(horizontal);2717var scrollbarVarsInverted = getScrollbarVars(!horizontal);2718var xy = scrollbarVars._x_y;2719var strDirection = horizontal ? _strBottom : isRTLLeft;2720var invertedAutoSize = horizontal ? heightAuto : widthAuto;2721
2722if (_nativeScrollbarIsOverlaid[xy] && hasOverflow[xy] && hideOverflow[xy + 's']) {2723contentElementCSS[_strMarginMinus + strDirection] = invertedAutoSize ? (ignoreOverlayScrollbarHiding ? _strEmpty : _overlayScrollbarDummySize[xy]) : _strEmpty;2724contentElementCSS[_strBorderMinus + strDirection] = ((horizontal ? !invertedAutoSize : true) && !ignoreOverlayScrollbarHiding) ? (_overlayScrollbarDummySize[xy] + borderDesign) : _strEmpty;2725}2726else {2727arrangeContent[scrollbarVarsInverted._w_h] =2728contentElementCSS[_strMarginMinus + strDirection] =2729contentElementCSS[_strBorderMinus + strDirection] = _strEmpty;2730arrangeChanged = true;2731}2732};2733
2734if (_nativeScrollbarStyling) {2735addRemoveClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible, !ignoreOverlayScrollbarHiding)2736}2737else {2738setContentElementCSS(true);2739setContentElementCSS(false);2740}2741}2742if (ignoreOverlayScrollbarHiding) {2743arrangeContent.w = arrangeContent.h = _strEmpty;2744arrangeChanged = true;2745}2746if (arrangeChanged && !_nativeScrollbarStyling) {2747contentArrangeElementCSS[_strWidth] = hideOverflow.y ? arrangeContent.w : _strEmpty;2748contentArrangeElementCSS[_strHeight] = hideOverflow.x ? arrangeContent.h : _strEmpty;2749
2750if (!_contentArrangeElement) {2751_contentArrangeElement = FRAMEWORK(generateDiv(_classNameContentArrangeElement));2752_viewportElement.prepend(_contentArrangeElement);2753}2754_contentArrangeElement.css(contentArrangeElementCSS);2755}2756_contentElement.css(contentElementCSS);2757}2758
2759var viewportElementCSS = {};2760var paddingElementCSS = {};2761var setViewportCSS;2762if (hostSizeChanged || hasOverflow.c || hideOverflow.c || contentScrollSize.c || overflowBehaviorChanged || boxSizingChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged || clipAlwaysChanged || heightAutoChanged) {2763viewportElementCSS[isRTLRight] = _strEmpty;2764setViewportCSS = function (horizontal) {2765var scrollbarVars = getScrollbarVars(horizontal);2766var scrollbarVarsInverted = getScrollbarVars(!horizontal);2767var xy = scrollbarVars._x_y;2768var XY = scrollbarVars._X_Y;2769var strDirection = horizontal ? _strBottom : isRTLLeft;2770
2771var reset = function () {2772viewportElementCSS[strDirection] = _strEmpty;2773_contentBorderSize[scrollbarVarsInverted._w_h] = 0;2774};2775if (hasOverflow[xy] && hideOverflow[xy + 's']) {2776viewportElementCSS[strOverflow + XY] = _strScroll;2777if (ignoreOverlayScrollbarHiding || _nativeScrollbarStyling) {2778reset();2779}2780else {2781viewportElementCSS[strDirection] = -(_nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[xy] : _nativeScrollbarSize[xy]);2782_contentBorderSize[scrollbarVarsInverted._w_h] = _nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[scrollbarVarsInverted._x_y] : 0;2783}2784} else {2785viewportElementCSS[strOverflow + XY] = _strEmpty;2786reset();2787}2788};2789setViewportCSS(true);2790setViewportCSS(false);2791
2792// if the scroll container is too small and if there is any overflow with no overlay scrollbar (and scrollbar styling isn't possible),2793// make viewport element greater in size (Firefox hide Scrollbars fix)2794// because firefox starts hiding scrollbars on too small elements2795// with this behavior the overflow calculation may be incorrect or the scrollbars would appear suddenly2796// https://bugzilla.mozilla.org/show_bug.cgi?id=2922842797if (!_nativeScrollbarStyling2798&& (_viewportSize.h < _nativeScrollbarMinSize.x || _viewportSize.w < _nativeScrollbarMinSize.y)2799&& ((hasOverflow.x && hideOverflow.x && !_nativeScrollbarIsOverlaid.x) || (hasOverflow.y && hideOverflow.y && !_nativeScrollbarIsOverlaid.y))) {2800viewportElementCSS[_strPaddingMinus + _strTop] = _nativeScrollbarMinSize.x;2801viewportElementCSS[_strMarginMinus + _strTop] = -_nativeScrollbarMinSize.x;2802
2803viewportElementCSS[_strPaddingMinus + isRTLRight] = _nativeScrollbarMinSize.y;2804viewportElementCSS[_strMarginMinus + isRTLRight] = -_nativeScrollbarMinSize.y;2805}2806else {2807viewportElementCSS[_strPaddingMinus + _strTop] =2808viewportElementCSS[_strMarginMinus + _strTop] =2809viewportElementCSS[_strPaddingMinus + isRTLRight] =2810viewportElementCSS[_strMarginMinus + isRTLRight] = _strEmpty;2811}2812viewportElementCSS[_strPaddingMinus + isRTLLeft] =2813viewportElementCSS[_strMarginMinus + isRTLLeft] = _strEmpty;2814
2815//if there is any overflow (x OR y axis) and this overflow shall be hidden, make overflow hidden, else overflow visible2816if ((hasOverflow.x && hideOverflow.x) || (hasOverflow.y && hideOverflow.y) || hideOverflowForceTextarea) {2817//only hide if is Textarea2818if (_isTextarea && hideOverflowForceTextarea) {2819paddingElementCSS[strOverflowX] =2820paddingElementCSS[strOverflowY] = strHidden;2821}2822}2823else {2824if (!clipAlways || (overflowBehaviorIsVH.x || overflowBehaviorIsVS.x || overflowBehaviorIsVH.y || overflowBehaviorIsVS.y)) {2825//only un-hide if Textarea2826if (_isTextarea) {2827paddingElementCSS[strOverflowX] =2828paddingElementCSS[strOverflowY] = _strEmpty;2829}2830viewportElementCSS[strOverflowX] =2831viewportElementCSS[strOverflowY] = strVisible;2832}2833}2834
2835_paddingElement.css(paddingElementCSS);2836_viewportElement.css(viewportElementCSS);2837viewportElementCSS = {};2838
2839//force soft redraw in webkit because without the scrollbars will may appear because DOM wont be redrawn under special conditions2840if ((hasOverflow.c || boxSizingChanged || widthAutoChanged || heightAutoChanged) && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {2841var elementStyle = _contentElementNative[LEXICON.s];2842var dump;2843elementStyle.webkitTransform = 'scale(1)';2844elementStyle.display = 'run-in';2845dump = _contentElementNative[LEXICON.oH];2846elementStyle.display = _strEmpty; //|| dump; //use dump to prevent it from deletion if minify2847elementStyle.webkitTransform = _strEmpty;2848}2849/*2850//force hard redraw in webkit if native overlaid scrollbars shall appear
2851if (ignoreOverlayScrollbarHidingChanged && ignoreOverlayScrollbarHiding) {
2852_hostElement.hide();
2853var dump = _hostElementNative[LEXICON.oH];
2854_hostElement.show();
2855}
2856*/
2857}2858
2859//change to direction RTL and width auto Bugfix in Webkit2860//without this fix, the DOM still thinks the scrollbar is LTR and thus the content is shifted to the left2861contentElementCSS = {};2862if (cssDirectionChanged || widthAutoChanged || heightAutoChanged) {2863if (_isRTL && widthAuto) {2864var floatTmp = _contentElement.css(_strFloat);2865var posLeftWithoutFloat = MATH.round(_contentElement.css(_strFloat, _strEmpty).css(_strLeft, _strEmpty).position().left);2866_contentElement.css(_strFloat, floatTmp);2867var posLeftWithFloat = MATH.round(_contentElement.position().left);2868
2869if (posLeftWithoutFloat !== posLeftWithFloat)2870contentElementCSS[_strLeft] = posLeftWithoutFloat;2871}2872else {2873contentElementCSS[_strLeft] = _strEmpty;2874}2875}2876_contentElement.css(contentElementCSS);2877
2878//handle scroll position2879if (_isTextarea && contentSizeChanged) {2880var textareaInfo = getTextareaInfo();2881if (textareaInfo) {2882var textareaRowsChanged = _textareaInfoCache === undefined ? true : textareaInfo._rows !== _textareaInfoCache._rows;2883var cursorRow = textareaInfo._cursorRow;2884var cursorCol = textareaInfo._cursorColumn;2885var widestRow = textareaInfo._widestRow;2886var lastRow = textareaInfo._rows;2887var lastCol = textareaInfo._columns;2888var cursorPos = textareaInfo._cursorPosition;2889var cursorMax = textareaInfo._cursorMax;2890var cursorIsLastPosition = (cursorPos >= cursorMax && _textareaHasFocus);2891var textareaScrollAmount = {2892x: (!textareaAutoWrapping && (cursorCol === lastCol && cursorRow === widestRow)) ? _overflowAmountCache.x : -1,2893y: (textareaAutoWrapping ? cursorIsLastPosition || textareaRowsChanged && (previousOverflowAmount ? (currScroll.y === previousOverflowAmount.y) : false) : (cursorIsLastPosition || textareaRowsChanged) && cursorRow === lastRow) ? _overflowAmountCache.y : -12894};2895currScroll.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.2896currScroll.y = textareaScrollAmount.y > -1 ? textareaScrollAmount.y : currScroll.y;2897}2898_textareaInfoCache = textareaInfo;2899}2900if (_isRTL && _rtlScrollBehavior.i && _nativeScrollbarIsOverlaid.y && hasOverflow.x && _normalizeRTLCache)2901currScroll.x += _contentBorderSize.w || 0;2902if (widthAuto)2903_hostElement[_strScrollLeft](0);2904if (heightAuto)2905_hostElement[_strScrollTop](0);2906_viewportElement[_strScrollLeft](currScroll.x)[_strScrollTop](currScroll.y);2907
2908//scrollbars management:2909var scrollbarsVisibilityVisible = scrollbarsVisibility === 'v';2910var scrollbarsVisibilityHidden = scrollbarsVisibility === 'h';2911var scrollbarsVisibilityAuto = scrollbarsVisibility === 'a';2912var refreshScrollbarsVisibility = function (showX, showY) {2913showY = showY === undefined ? showX : showY;2914refreshScrollbarAppearance(true, showX, canScroll.x)2915refreshScrollbarAppearance(false, showY, canScroll.y)2916};2917
2918//manage class name which indicates scrollable overflow2919addRemoveClass(_hostElement, _classNameHostOverflow, hideOverflow.x || hideOverflow.y);2920addRemoveClass(_hostElement, _classNameHostOverflowX, hideOverflow.x);2921addRemoveClass(_hostElement, _classNameHostOverflowY, hideOverflow.y);2922
2923//add or remove rtl class name for styling purposes except when its body, then the scrollbar stays2924if (cssDirectionChanged && !_isBody) {2925addRemoveClass(_hostElement, _classNameHostRTL, _isRTL);2926}2927
2928//manage the resize feature (CSS3 resize "polyfill" for this plugin)2929if (_isBody)2930addClass(_hostElement, _classNameHostResizeDisabled);2931if (resizeChanged) {2932addRemoveClass(_hostElement, _classNameHostResizeDisabled, _resizeNone);2933addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResize, !_resizeNone);2934addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeB, _resizeBoth);2935addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeH, _resizeHorizontal);2936addRemoveClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV, _resizeVertical);2937}2938
2939//manage the scrollbars general visibility + the scrollbar interactivity (unusable class name)2940if (scrollbarsVisibilityChanged || overflowBehaviorChanged || hideOverflow.c || hasOverflow.c || ignoreOverlayScrollbarHidingChanged) {2941if (ignoreOverlayScrollbarHiding) {2942if (ignoreOverlayScrollbarHidingChanged) {2943removeClass(_hostElement, _classNameHostScrolling);2944if (ignoreOverlayScrollbarHiding) {2945refreshScrollbarsVisibility(false);2946}2947}2948}2949else if (scrollbarsVisibilityAuto) {2950refreshScrollbarsVisibility(canScroll.x, canScroll.y);2951}2952else if (scrollbarsVisibilityVisible) {2953refreshScrollbarsVisibility(true);2954}2955else if (scrollbarsVisibilityHidden) {2956refreshScrollbarsVisibility(false);2957}2958}2959
2960//manage the scrollbars auto hide feature (auto hide them after specific actions)2961if (scrollbarsAutoHideChanged || ignoreOverlayScrollbarHidingChanged) {2962setupHostMouseTouchEvents(!_scrollbarsAutoHideLeave && !_scrollbarsAutoHideMove);2963refreshScrollbarsAutoHide(_scrollbarsAutoHideNever, !_scrollbarsAutoHideNever);2964}2965
2966//manage scrollbars handle length & offset - don't remove!2967if (hostSizeChanged || overflowAmount.c || heightAutoChanged || widthAutoChanged || resizeChanged || boxSizingChanged || paddingAbsoluteChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged) {2968refreshScrollbarHandleLength(true);2969refreshScrollbarHandleOffset(true);2970refreshScrollbarHandleLength(false);2971refreshScrollbarHandleOffset(false);2972}2973
2974//manage interactivity2975if (scrollbarsClickScrollingChanged)2976refreshScrollbarsInteractive(true, scrollbarsClickScrolling);2977if (scrollbarsDragScrollingChanged)2978refreshScrollbarsInteractive(false, scrollbarsDragScrolling);2979
2980//callbacks:2981dispatchCallback('onDirectionChanged', {2982isRTL: _isRTL,2983dir: cssDirection2984}, cssDirectionChanged);2985dispatchCallback('onHostSizeChanged', {2986width: _hostSizeCache.w,2987height: _hostSizeCache.h2988}, hostSizeChanged);2989dispatchCallback('onContentSizeChanged', {2990width: _contentScrollSizeCache.w,2991height: _contentScrollSizeCache.h2992}, contentSizeChanged);2993dispatchCallback('onOverflowChanged', {2994x: hasOverflow.x,2995y: hasOverflow.y,2996xScrollable: hideOverflow.xs,2997yScrollable: hideOverflow.ys,2998clipped: hideOverflow.x || hideOverflow.y2999}, hasOverflow.c || hideOverflow.c);3000dispatchCallback('onOverflowAmountChanged', {3001x: overflowAmount.x,3002y: overflowAmount.y3003}, overflowAmount.c);3004}3005
3006//fix body min size3007if (_isBody && _bodyMinSizeCache && (_hasOverflowCache.c || _bodyMinSizeCache.c)) {3008//its possible that no min size was measured until now, because the content arrange element was just added now, in this case, measure now the min size.3009if (!_bodyMinSizeCache.f)3010bodyMinSizeChanged();3011if (_nativeScrollbarIsOverlaid.y && _hasOverflowCache.x)3012_contentElement.css(_strMinMinus + _strWidth, _bodyMinSizeCache.w + _overlayScrollbarDummySize.y);3013if (_nativeScrollbarIsOverlaid.x && _hasOverflowCache.y)3014_contentElement.css(_strMinMinus + _strHeight, _bodyMinSizeCache.h + _overlayScrollbarDummySize.x);3015_bodyMinSizeCache.c = false;3016}3017
3018if (_initialized && changedOptions.updateOnLoad) {3019updateElementsOnLoad();3020}3021
3022//freezeResizeObserver(_sizeObserverElement, false);3023//freezeResizeObserver(_sizeAutoObserverElement, false);3024
3025dispatchCallback('onUpdated', { forced: force });3026}3027
3028/**3029* Updates the found elements of which the load event shall be handled.
3030*/
3031function updateElementsOnLoad() {3032if (!_isTextarea) {3033eachUpdateOnLoad(function (i, updateOnLoadSelector) {3034_contentElement.find(updateOnLoadSelector).each(function (i, el) {3035// if element doesn't have a updateOnLoadCallback applied3036if (COMPATIBILITY.inA(el, _updateOnLoadElms) < 0) {3037_updateOnLoadElms.push(el);3038FRAMEWORK(el)3039.off(_updateOnLoadEventName, updateOnLoadCallback)3040.on(_updateOnLoadEventName, updateOnLoadCallback);3041}3042});3043});3044}3045}3046
3047//==== Options ====//3048
3049/**3050* Sets new options but doesn't call the update method.
3051* @param newOptions The object which contains the new options.
3052* @returns {*} A object which contains the changed options.
3053*/
3054function setOptions(newOptions) {3055var validatedOpts = _pluginsOptions._validate(newOptions, _pluginsOptions._template, true, _currentOptions)3056
3057_currentOptions = extendDeep({}, _currentOptions, validatedOpts._default);3058_currentPreparedOptions = extendDeep({}, _currentPreparedOptions, validatedOpts._prepared);3059
3060return validatedOpts._prepared;3061}3062
3063
3064//==== Structure ====//3065
3066/**3067* Builds or destroys the wrapper and helper DOM elements.
3068* @param destroy Indicates whether the DOM shall be build or destroyed.
3069*/
3070/**3071* Builds or destroys the wrapper and helper DOM elements.
3072* @param destroy Indicates whether the DOM shall be build or destroyed.
3073*/
3074function setupStructureDOM(destroy) {3075var strParent = 'parent';3076var classNameResizeObserverHost = 'os-resize-observer-host';3077var classNameTextareaElementFull = _classNameTextareaElement + _strSpace + _classNameTextInherit;3078var textareaClass = _isTextarea ? _strSpace + _classNameTextInherit : _strEmpty;3079var adoptAttrs = _currentPreparedOptions.textarea.inheritedAttrs;3080var adoptAttrsMap = {};3081var applyAdoptedAttrs = function () {3082var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement;3083each(adoptAttrsMap, function (key, value) {3084if (type(value) == TYPES.s) {3085if (key == LEXICON.c)3086applyAdoptedAttrsElm.addClass(value);3087else3088applyAdoptedAttrsElm.attr(key, value);3089}3090});3091};3092var hostElementClassNames = [3093_classNameHostElement,3094_classNameHostElementForeign,3095_classNameHostTextareaElement,3096_classNameHostResizeDisabled,3097_classNameHostRTL,3098_classNameHostScrollbarHorizontalHidden,3099_classNameHostScrollbarVerticalHidden,3100_classNameHostTransition,3101_classNameHostScrolling,3102_classNameHostOverflow,3103_classNameHostOverflowX,3104_classNameHostOverflowY,3105_classNameThemeNone,3106_classNameTextareaElement,3107_classNameTextInherit,3108_classNameCache].join(_strSpace);3109var hostElementCSS = {};3110
3111//get host element as first element, because that's the most upper element and required for the other elements3112_hostElement = _hostElement || (_isTextarea ? (_domExists ? _targetElement[strParent]()[strParent]()[strParent]()[strParent]() : FRAMEWORK(generateDiv(_classNameHostTextareaElement))) : _targetElement);3113_contentElement = _contentElement || selectOrGenerateDivByClass(_classNameContentElement + textareaClass);3114_viewportElement = _viewportElement || selectOrGenerateDivByClass(_classNameViewportElement + textareaClass);3115_paddingElement = _paddingElement || selectOrGenerateDivByClass(_classNamePaddingElement + textareaClass);3116_sizeObserverElement = _sizeObserverElement || selectOrGenerateDivByClass(classNameResizeObserverHost);3117_textareaCoverElement = _textareaCoverElement || (_isTextarea ? selectOrGenerateDivByClass(_classNameTextareaCoverElement) : undefined);3118
3119//add this class to workaround class changing issues with UI frameworks especially Vue3120if (_domExists)3121addClass(_hostElement, _classNameHostElementForeign);3122
3123//on destroy, remove all generated class names from the host element before collecting the adopted attributes3124//to prevent adopting generated class names3125if (destroy)3126removeClass(_hostElement, hostElementClassNames);3127
3128//collect all adopted attributes3129adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(_strSpace) : adoptAttrs;3130if (COMPATIBILITY.isA(adoptAttrs) && _isTextarea) {3131each(adoptAttrs, function (i, v) {3132if (type(v) == TYPES.s) {3133adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v);3134}3135});3136}3137
3138if (!destroy) {3139if (_isTextarea) {3140if (!_currentPreparedOptions.sizeAutoCapable) {3141hostElementCSS[_strWidth] = _targetElement.css(_strWidth);3142hostElementCSS[_strHeight] = _targetElement.css(_strHeight);3143}3144
3145if (!_domExists)3146_targetElement.addClass(_classNameTextInherit).wrap(_hostElement);3147
3148//jQuery clones elements in wrap functions, so we have to select them again3149_hostElement = _targetElement[strParent]().css(hostElementCSS);3150}3151
3152if (!_domExists) {3153//add the correct class to the target element3154addClass(_targetElement, _isTextarea ? classNameTextareaElementFull : _classNameHostElement);3155
3156//wrap the content into the generated elements to create the required DOM3157_hostElement.wrapInner(_contentElement)3158.wrapInner(_viewportElement)3159.wrapInner(_paddingElement)3160.prepend(_sizeObserverElement);3161
3162//jQuery clones elements in wrap functions, so we have to select them again3163_contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);3164_viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);3165_paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);3166
3167if (_isTextarea) {3168_contentElement.prepend(_textareaCoverElement);3169applyAdoptedAttrs();3170}3171}3172
3173if (_nativeScrollbarStyling)3174addClass(_viewportElement, _classNameViewportNativeScrollbarsInvisible);3175if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)3176addClass(_viewportElement, _classNameViewportNativeScrollbarsOverlaid);3177if (_isBody)3178addClass(_htmlElement, _classNameHTMLElement);3179
3180_sizeObserverElementNative = _sizeObserverElement[0];3181_hostElementNative = _hostElement[0];3182_paddingElementNative = _paddingElement[0];3183_viewportElementNative = _viewportElement[0];3184_contentElementNative = _contentElement[0];3185
3186updateViewportAttrsFromTarget();3187}3188else {3189if (_domExists && _initialized) {3190//clear size observer3191_sizeObserverElement.children().remove();3192
3193//remove the style property and classes from already generated elements3194each([_paddingElement, _viewportElement, _contentElement, _textareaCoverElement], function (i, elm) {3195if (elm) {3196removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);3197}3198});3199
3200//add classes to the host element which was removed previously to match the expected DOM3201addClass(_hostElement, _isTextarea ? _classNameHostTextareaElement : _classNameHostElement);3202}3203else {3204//remove size observer3205remove(_sizeObserverElement);3206
3207//unwrap the content to restore DOM3208_contentElement.contents()3209.unwrap()3210.unwrap()3211.unwrap();3212
3213if (_isTextarea) {3214_targetElement.unwrap();3215remove(_hostElement);3216remove(_textareaCoverElement);3217applyAdoptedAttrs();3218}3219}3220
3221if (_isTextarea)3222_targetElement.removeAttr(LEXICON.s);3223
3224if (_isBody)3225removeClass(_htmlElement, _classNameHTMLElement);3226}3227}3228
3229/**3230* Adds or removes all wrapper elements interactivity events.
3231* @param destroy Indicates whether the Events shall be added or removed.
3232*/
3233function setupStructureEvents() {3234var textareaKeyDownRestrictedKeyCodes = [3235112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, //F1 to F12323633, 34, //page up, page down323737, 38, 39, 40, //left, up, right, down arrows323816, 17, 18, 19, 20, 144 //Shift, Ctrl, Alt, Pause, CapsLock, NumLock3239];3240var textareaKeyDownKeyCodesList = [];3241var textareaUpdateIntervalID;3242var scrollStopTimeoutId;3243var scrollStopDelay = 175;3244var strFocus = 'focus';3245
3246function updateTextarea(doClearInterval) {3247textareaUpdate();3248_base.update(_strAuto);3249if (doClearInterval && _autoUpdateRecommended)3250clearInterval(textareaUpdateIntervalID);3251}3252function textareaOnScroll(event) {3253_targetElement[_strScrollLeft](_rtlScrollBehavior.i && _normalizeRTLCache ? 9999999 : 0);3254_targetElement[_strScrollTop](0);3255COMPATIBILITY.prvD(event);3256COMPATIBILITY.stpP(event);3257return false;3258}3259function textareaOnDrop(event) {3260setTimeout(function () {3261if (!_destroyed)3262updateTextarea();3263}, 50);3264}3265function textareaOnFocus() {3266_textareaHasFocus = true;3267addClass(_hostElement, strFocus);3268}3269function textareaOnFocusout() {3270_textareaHasFocus = false;3271textareaKeyDownKeyCodesList = [];3272removeClass(_hostElement, strFocus);3273updateTextarea(true);3274}3275function textareaOnKeyDown(event) {3276var keyCode = event.keyCode;3277
3278if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {3279if (!textareaKeyDownKeyCodesList[LEXICON.l]) {3280updateTextarea();3281textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60);3282}3283if (inArray(keyCode, textareaKeyDownKeyCodesList) < 0)3284textareaKeyDownKeyCodesList.push(keyCode);3285}3286}3287function textareaOnKeyUp(event) {3288var keyCode = event.keyCode;3289var index = inArray(keyCode, textareaKeyDownKeyCodesList);3290
3291if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) < 0) {3292if (index > -1)3293textareaKeyDownKeyCodesList.splice(index, 1);3294if (!textareaKeyDownKeyCodesList[LEXICON.l])3295updateTextarea(true);3296}3297}3298function contentOnTransitionEnd(event) {3299if (_autoUpdateCache === true)3300return;3301event = event.originalEvent || event;3302if (isSizeAffectingCSSProperty(event.propertyName))3303_base.update(_strAuto);3304}3305function viewportOnScroll(event) {3306if (!_sleeping) {3307if (scrollStopTimeoutId !== undefined)3308clearTimeout(scrollStopTimeoutId);3309else {3310if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)3311refreshScrollbarsAutoHide(true);3312
3313if (!nativeOverlayScrollbarsAreActive())3314addClass(_hostElement, _classNameHostScrolling);3315
3316dispatchCallback('onScrollStart', event);3317}3318
3319//if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset3320//because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point3321//this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove3322if (!_scrollbarsHandlesDefineScrollPos) {3323refreshScrollbarHandleOffset(true);3324refreshScrollbarHandleOffset(false);3325}3326dispatchCallback('onScroll', event);3327
3328scrollStopTimeoutId = setTimeout(function () {3329if (!_destroyed) {3330//OnScrollStop:3331clearTimeout(scrollStopTimeoutId);3332scrollStopTimeoutId = undefined;3333
3334if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)3335refreshScrollbarsAutoHide(false);3336
3337if (!nativeOverlayScrollbarsAreActive())3338removeClass(_hostElement, _classNameHostScrolling);3339
3340dispatchCallback('onScrollStop', event);3341}3342}, scrollStopDelay);3343}3344}3345
3346
3347if (_isTextarea) {3348if (_msieVersion > 9 || !_autoUpdateRecommended) {3349addDestroyEventListener(_targetElement, 'input', updateTextarea);3350}3351else {3352addDestroyEventListener(_targetElement,3353[_strKeyDownEvent, _strKeyUpEvent],3354[textareaOnKeyDown, textareaOnKeyUp]);3355}3356
3357addDestroyEventListener(_targetElement,3358[_strScroll, 'drop', strFocus, strFocus + 'out'],3359[textareaOnScroll, textareaOnDrop, textareaOnFocus, textareaOnFocusout]);3360}3361else {3362addDestroyEventListener(_contentElement, _strTransitionEndEvent, contentOnTransitionEnd);3363}3364addDestroyEventListener(_viewportElement, _strScroll, viewportOnScroll, true);3365}3366
3367
3368//==== Scrollbars ====//3369
3370/**3371* Builds or destroys all scrollbar DOM elements (scrollbar, track, handle)
3372* @param destroy Indicates whether the DOM shall be build or destroyed.
3373*/
3374function setupScrollbarsDOM(destroy) {3375var selectOrGenerateScrollbarDOM = function (isHorizontal) {3376var scrollbarClassName = isHorizontal ? _classNameScrollbarHorizontal : _classNameScrollbarVertical;3377var scrollbar = selectOrGenerateDivByClass(_classNameScrollbar + _strSpace + scrollbarClassName, true);3378var track = selectOrGenerateDivByClass(_classNameScrollbarTrack, scrollbar);3379var handle = selectOrGenerateDivByClass(_classNameScrollbarHandle, scrollbar);3380
3381if (!_domExists && !destroy) {3382scrollbar.append(track);3383track.append(handle);3384}3385
3386return {3387_scrollbar: scrollbar,3388_track: track,3389_handle: handle3390};3391};3392function resetScrollbarDOM(isHorizontal) {3393var scrollbarVars = getScrollbarVars(isHorizontal);3394var scrollbar = scrollbarVars._scrollbar;3395var track = scrollbarVars._track;3396var handle = scrollbarVars._handle;3397
3398if (_domExists && _initialized) {3399each([scrollbar, track, handle], function (i, elm) {3400removeClass(elm.removeAttr(LEXICON.s), _classNamesDynamicDestroy);3401});3402}3403else {3404remove(scrollbar || selectOrGenerateScrollbarDOM(isHorizontal)._scrollbar);3405}3406}3407var horizontalElements;3408var verticalElements;3409
3410if (!destroy) {3411horizontalElements = selectOrGenerateScrollbarDOM(true);3412verticalElements = selectOrGenerateScrollbarDOM();3413
3414_scrollbarHorizontalElement = horizontalElements._scrollbar;3415_scrollbarHorizontalTrackElement = horizontalElements._track;3416_scrollbarHorizontalHandleElement = horizontalElements._handle;3417_scrollbarVerticalElement = verticalElements._scrollbar;3418_scrollbarVerticalTrackElement = verticalElements._track;3419_scrollbarVerticalHandleElement = verticalElements._handle;3420
3421if (!_domExists) {3422_paddingElement.after(_scrollbarVerticalElement);3423_paddingElement.after(_scrollbarHorizontalElement);3424}3425}3426else {3427resetScrollbarDOM(true);3428resetScrollbarDOM();3429}3430}3431
3432/**3433* Initializes all scrollbar interactivity events. (track and handle dragging, clicking, scrolling)
3434* @param isHorizontal True if the target scrollbar is the horizontal scrollbar, false if the target scrollbar is the vertical scrollbar.
3435*/
3436function setupScrollbarEvents(isHorizontal) {3437var scrollbarVars = getScrollbarVars(isHorizontal);3438var scrollbarVarsInfo = scrollbarVars._info;3439var insideIFrame = _windowElementNative.top !== _windowElementNative;3440var xy = scrollbarVars._x_y;3441var XY = scrollbarVars._X_Y;3442var scroll = _strScroll + scrollbarVars._Left_Top;3443var strActive = 'active';3444var strSnapHandle = 'snapHandle';3445var strClickEvent = 'click';3446var scrollDurationFactor = 1;3447var increaseDecreaseScrollAmountKeyCodes = [16, 17]; //shift, ctrl3448var trackTimeout;3449var mouseDownScroll;3450var mouseDownOffset;3451var mouseDownInvertedScale;3452
3453function getPointerPosition(event) {3454return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames.3455}3456function getPreparedScrollbarsOption(name) {3457return _currentPreparedOptions.scrollbars[name];3458}3459function increaseTrackScrollAmount() {3460scrollDurationFactor = 0.5;3461}3462function decreaseTrackScrollAmount() {3463scrollDurationFactor = 1;3464}3465function stopClickEventPropagation(event) {3466COMPATIBILITY.stpP(event);3467}3468function documentKeyDown(event) {3469if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)3470increaseTrackScrollAmount();3471}3472function documentKeyUp(event) {3473if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)3474decreaseTrackScrollAmount();3475}3476function onMouseTouchDownContinue(event) {3477var originalEvent = event.originalEvent || event;3478var isTouchEvent = originalEvent.touches !== undefined;3479return _sleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;3480}3481function documentDragMove(event) {3482if (onMouseTouchDownContinue(event)) {3483var trackLength = scrollbarVarsInfo._trackLength;3484var handleLength = scrollbarVarsInfo._handleLength;3485var scrollRange = scrollbarVarsInfo._maxScroll;3486var scrollRaw = (getPointerPosition(event) - mouseDownOffset) * mouseDownInvertedScale;3487var scrollDeltaPercent = scrollRaw / (trackLength - handleLength);3488var scrollDelta = (scrollRange * scrollDeltaPercent);3489scrollDelta = isFinite(scrollDelta) ? scrollDelta : 0;3490if (_isRTL && isHorizontal && !_rtlScrollBehavior.i)3491scrollDelta *= -1;3492
3493_viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta));3494
3495if (_scrollbarsHandlesDefineScrollPos)3496refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta);3497
3498if (!_supportPassiveEvents)3499COMPATIBILITY.prvD(event);3500}3501else3502documentMouseTouchUp(event);3503}3504function documentMouseTouchUp(event) {3505event = event || event.originalEvent;3506
3507setupResponsiveEventListener(_documentElement,3508[_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],3509[documentDragMove, documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart],3510true);3511COMPATIBILITY.rAF()(function() {3512setupResponsiveEventListener(_documentElement, strClickEvent, stopClickEventPropagation, true, { _capture: true });3513});3514
3515
3516if (_scrollbarsHandlesDefineScrollPos)3517refreshScrollbarHandleOffset(isHorizontal, true);3518
3519_scrollbarsHandlesDefineScrollPos = false;3520removeClass(_bodyElement, _classNameDragging);3521removeClass(scrollbarVars._handle, strActive);3522removeClass(scrollbarVars._track, strActive);3523removeClass(scrollbarVars._scrollbar, strActive);3524
3525mouseDownScroll = undefined;3526mouseDownOffset = undefined;3527mouseDownInvertedScale = 1;3528
3529decreaseTrackScrollAmount();3530
3531if (trackTimeout !== undefined) {3532_base.scrollStop();3533clearTimeout(trackTimeout);3534trackTimeout = undefined;3535}3536
3537if (event) {3538var rect = _hostElementNative[LEXICON.bCR]();3539var mouseInsideHost = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;3540
3541//if mouse is outside host element3542if (!mouseInsideHost)3543hostOnMouseLeave();3544
3545if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)3546refreshScrollbarsAutoHide(false);3547}3548}3549function onHandleMouseTouchDown(event) {3550if (onMouseTouchDownContinue(event))3551onHandleMouseTouchDownAction(event);3552}3553function onHandleMouseTouchDownAction(event) {3554mouseDownScroll = _viewportElement[scroll]();3555mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll;3556if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL)3557mouseDownScroll = mouseDownScroll < 0 ? 0 : mouseDownScroll;3558
3559mouseDownInvertedScale = getHostElementInvertedScale()[xy];3560mouseDownOffset = getPointerPosition(event);3561
3562_scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);3563addClass(_bodyElement, _classNameDragging);3564addClass(scrollbarVars._handle, strActive);3565addClass(scrollbarVars._scrollbar, strActive);3566
3567setupResponsiveEventListener(_documentElement,3568[_strMouseTouchMoveEvent, _strMouseTouchUpEvent, _strSelectStartEvent],3569[documentDragMove, documentMouseTouchUp, documentOnSelectStart]);3570COMPATIBILITY.rAF()(function() {3571setupResponsiveEventListener(_documentElement, strClickEvent, stopClickEventPropagation, false, { _capture: true });3572});3573
3574
3575if (_msieVersion || !_documentMixed)3576COMPATIBILITY.prvD(event);3577COMPATIBILITY.stpP(event);3578}3579function onTrackMouseTouchDown(event) {3580if (onMouseTouchDownContinue(event)) {3581var handleToViewportRatio = scrollbarVars._info._handleLength / Math.round(MATH.min(1, _viewportSize[scrollbarVars._w_h] / _contentScrollSizeCache[scrollbarVars._w_h]) * scrollbarVars._info._trackLength);3582var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h] * handleToViewportRatio);3583var scrollBaseDuration = 270 * handleToViewportRatio;3584var scrollFirstIterationDelay = 400 * handleToViewportRatio;3585var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top];3586var ctrlKey = event.ctrlKey;3587var instantScroll = event.shiftKey;3588var instantScrollTransition = instantScroll && ctrlKey;3589var isFirstIteration = true;3590var easing = 'linear';3591var decreaseScroll;3592var finishedCondition;3593var scrollActionFinsished = function (transition) {3594if (_scrollbarsHandlesDefineScrollPos)3595refreshScrollbarHandleOffset(isHorizontal, transition);3596};3597var scrollActionInstantFinished = function () {3598scrollActionFinsished();3599onHandleMouseTouchDownAction(event);3600};3601var scrollAction = function () {3602if (!_destroyed) {3603var mouseOffset = (mouseDownOffset - trackOffset) * mouseDownInvertedScale;3604var handleOffset = scrollbarVarsInfo._handleOffset;3605var trackLength = scrollbarVarsInfo._trackLength;3606var handleLength = scrollbarVarsInfo._handleLength;3607var scrollRange = scrollbarVarsInfo._maxScroll;3608var currScroll = scrollbarVarsInfo._currentScroll;3609var scrollDuration = scrollBaseDuration * scrollDurationFactor;3610var timeoutDelay = isFirstIteration ? MATH.max(scrollFirstIterationDelay, scrollDuration) : scrollDuration;3611var instantScrollPosition = scrollRange * ((mouseOffset - (handleLength / 2)) / (trackLength - handleLength)); // 100% * positionPercent3612var rtlIsNormal = _isRTL && isHorizontal && ((!_rtlScrollBehavior.i && !_rtlScrollBehavior.n) || _normalizeRTLCache);3613var decreaseScrollCondition = rtlIsNormal ? handleOffset < mouseOffset : handleOffset > mouseOffset;3614var scrollObj = {};3615var animationObj = {3616easing: easing,3617step: function (now) {3618if (_scrollbarsHandlesDefineScrollPos) {3619_viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/43403620refreshScrollbarHandleOffset(isHorizontal, now);3621}3622}3623};3624instantScrollPosition = isFinite(instantScrollPosition) ? instantScrollPosition : 0;3625instantScrollPosition = _isRTL && isHorizontal && !_rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;3626
3627//_base.scrollStop();3628
3629if (instantScroll) {3630_viewportElement[scroll](instantScrollPosition); //scroll instantly to new position3631if (instantScrollTransition) {3632//get the scroll position after instant scroll (in case CSS Snap Points are used) to get the correct snapped scroll position3633//and the animation stops at the correct point3634instantScrollPosition = _viewportElement[scroll]();3635//scroll back to the position before instant scrolling so animation can be performed3636_viewportElement[scroll](currScroll);3637
3638instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;3639instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.n ? -instantScrollPosition : instantScrollPosition;3640
3641scrollObj[xy] = instantScrollPosition;3642_base.scroll(scrollObj, extendDeep(animationObj, {3643duration: 130,3644complete: scrollActionInstantFinished3645}));3646}3647else3648scrollActionInstantFinished();3649}3650else {3651decreaseScroll = isFirstIteration ? decreaseScrollCondition : decreaseScroll;3652finishedCondition = rtlIsNormal3653? (decreaseScroll ? handleOffset + handleLength >= mouseOffset : handleOffset <= mouseOffset)3654: (decreaseScroll ? handleOffset <= mouseOffset : handleOffset + handleLength >= mouseOffset);3655
3656if (finishedCondition) {3657clearTimeout(trackTimeout);3658_base.scrollStop();3659trackTimeout = undefined;3660scrollActionFinsished(true);3661}3662else {3663trackTimeout = setTimeout(scrollAction, timeoutDelay);3664
3665scrollObj[xy] = (decreaseScroll ? '-=' : '+=') + scrollDistance;3666_base.scroll(scrollObj, extendDeep(animationObj, {3667duration: scrollDuration3668}));3669}3670isFirstIteration = false;3671}3672}3673};3674if (ctrlKey)3675increaseTrackScrollAmount();3676
3677mouseDownInvertedScale = getHostElementInvertedScale()[xy];3678mouseDownOffset = COMPATIBILITY.page(event)[xy];3679
3680_scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle);3681addClass(_bodyElement, _classNameDragging);3682addClass(scrollbarVars._track, strActive);3683addClass(scrollbarVars._scrollbar, strActive);3684
3685setupResponsiveEventListener(_documentElement,3686[_strMouseTouchUpEvent, _strKeyDownEvent, _strKeyUpEvent, _strSelectStartEvent],3687[documentMouseTouchUp, documentKeyDown, documentKeyUp, documentOnSelectStart]);3688
3689scrollAction();3690COMPATIBILITY.prvD(event);3691COMPATIBILITY.stpP(event);3692}3693}3694function onTrackMouseTouchEnter(event) {3695//make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move".3696_scrollbarsHandleHovered = true;3697if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)3698refreshScrollbarsAutoHide(true);3699}3700function onTrackMouseTouchLeave(event) {3701_scrollbarsHandleHovered = false;3702if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)3703refreshScrollbarsAutoHide(false);3704}3705function onScrollbarMouseTouchDown(event) {3706COMPATIBILITY.stpP(event);3707}3708
3709addDestroyEventListener(scrollbarVars._handle,3710_strMouseTouchDownEvent,3711onHandleMouseTouchDown);3712addDestroyEventListener(scrollbarVars._track,3713[_strMouseTouchDownEvent, _strMouseEnter, _strMouseLeave],3714[onTrackMouseTouchDown, onTrackMouseTouchEnter, onTrackMouseTouchLeave]);3715addDestroyEventListener(scrollbarVars._scrollbar,3716_strMouseTouchDownEvent,3717onScrollbarMouseTouchDown);3718
3719if (_supportTransition) {3720addDestroyEventListener(scrollbarVars._scrollbar, _strTransitionEndEvent, function (event) {3721if (event.target !== scrollbarVars._scrollbar[0])3722return;3723refreshScrollbarHandleLength(isHorizontal);3724refreshScrollbarHandleOffset(isHorizontal);3725});3726}3727}3728
3729/**3730* Shows or hides the given scrollbar and applied a class name which indicates if the scrollbar is scrollable or not.
3731* @param isHorizontal True if the horizontal scrollbar is the target, false if the vertical scrollbar is the target.
3732* @param shallBeVisible True if the scrollbar shall be shown, false if hidden.
3733* @param canScroll True if the scrollbar is scrollable, false otherwise.
3734*/
3735function refreshScrollbarAppearance(isHorizontal, shallBeVisible, canScroll) {3736var scrollbarHiddenClassName = isHorizontal ? _classNameHostScrollbarHorizontalHidden : _classNameHostScrollbarVerticalHidden;3737var scrollbarElement = isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement;3738
3739addRemoveClass(_hostElement, scrollbarHiddenClassName, !shallBeVisible);3740addRemoveClass(scrollbarElement, _classNameScrollbarUnusable, !canScroll);3741}3742
3743/**3744* Autoshows / autohides both scrollbars with.
3745* @param shallBeVisible True if the scrollbars shall be autoshown (only the case if they are hidden by a autohide), false if the shall be auto hidden.
3746* @param delayfree True if the scrollbars shall be hidden without a delay, false or undefined otherwise.
3747*/
3748function refreshScrollbarsAutoHide(shallBeVisible, delayfree) {3749clearTimeout(_scrollbarsAutoHideTimeoutId);3750if (shallBeVisible) {3751//if(_hasOverflowCache.x && _hideOverflowCache.xs)3752removeClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);3753//if(_hasOverflowCache.y && _hideOverflowCache.ys)3754removeClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);3755}3756else {3757var anyActive;3758var strActive = 'active';3759var hide = function () {3760if (!_scrollbarsHandleHovered && !_destroyed) {3761anyActive = _scrollbarHorizontalHandleElement.hasClass(strActive) || _scrollbarVerticalHandleElement.hasClass(strActive);3762if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))3763addClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);3764if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))3765addClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);3766}3767};3768if (_scrollbarsAutoHideDelay > 0 && delayfree !== true)3769_scrollbarsAutoHideTimeoutId = setTimeout(hide, _scrollbarsAutoHideDelay);3770else3771hide();3772}3773}3774
3775/**3776* Refreshes the handle length of the given scrollbar.
3777* @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
3778*/
3779function refreshScrollbarHandleLength(isHorizontal) {3780var handleCSS = {};3781var scrollbarVars = getScrollbarVars(isHorizontal);3782var scrollbarVarsInfo = scrollbarVars._info;3783var digit = 1000000;3784//get and apply intended handle length3785var handleRatio = MATH.min(1, _viewportSize[scrollbarVars._w_h] / _contentScrollSizeCache[scrollbarVars._w_h]);3786handleCSS[scrollbarVars._width_height] = (MATH.floor(handleRatio * 100 * digit) / digit) + '%'; //the last * digit / digit is for flooring to the 4th digit3787
3788if (!nativeOverlayScrollbarsAreActive())3789scrollbarVars._handle.css(handleCSS);3790
3791//measure the handle length to respect min & max length3792scrollbarVarsInfo._handleLength = scrollbarVars._handle[0]['offset' + scrollbarVars._Width_Height];3793scrollbarVarsInfo._handleLengthRatio = handleRatio;3794}3795
3796/**3797* Refreshes the handle offset of the given scrollbar.
3798* @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
3799* @param scrollOrTransition The scroll position of the given scrollbar axis to which the handle shall be moved or a boolean which indicates whether a transition shall be applied. If undefined or boolean if the current scroll-offset is taken. (if isHorizontal ? scrollLeft : scrollTop)
3800*/
3801function refreshScrollbarHandleOffset(isHorizontal, scrollOrTransition) {3802var transition = type(scrollOrTransition) == TYPES.b;3803var transitionDuration = 250;3804var isRTLisHorizontal = _isRTL && isHorizontal;3805var scrollbarVars = getScrollbarVars(isHorizontal);3806var scrollbarVarsInfo = scrollbarVars._info;3807var strTranslateBrace = 'translate(';3808var strTransform = VENDORS._cssProperty('transform');3809var strTransition = VENDORS._cssProperty('transition');3810var nativeScroll = isHorizontal ? _viewportElement[_strScrollLeft]() : _viewportElement[_strScrollTop]();3811var currentScroll = scrollOrTransition === undefined || transition ? nativeScroll : scrollOrTransition;3812
3813//measure the handle length to respect min & max length3814var handleLength = scrollbarVarsInfo._handleLength;3815var trackLength = scrollbarVars._track[0]['offset' + scrollbarVars._Width_Height];3816var handleTrackDiff = trackLength - handleLength;3817var handleCSS = {};3818var transformOffset;3819var translateValue;3820
3821//DONT use the variable '_contentScrollSizeCache[scrollbarVars._w_h]' instead of '_viewportElement[0]['scroll' + scrollbarVars._Width_Height]'3822// because its a bit behind during the small delay when content size updates3823//(delay = mutationObserverContentLag, if its 0 then this var could be used)3824var maxScroll = (_viewportElementNative[_strScroll + scrollbarVars._Width_Height] - _viewportElementNative['client' + scrollbarVars._Width_Height]) * (_rtlScrollBehavior.n && isRTLisHorizontal ? -1 : 1); //* -1 if rtl scroll max is negative3825var getScrollRatio = function (base) {3826return isNaN(base / maxScroll) ? 0 : MATH.max(0, MATH.min(1, base / maxScroll));3827};3828var getHandleOffset = function (scrollRatio) {3829var offset = handleTrackDiff * scrollRatio;3830offset = isNaN(offset) ? 0 : offset;3831offset = (isRTLisHorizontal && !_rtlScrollBehavior.i) ? (trackLength - handleLength - offset) : offset;3832offset = MATH.max(0, offset);3833return offset;3834};3835var scrollRatio = getScrollRatio(nativeScroll);3836var unsnappedScrollRatio = getScrollRatio(currentScroll);3837var handleOffset = getHandleOffset(unsnappedScrollRatio);3838var snappedHandleOffset = getHandleOffset(scrollRatio);3839
3840scrollbarVarsInfo._maxScroll = maxScroll;3841scrollbarVarsInfo._currentScroll = nativeScroll;3842scrollbarVarsInfo._currentScrollRatio = scrollRatio;3843
3844if (_supportTransform) {3845transformOffset = isRTLisHorizontal ? -(trackLength - handleLength - handleOffset) : handleOffset; //in px3846//transformOffset = (transformOffset / trackLength * 100) * (trackLength / handleLength); //in %3847translateValue = isHorizontal ? strTranslateBrace + transformOffset + 'px, 0)' : strTranslateBrace + '0, ' + transformOffset + 'px)';3848
3849handleCSS[strTransform] = translateValue;3850
3851//apply or clear up transition3852if (_supportTransition)3853handleCSS[strTransition] = transition && MATH.abs(handleOffset - scrollbarVarsInfo._handleOffset) > 1 ? getCSSTransitionString(scrollbarVars._handle) + ', ' + (strTransform + _strSpace + transitionDuration + 'ms') : _strEmpty;3854}3855else3856handleCSS[scrollbarVars._left_top] = handleOffset;3857
3858
3859//only apply css if offset has changed and overflow exists.3860if (!nativeOverlayScrollbarsAreActive()) {3861scrollbarVars._handle.css(handleCSS);3862
3863//clear up transition3864if (_supportTransform && _supportTransition && transition) {3865scrollbarVars._handle.one(_strTransitionEndEvent, function () {3866if (!_destroyed)3867scrollbarVars._handle.css(strTransition, _strEmpty);3868});3869}3870}3871
3872scrollbarVarsInfo._handleOffset = handleOffset;3873scrollbarVarsInfo._snappedHandleOffset = snappedHandleOffset;3874scrollbarVarsInfo._trackLength = trackLength;3875}3876
3877/**3878* Refreshes the interactivity of the given scrollbar element.
3879* @param isTrack True if the track element is the target, false if the handle element is the target.
3880* @param value True for interactivity false for no interactivity.
3881*/
3882function refreshScrollbarsInteractive(isTrack, value) {3883var action = value ? 'removeClass' : 'addClass';3884var element1 = isTrack ? _scrollbarHorizontalTrackElement : _scrollbarHorizontalHandleElement;3885var element2 = isTrack ? _scrollbarVerticalTrackElement : _scrollbarVerticalHandleElement;3886var className = isTrack ? _classNameScrollbarTrackOff : _classNameScrollbarHandleOff;3887
3888element1[action](className);3889element2[action](className);3890}3891
3892/**3893* Returns a object which is used for fast access for specific variables.
3894* @param isHorizontal True if the horizontal scrollbar vars shall be accessed, false if the vertical scrollbar vars shall be accessed.
3895* @returns {{wh: string, WH: string, lt: string, _wh: string, _lt: string, t: *, h: *, c: {}, s: *}}
3896*/
3897function getScrollbarVars(isHorizontal) {3898return {3899_width_height: isHorizontal ? _strWidth : _strHeight,3900_Width_Height: isHorizontal ? 'Width' : 'Height',3901_left_top: isHorizontal ? _strLeft : _strTop,3902_Left_Top: isHorizontal ? 'Left' : 'Top',3903_x_y: isHorizontal ? _strX : _strY,3904_X_Y: isHorizontal ? 'X' : 'Y',3905_w_h: isHorizontal ? 'w' : 'h',3906_l_t: isHorizontal ? 'l' : 't',3907_track: isHorizontal ? _scrollbarHorizontalTrackElement : _scrollbarVerticalTrackElement,3908_handle: isHorizontal ? _scrollbarHorizontalHandleElement : _scrollbarVerticalHandleElement,3909_scrollbar: isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement,3910_info: isHorizontal ? _scrollHorizontalInfo : _scrollVerticalInfo3911};3912}3913
3914
3915//==== Scrollbar Corner ====//3916
3917/**3918* Builds or destroys the scrollbar corner DOM element.
3919* @param destroy Indicates whether the DOM shall be build or destroyed.
3920*/
3921function setupScrollbarCornerDOM(destroy) {3922_scrollbarCornerElement = _scrollbarCornerElement || selectOrGenerateDivByClass(_classNameScrollbarCorner, true);3923
3924if (!destroy) {3925if (!_domExists) {3926_hostElement.append(_scrollbarCornerElement);3927}3928}3929else {3930if (_domExists && _initialized) {3931removeClass(_scrollbarCornerElement.removeAttr(LEXICON.s), _classNamesDynamicDestroy);3932}3933else {3934remove(_scrollbarCornerElement);3935}3936}3937}3938
3939/**3940* Initializes all scrollbar corner interactivity events.
3941*/
3942function setupScrollbarCornerEvents() {3943var insideIFrame = _windowElementNative.top !== _windowElementNative;3944var mouseDownPosition = {};3945var mouseDownSize = {};3946var mouseDownInvertedScale = {};3947var reconnectMutationObserver;3948
3949function documentDragMove(event) {3950if (onMouseTouchDownContinue(event)) {3951var pageOffset = getCoordinates(event);3952var hostElementCSS = {};3953if (_resizeHorizontal || _resizeBoth)3954hostElementCSS[_strWidth] = (mouseDownSize.w + (pageOffset.x - mouseDownPosition.x) * mouseDownInvertedScale.x);3955if (_resizeVertical || _resizeBoth)3956hostElementCSS[_strHeight] = (mouseDownSize.h + (pageOffset.y - mouseDownPosition.y) * mouseDownInvertedScale.y);3957_hostElement.css(hostElementCSS);3958COMPATIBILITY.stpP(event);3959}3960else {3961documentMouseTouchUp(event);3962}3963}3964function documentMouseTouchUp(event) {3965var eventIsTrusted = event !== undefined;3966
3967setupResponsiveEventListener(_documentElement,3968[_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],3969[documentOnSelectStart, documentDragMove, documentMouseTouchUp],3970true);3971
3972removeClass(_bodyElement, _classNameDragging);3973if (_scrollbarCornerElement.releaseCapture)3974_scrollbarCornerElement.releaseCapture();3975
3976if (eventIsTrusted) {3977if (reconnectMutationObserver)3978connectMutationObservers();3979_base.update(_strAuto);3980}3981reconnectMutationObserver = false;3982}3983function onMouseTouchDownContinue(event) {3984var originalEvent = event.originalEvent || event;3985var isTouchEvent = originalEvent.touches !== undefined;3986return _sleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;3987}3988function getCoordinates(event) {3989return _msieVersion && insideIFrame ? { x: event.screenX, y: event.screenY } : COMPATIBILITY.page(event);3990}3991
3992addDestroyEventListener(_scrollbarCornerElement, _strMouseTouchDownEvent, function (event) {3993if (onMouseTouchDownContinue(event) && !_resizeNone) {3994if (_mutationObserversConnected) {3995reconnectMutationObserver = true;3996disconnectMutationObservers();3997}3998
3999mouseDownPosition = getCoordinates(event);4000
4001mouseDownSize.w = _hostElementNative[LEXICON.oW] - (!_isBorderBox ? _paddingX : 0);4002mouseDownSize.h = _hostElementNative[LEXICON.oH] - (!_isBorderBox ? _paddingY : 0);4003mouseDownInvertedScale = getHostElementInvertedScale();4004
4005setupResponsiveEventListener(_documentElement,4006[_strSelectStartEvent, _strMouseTouchMoveEvent, _strMouseTouchUpEvent],4007[documentOnSelectStart, documentDragMove, documentMouseTouchUp]);4008
4009addClass(_bodyElement, _classNameDragging);4010if (_scrollbarCornerElement.setCapture)4011_scrollbarCornerElement.setCapture();4012
4013COMPATIBILITY.prvD(event);4014COMPATIBILITY.stpP(event);4015}4016});4017}4018
4019
4020//==== Utils ====//4021
4022/**4023* Calls the callback with the given name. The Context of this callback is always _base (this).
4024* @param name The name of the target which shall be called.
4025* @param args The args with which the callback shall be called.
4026* @param dependent Boolean which decides whether the callback shall be fired, undefined is like a "true" value.
4027*/
4028function dispatchCallback(name, args, dependent) {4029if (dependent === false)4030return;4031if (_initialized) {4032var callback = _currentPreparedOptions.callbacks[name];4033var extensionOnName = name;4034var ext;4035
4036if (extensionOnName.substr(0, 2) === 'on')4037extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3);4038
4039if (type(callback) == TYPES.f)4040callback.call(_base, args);4041
4042each(_extensions, function () {4043ext = this;4044if (type(ext.on) == TYPES.f)4045ext.on(extensionOnName, args);4046});4047}4048else if (!_destroyed)4049_callbacksInitQeueue.push({ n: name, a: args });4050}4051
4052/**4053* Sets the "top, right, bottom, left" properties, with a given prefix, of the given css object.
4054* @param targetCSSObject The css object to which the values shall be applied.
4055* @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
4056* @param values A array of values which shall be applied to the "top, right, bottom, left" -properties. The array order is [top, right, bottom, left].
4057* If this argument is undefined the value '' (empty string) will be applied to all properties.
4058*/
4059function setTopRightBottomLeft(targetCSSObject, prefix, values) {4060prefix = prefix || _strEmpty;4061values = values || [_strEmpty, _strEmpty, _strEmpty, _strEmpty];4062
4063targetCSSObject[prefix + _strTop] = values[0];4064targetCSSObject[prefix + _strRight] = values[1];4065targetCSSObject[prefix + _strBottom] = values[2];4066targetCSSObject[prefix + _strLeft] = values[3];4067}4068
4069/**4070* Gets the "top, right, bottom, left" CSS properties of the CSS property with the given prefix from the host element.
4071* @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
4072* @param suffix The suffix of the "top, right, bottom, left" css properties. (example: 'border-' is a valid prefix with '-width' is a valid suffix)
4073* @param zeroX True if the x axis shall be 0.
4074* @param zeroY True if the y axis shall be 0.
4075* @returns {{}} The object which contains the numbers of the read CSS properties.
4076*/
4077function getTopRightBottomLeftHost(prefix, suffix, zeroX, zeroY) {4078suffix = suffix || _strEmpty;4079prefix = prefix || _strEmpty;4080return {4081t: zeroY ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strTop + suffix)),4082r: zeroX ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strRight + suffix)),4083b: zeroY ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strBottom + suffix)),4084l: zeroX ? 0 : parseToZeroOrNumber(_hostElement.css(prefix + _strLeft + suffix))4085};4086}4087
4088/**4089* Returns the computed CSS transition string from the given element.
4090* @param element The element from which the transition string shall be returned.
4091* @returns {string} The CSS transition string from the given element.
4092*/
4093function getCSSTransitionString(element) {4094var transitionStr = VENDORS._cssProperty('transition');4095var assembledValue = element.css(transitionStr);4096if (assembledValue)4097return assembledValue;4098var regExpString = '\\s*(' + '([^,(]+(\\(.+?\\))?)+' + ')[\\s,]*';4099var regExpMain = new RegExp(regExpString);4100var regExpValidate = new RegExp('^(' + regExpString + ')+$');4101var properties = 'property duration timing-function delay'.split(' ');4102var result = [];4103var strResult;4104var valueArray;4105var i = 0;4106var j;4107var splitCssStyleByComma = function (str) {4108strResult = [];4109if (!str.match(regExpValidate))4110return str;4111while (str.match(regExpMain)) {4112strResult.push(RegExp.$1);4113str = str.replace(regExpMain, _strEmpty);4114}4115
4116return strResult;4117};4118for (; i < properties[LEXICON.l]; i++) {4119valueArray = splitCssStyleByComma(element.css(transitionStr + '-' + properties[i]));4120for (j = 0; j < valueArray[LEXICON.l]; j++)4121result[j] = (result[j] ? result[j] + _strSpace : _strEmpty) + valueArray[j];4122}4123return result.join(', ');4124}4125
4126/**4127* Generates a Regular Expression which matches with a string which starts with 'os-host'.
4128* @param {boolean} withCurrClassNameOption The Regular Expression also matches if the string is the current ClassName option (multiple values splitted by space possible).
4129* @param {boolean} withOldClassNameOption The Regular Expression also matches if the string is the old ClassName option (multiple values splitted by space possible).
4130*/
4131function createHostClassNameRegExp(withCurrClassNameOption, withOldClassNameOption) {4132var i;4133var split;4134var appendix;4135var appendClasses = function (classes, condition) {4136appendix = '';4137if (condition && typeof classes == TYPES.s) {4138split = classes.split(_strSpace);4139for (i = 0; i < split[LEXICON.l]; i++)4140appendix += '|' + split[i] + '$';4141// split[i].replace(/[.*+?^${}()|[\]\\]/g, '\\$&') for escaping regex characters4142}4143return appendix;4144};4145
4146return new RegExp(4147'(^' + _classNameHostElement + '([-_].+|)$)' +4148appendClasses(_classNameCache, withCurrClassNameOption) +4149appendClasses(_oldClassName, withOldClassNameOption), 'g');4150}4151
4152/**4153* Calculates the host-elements inverted scale. (invertedScale = 1 / scale)
4154* @returns {{x: number, y: number}} The scale of the host-element.
4155*/
4156function getHostElementInvertedScale() {4157var rect = _paddingElementNative[LEXICON.bCR]();4158return {4159x: _supportTransform ? 1 / (MATH.round(rect.width) / _paddingElementNative[LEXICON.oW]) || 1 : 1,4160y: _supportTransform ? 1 / (MATH.round(rect.height) / _paddingElementNative[LEXICON.oH]) || 1 : 14161};4162}4163
4164/**4165* Checks whether the given object is a HTMLElement.
4166* @param o The object which shall be checked.
4167* @returns {boolean} True the given object is a HTMLElement, false otherwise.
4168*/
4169function isHTMLElement(o) {4170var strOwnerDocument = 'ownerDocument';4171var strHTMLElement = 'HTMLElement';4172var wnd = o && o[strOwnerDocument] ? (o[strOwnerDocument].parentWindow || window) : window;4173return (4174typeof wnd[strHTMLElement] == TYPES.o ? o instanceof wnd[strHTMLElement] : //DOM24175o && typeof o == TYPES.o && o !== null && o.nodeType === 1 && typeof o.nodeName == TYPES.s4176);4177}4178
4179/**4180* Compares 2 arrays and returns the differences between them as a array.
4181* @param a1 The first array which shall be compared.
4182* @param a2 The second array which shall be compared.
4183* @returns {Array} The differences between the two arrays.
4184*/
4185function getArrayDifferences(a1, a2) {4186var a = [];4187var diff = [];4188var i;4189var k;4190for (i = 0; i < a1.length; i++)4191a[a1[i]] = true;4192for (i = 0; i < a2.length; i++) {4193if (a[a2[i]])4194delete a[a2[i]];4195else4196a[a2[i]] = true;4197}4198for (k in a)4199diff.push(k);4200return diff;4201}4202
4203/**4204* Returns Zero or the number to which the value can be parsed.
4205* @param value The value which shall be parsed.
4206* @param toFloat Indicates whether the number shall be parsed to a float.
4207*/
4208function parseToZeroOrNumber(value, toFloat) {4209var num = toFloat ? parseFloat(value) : parseInt(value, 10);4210return isNaN(num) ? 0 : num;4211}4212
4213/**4214* Gets several information of the textarea and returns them as a object or undefined if the browser doesn't support it.
4215* @returns {{cursorRow: Number, cursorCol, rows: Number, cols: number, wRow: number, pos: number, max : number}} or undefined if not supported.
4216*/
4217function getTextareaInfo() {4218//read needed values4219var textareaCursorPosition = _targetElementNative.selectionStart;4220if (textareaCursorPosition === undefined)4221return;4222
4223var textareaValue = _targetElement.val();4224var textareaLength = textareaValue[LEXICON.l];4225var textareaRowSplit = textareaValue.split('\n');4226var textareaLastRow = textareaRowSplit[LEXICON.l];4227var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split('\n');4228var widestRow = 0;4229var textareaLastCol = 0;4230var cursorRow = textareaCurrentCursorRowSplit[LEXICON.l];4231var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[LEXICON.l] - 1][LEXICON.l];4232var rowCols;4233var i;4234
4235//get widest Row and the last column of the textarea4236for (i = 0; i < textareaRowSplit[LEXICON.l]; i++) {4237rowCols = textareaRowSplit[i][LEXICON.l];4238if (rowCols > textareaLastCol) {4239widestRow = i + 1;4240textareaLastCol = rowCols;4241}4242}4243
4244return {4245_cursorRow: cursorRow, //cursorRow4246_cursorColumn: cursorCol, //cursorCol4247_rows: textareaLastRow, //rows4248_columns: textareaLastCol, //cols4249_widestRow: widestRow, //wRow4250_cursorPosition: textareaCursorPosition, //pos4251_cursorMax: textareaLength //max4252};4253}4254
4255/**4256* Determines whether native overlay scrollbars are active.
4257* @returns {boolean} True if native overlay scrollbars are active, false otherwise.
4258*/
4259function nativeOverlayScrollbarsAreActive() {4260return (_ignoreOverlayScrollbarHidingCache && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y));4261}4262
4263/**4264* Gets the element which is used to measure the content size.
4265* @returns {*} TextareaCover if target element is textarea else the ContentElement.
4266*/
4267function getContentMeasureElement() {4268return _isTextarea ? _textareaCoverElement[0] : _contentElementNative;4269}4270
4271/**4272* Generates a string which represents a HTML div with the given classes or attributes.
4273* @param classesOrAttrs The class of the div as string or a object which represents the attributes of the div. (The class attribute can also be written as "className".)
4274* @param content The content of the div as string.
4275* @returns {string} The concated string which represents a HTML div and its content.
4276*/
4277function generateDiv(classesOrAttrs, content) {4278return '<div ' + (classesOrAttrs ? type(classesOrAttrs) == TYPES.s ?4279'class="' + classesOrAttrs + '"' :4280(function () {4281var key;4282var attrs = _strEmpty;4283if (FRAMEWORK.isPlainObject(classesOrAttrs)) {4284for (key in classesOrAttrs)4285attrs += (key === 'c' ? 'class' : key) + '="' + classesOrAttrs[key] + '" ';4286}4287return attrs;4288})() :4289_strEmpty) +4290'>' +4291(content || _strEmpty) +4292'</div>';4293}4294
4295/**4296* Selects or generates a div with the given class attribute.
4297* @param className The class names (divided by spaces) of the div which shall be selected or generated.
4298* @param selectParentOrOnlyChildren The parent element from which of the element shall be selected. (if undefined or boolean its hostElement)
4299* If its a boolean it decides whether only the children of the host element shall be selected.
4300* @returns {*} The generated or selected element.
4301*/
4302function selectOrGenerateDivByClass(className, selectParentOrOnlyChildren) {4303var onlyChildren = type(selectParentOrOnlyChildren) == TYPES.b;4304var selectParent = onlyChildren ? _hostElement : (selectParentOrOnlyChildren || _hostElement);4305
4306return (_domExists && !selectParent[LEXICON.l])4307? null4308: _domExists4309? selectParent[onlyChildren ? 'children' : 'find'](_strDot + className.replace(/\s/g, _strDot)).eq(0)4310: FRAMEWORK(generateDiv(className))4311}4312
4313/**4314* Gets the value of the given property from the given object.
4315* @param obj The object from which the property value shall be got.
4316* @param path The property of which the value shall be got.
4317* @returns {*} Returns the value of the searched property or undefined of the property wasn't found.
4318*/
4319function getObjectPropVal(obj, path) {4320var splits = path.split(_strDot);4321var i = 0;4322var val;4323for (; i < splits.length; i++) {4324if (!obj[LEXICON.hOP](splits[i]))4325return;4326val = obj[splits[i]];4327if (i < splits.length && type(val) == TYPES.o)4328obj = val;4329}4330return val;4331}4332
4333/**4334* Sets the value of the given property from the given object.
4335* @param obj The object from which the property value shall be set.
4336* @param path The property of which the value shall be set.
4337* @param val The value of the property which shall be set.
4338*/
4339function setObjectPropVal(obj, path, val) {4340var splits = path.split(_strDot);4341var splitsLength = splits.length;4342var i = 0;4343var extendObj = {};4344var extendObjRoot = extendObj;4345for (; i < splitsLength; i++)4346extendObj = extendObj[splits[i]] = i + 1 < splitsLength ? {} : val;4347FRAMEWORK.extend(obj, extendObjRoot, true);4348}4349
4350/**4351* Runs a action for each selector inside the updateOnLoad option.
4352* @param {Function} action The action for each updateOnLoad selector, the arguments the function takes is the index and the value (the selector).
4353*/
4354function eachUpdateOnLoad(action) {4355var updateOnLoad = _currentPreparedOptions.updateOnLoad;4356updateOnLoad = type(updateOnLoad) == TYPES.s ? updateOnLoad.split(_strSpace) : updateOnLoad;4357
4358if (COMPATIBILITY.isA(updateOnLoad) && !_destroyed) {4359each(updateOnLoad, action);4360}4361}4362
4363
4364//==== Utils Cache ====//4365
4366/**4367* Compares two values or objects and returns true if they aren't equal.
4368* @param current The first value or object which shall be compared.
4369* @param cache The second value or object which shall be compared.
4370* @param force If true the returned value is always true.
4371* @returns {boolean} True if both values or objects aren't equal or force is true, false otherwise.
4372*/
4373function checkCache(current, cache, force) {4374if (force)4375return force;4376if (type(current) == TYPES.o && type(cache) == TYPES.o) {4377for (var prop in current) {4378if (prop !== 'c') {4379if (current[LEXICON.hOP](prop) && cache[LEXICON.hOP](prop)) {4380if (checkCache(current[prop], cache[prop]))4381return true;4382}4383else {4384return true;4385}4386}4387}4388}4389else {4390return current !== cache;4391}4392return false;4393}4394
4395
4396//==== Shortcuts ====//4397
4398/**4399* jQuery extend method shortcut with a appended "true" as first argument.
4400*/
4401function extendDeep() {4402return FRAMEWORK.extend.apply(this, [true].concat([].slice.call(arguments)));4403}4404
4405/**4406* jQuery addClass method shortcut.
4407*/
4408function addClass(el, classes) {4409return _frameworkProto.addClass.call(el, classes);4410}4411
4412/**4413* jQuery removeClass method shortcut.
4414*/
4415function removeClass(el, classes) {4416return _frameworkProto.removeClass.call(el, classes);4417}4418
4419/**4420* Adds or removes the given classes dependent on the boolean value. True for add, false for remove.
4421*/
4422function addRemoveClass(el, classes, doAdd) {4423return doAdd ? addClass(el, classes) : removeClass(el, classes);4424}4425
4426/**4427* jQuery remove method shortcut.
4428*/
4429function remove(el) {4430return _frameworkProto.remove.call(el);4431}4432
4433/**4434* Finds the first child element with the given selector of the given element.
4435* @param el The root element from which the selector shall be valid.
4436* @param selector The selector of the searched element.
4437* @returns {*} The first element which is a child of the given element and matches the givens selector.
4438*/
4439function findFirst(el, selector) {4440return _frameworkProto.find.call(el, selector).eq(0);4441}4442
4443
4444//==== API ====//4445
4446/**4447* Puts the instance to sleep. It wont respond to any changes in the DOM and won't update. Scrollbar Interactivity is also disabled as well as the resize handle.
4448* This behavior can be reset by calling the update method.
4449*/
4450_base.sleep = function () {4451_sleeping = true;4452};4453
4454/**4455* Updates the plugin and DOM to the current options.
4456* This method should only be called if a update is 100% required.
4457* @param force True if every property shall be updated and the cache shall be ignored.
4458* !INTERNAL USAGE! : force can be a string "auto", "sync" or "zoom" too
4459* if "auto" then before a real update the content size and host element attributes gets checked, and if they changed only then the update method will be called.
4460* if "sync" then the async update process (MutationObserver or UpdateLoop) gets synchronized and a corresponding update takes place if one was needed due to pending changes.
4461* if "zoom" then a update takes place where it's assumed that content and host size changed
4462* @returns {boolean|undefined}
4463* If force is "sync" then a boolean is returned which indicates whether a update was needed due to pending changes.
4464* If force is "auto" then a boolean is returned whether a update was needed due to attribute or size changes.
4465* undefined otherwise.
4466*/
4467_base.update = function (force) {4468if (_destroyed)4469return;4470
4471var attrsChanged;4472var contentSizeC;4473var isString = type(force) == TYPES.s;4474var doUpdateAuto;4475var mutHost;4476var mutContent;4477
4478if (isString) {4479if (force === _strAuto) {4480attrsChanged = meaningfulAttrsChanged();4481contentSizeC = updateAutoContentSizeChanged();4482doUpdateAuto = attrsChanged || contentSizeC;4483if (doUpdateAuto) {4484update({4485_contentSizeChanged: contentSizeC,4486_changedOptions: _initialized ? undefined : _currentPreparedOptions4487});4488}4489}4490else if (force === _strSync) {4491if (_mutationObserversConnected) {4492mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords());4493mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords());4494}4495else {4496mutHost = _base.update(_strAuto);4497}4498}4499else if (force === 'zoom') {4500update({4501_hostSizeChanged: true,4502_contentSizeChanged: true4503});4504}4505}4506else {4507force = _sleeping || force;4508_sleeping = false;4509if (!_base.update(_strSync) || force)4510update({ _force: force });4511}4512
4513updateElementsOnLoad();4514
4515return doUpdateAuto || mutHost || mutContent;4516};4517
4518/**4519Gets or sets the current options. The update method will be called automatically if new options were set.
4520* @param newOptions If new options are given, then the new options will be set, if new options aren't given (undefined or a not a plain object) then the current options will be returned.
4521* @param value If new options is a property path string, then this value will be used to set the option to which the property path string leads.
4522* @returns {*}
4523*/
4524_base.options = function (newOptions, value) {4525var option = {};4526var changedOps;4527
4528//return current options if newOptions are undefined or empty4529if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) {4530if (type(newOptions) == TYPES.s) {4531if (arguments.length > 1) {4532setObjectPropVal(option, newOptions, value);4533changedOps = setOptions(option);4534}4535else4536return getObjectPropVal(_currentOptions, newOptions);4537}4538else4539return _currentOptions;4540}4541else {4542changedOps = setOptions(newOptions);4543}4544
4545if (!FRAMEWORK.isEmptyObject(changedOps)) {4546update({ _changedOptions: changedOps });4547}4548};4549
4550/**4551* Restore the DOM, disconnects all observers, remove all resize observers and put the instance to sleep.
4552*/
4553_base.destroy = function () {4554if (_destroyed)4555return;4556
4557//remove this instance from auto update loop4558autoUpdateLoop.remove(_base);4559
4560//disconnect all mutation observers4561disconnectMutationObservers();4562
4563//remove all resize observers4564setupResizeObserver(_sizeObserverElement);4565setupResizeObserver(_sizeAutoObserverElement);4566
4567//remove all extensions4568for (var extName in _extensions)4569_base.removeExt(extName);4570
4571//remove all 'destroy' events4572while (_destroyEvents[LEXICON.l] > 0)4573_destroyEvents.pop()();4574
4575//remove all events from host element4576setupHostMouseTouchEvents(true);4577
4578//remove all helper / detection elements4579if (_contentGlueElement)4580remove(_contentGlueElement);4581if (_contentArrangeElement)4582remove(_contentArrangeElement);4583if (_sizeAutoObserverAdded)4584remove(_sizeAutoObserverElement);4585
4586//remove all generated DOM4587setupScrollbarsDOM(true);4588setupScrollbarCornerDOM(true);4589setupStructureDOM(true);4590
4591//remove all generated image load events4592for (var i = 0; i < _updateOnLoadElms[LEXICON.l]; i++)4593FRAMEWORK(_updateOnLoadElms[i]).off(_updateOnLoadEventName, updateOnLoadCallback);4594_updateOnLoadElms = undefined;4595
4596_destroyed = true;4597_sleeping = true;4598
4599//remove this instance from the instances list4600INSTANCES(pluginTargetElement, 0);4601dispatchCallback('onDestroyed');4602
4603//remove all properties and methods4604//for (var property in _base)4605// delete _base[property];4606//_base = undefined;4607};4608
4609/**4610* Scrolls to a given position or element.
4611* @param coordinates
4612* 1. Can be "coordinates" which looks like:
4613* { x : ?, y : ? } OR Object with x and y properties
4614* { left : ?, top : ? } OR Object with left and top properties
4615* { l : ?, t : ? } OR Object with l and t properties
4616* [ ?, ? ] OR Array where the first two element are the coordinates (first is x, second is y)
4617* ? A single value which stays for both axis
4618* A value can be a number, a string or a calculation.
4619*
4620* Operators:
4621* [NONE] The current scroll will be overwritten by the value.
4622* '+=' The value will be added to the current scroll offset
4623* '-=' The value will be subtracted from the current scroll offset
4624* '*=' The current scroll wil be multiplicated by the value.
4625* '/=' The current scroll wil be divided by the value.
4626*
4627* Units:
4628* [NONE] The value is the final scroll amount. final = (value * 1)
4629* 'px' Same as none
4630* '%' The value is dependent on the current scroll value. final = ((currentScrollValue / 100) * value)
4631* 'vw' The value is multiplicated by the viewport width. final = (value * viewportWidth)
4632* 'vh' The value is multiplicated by the viewport height. final = (value * viewportHeight)
4633*
4634* example final values:
4635* 200, '200px', '50%', '1vw', '1vh', '+=200', '/=1vw', '*=2px', '-=5vh', '+=33%', '+= 50% - 2px', '-= 1vw - 50%'
4636*
4637* 2. Can be a HTML or jQuery element:
4638* The final scroll offset is the offset (without margin) of the given HTML / jQuery element.
4639*
4640* 3. Can be a object with a HTML or jQuery element with additional settings:
4641* {
4642* el : [HTMLElement, jQuery element], MUST be specified, else this object isn't valid.
4643* scroll : [string, array, object], Default value is 'always'.
4644* block : [string, array, object], Default value is 'begin'.
4645* margin : [number, boolean, array, object] Default value is false.
4646* }
4647*
4648* Possible scroll settings are:
4649* 'always' Scrolls always.
4650* 'ifneeded' Scrolls only if the element isnt fully in view.
4651* 'never' Scrolls never.
4652*
4653* Possible block settings are:
4654* 'begin' Both axis shall be docked to the "begin" edge. - The element will be docked to the top and left edge of the viewport.
4655* 'end' Both axis shall be docked to the "end" edge. - The element will be docked to the bottom and right edge of the viewport. (If direction is RTL to the bottom and left edge.)
4656* 'center' Both axis shall be docked to "center". - The element will be centered in the viewport.
4657* 'nearest' The element will be docked to the nearest edge(s).
4658*
4659* Possible margin settings are: -- The actual margin of the element wont be affect, this option affects only the final scroll offset.
4660* [BOOLEAN] If true the css margin of the element will be used, if false no margin will be used.
4661* [NUMBER] The margin will be used for all edges.
4662*
4663* @param duration The duration of the scroll animation, OR a jQuery animation configuration object.
4664* @param easing The animation easing.
4665* @param complete The animation complete callback.
4666* @returns {{
4667* position: {x: number, y: number},
4668* ratio: {x: number, y: number},
4669* max: {x: number, y: number},
4670* handleOffset: {x: number, y: number},
4671* handleLength: {x: number, y: number},
4672* handleLengthRatio: {x: number, y: number}, t
4673* rackLength: {x: number, y: number},
4674* isRTL: boolean,
4675* isRTLNormalized: boolean
4676* }}
4677*/
4678_base.scroll = function (coordinates, duration, easing, complete) {4679if (arguments.length === 0 || coordinates === undefined) {4680var infoX = _scrollHorizontalInfo;4681var infoY = _scrollVerticalInfo;4682var normalizeInvert = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.i;4683var normalizeNegate = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.n;4684var scrollX = infoX._currentScroll;4685var scrollXRatio = infoX._currentScrollRatio;4686var maxScrollX = infoX._maxScroll;4687scrollXRatio = normalizeInvert ? 1 - scrollXRatio : scrollXRatio;4688scrollX = normalizeInvert ? maxScrollX - scrollX : scrollX;4689scrollX *= normalizeNegate ? -1 : 1;4690maxScrollX *= normalizeNegate ? -1 : 1;4691
4692return {4693position: {4694x: scrollX,4695y: infoY._currentScroll4696},4697ratio: {4698x: scrollXRatio,4699y: infoY._currentScrollRatio4700},4701max: {4702x: maxScrollX,4703y: infoY._maxScroll4704},4705handleOffset: {4706x: infoX._handleOffset,4707y: infoY._handleOffset4708},4709handleLength: {4710x: infoX._handleLength,4711y: infoY._handleLength4712},4713handleLengthRatio: {4714x: infoX._handleLengthRatio,4715y: infoY._handleLengthRatio4716},4717trackLength: {4718x: infoX._trackLength,4719y: infoY._trackLength4720},4721snappedHandleOffset: {4722x: infoX._snappedHandleOffset,4723y: infoY._snappedHandleOffset4724},4725isRTL: _isRTL,4726isRTLNormalized: _normalizeRTLCache4727};4728}4729
4730_base.update(_strSync);4731
4732var normalizeRTL = _normalizeRTLCache;4733var coordinatesXAxisProps = [_strX, _strLeft, 'l'];4734var coordinatesYAxisProps = [_strY, _strTop, 't'];4735var coordinatesOperators = ['+=', '-=', '*=', '/='];4736var durationIsObject = type(duration) == TYPES.o;4737var completeCallback = durationIsObject ? duration.complete : complete;4738var i;4739var finalScroll = {};4740var specialEasing = {};4741var doScrollLeft;4742var doScrollTop;4743var animationOptions;4744var strEnd = 'end';4745var strBegin = 'begin';4746var strCenter = 'center';4747var strNearest = 'nearest';4748var strAlways = 'always';4749var strNever = 'never';4750var strIfNeeded = 'ifneeded';4751var strLength = LEXICON.l;4752var settingsAxis;4753var settingsScroll;4754var settingsBlock;4755var settingsMargin;4756var finalElement;4757var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx'];4758var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest];4759var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded];4760var coordinatesIsElementObj = coordinates[LEXICON.hOP]('el');4761var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates;4762var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false;4763var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement);4764var updateScrollbarInfos = function () {4765if (doScrollLeft)4766refreshScrollbarHandleOffset(true);4767if (doScrollTop)4768refreshScrollbarHandleOffset(false);4769};4770var proxyCompleteCallback = type(completeCallback) != TYPES.f ? undefined : function () {4771updateScrollbarInfos();4772completeCallback();4773};4774function checkSettingsStringValue(currValue, allowedValues) {4775for (i = 0; i < allowedValues[strLength]; i++) {4776if (currValue === allowedValues[i])4777return true;4778}4779return false;4780}4781function getRawScroll(isX, coordinates) {4782var coordinateProps = isX ? coordinatesXAxisProps : coordinatesYAxisProps;4783coordinates = type(coordinates) == TYPES.s || type(coordinates) == TYPES.n ? [coordinates, coordinates] : coordinates;4784
4785if (COMPATIBILITY.isA(coordinates))4786return isX ? coordinates[0] : coordinates[1];4787else if (type(coordinates) == TYPES.o) {4788//decides RTL normalization "hack" with .n4789//normalizeRTL = type(coordinates.n) == TYPES.b ? coordinates.n : normalizeRTL;4790for (i = 0; i < coordinateProps[strLength]; i++)4791if (coordinateProps[i] in coordinates)4792return coordinates[coordinateProps[i]];4793}4794}4795function getFinalScroll(isX, rawScroll) {4796var isString = type(rawScroll) == TYPES.s;4797var operator;4798var amount;4799var scrollInfo = isX ? _scrollHorizontalInfo : _scrollVerticalInfo;4800var currScroll = scrollInfo._currentScroll;4801var maxScroll = scrollInfo._maxScroll;4802var mult = ' * ';4803var finalValue;4804var isRTLisX = _isRTL && isX;4805var normalizeShortcuts = isRTLisX && _rtlScrollBehavior.n && !normalizeRTL;4806var strReplace = 'replace';4807var evalFunc = eval;4808var possibleOperator;4809if (isString) {4810//check operator4811if (rawScroll[strLength] > 2) {4812possibleOperator = rawScroll.substr(0, 2);4813if (inArray(possibleOperator, coordinatesOperators) > -1)4814operator = possibleOperator;4815}4816
4817//calculate units and shortcuts4818rawScroll = operator ? rawScroll.substr(2) : rawScroll;4819rawScroll = rawScroll4820[strReplace](/min/g, 0) //'min' = 0%4821[strReplace](/</g, 0) //'<' = 0%4822[strReplace](/max/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'max' = 100%4823[strReplace](/>/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'>' = 100%4824[strReplace](/px/g, _strEmpty)4825[strReplace](/%/g, mult + (maxScroll * (isRTLisX && _rtlScrollBehavior.n ? -1 : 1) / 100.0))4826[strReplace](/vw/g, mult + _viewportSize.w)4827[strReplace](/vh/g, mult + _viewportSize.h);4828amount = parseToZeroOrNumber(isNaN(rawScroll) ? parseToZeroOrNumber(evalFunc(rawScroll), true).toFixed() : rawScroll);4829}4830else {4831amount = rawScroll;4832}4833
4834if (amount !== undefined && !isNaN(amount) && type(amount) == TYPES.n) {4835var normalizeIsRTLisX = normalizeRTL && isRTLisX;4836var operatorCurrScroll = currScroll * (normalizeIsRTLisX && _rtlScrollBehavior.n ? -1 : 1);4837var invert = normalizeIsRTLisX && _rtlScrollBehavior.i;4838var negate = normalizeIsRTLisX && _rtlScrollBehavior.n;4839operatorCurrScroll = invert ? (maxScroll - operatorCurrScroll) : operatorCurrScroll;4840switch (operator) {4841case '+=':4842finalValue = operatorCurrScroll + amount;4843break;4844case '-=':4845finalValue = operatorCurrScroll - amount;4846break;4847case '*=':4848finalValue = operatorCurrScroll * amount;4849break;4850case '/=':4851finalValue = operatorCurrScroll / amount;4852break;4853default:4854finalValue = amount;4855break;4856}4857finalValue = invert ? maxScroll - finalValue : finalValue;4858finalValue *= negate ? -1 : 1;4859finalValue = isRTLisX && _rtlScrollBehavior.n ? MATH.min(0, MATH.max(maxScroll, finalValue)) : MATH.max(0, MATH.min(maxScroll, finalValue));4860}4861return finalValue === currScroll ? undefined : finalValue;4862}4863function getPerAxisValue(value, valueInternalType, defaultValue, allowedValues) {4864var resultDefault = [defaultValue, defaultValue];4865var valueType = type(value);4866var valueArrLength;4867var valueArrItem;4868
4869//value can be [ string, or array of two strings ]4870if (valueType == valueInternalType) {4871value = [value, value];4872}4873else if (valueType == TYPES.a) {4874valueArrLength = value[strLength];4875if (valueArrLength > 2 || valueArrLength < 1)4876value = resultDefault;4877else {4878if (valueArrLength === 1)4879value[1] = defaultValue;4880for (i = 0; i < valueArrLength; i++) {4881valueArrItem = value[i];4882if (type(valueArrItem) != valueInternalType || !checkSettingsStringValue(valueArrItem, allowedValues)) {4883value = resultDefault;4884break;4885}4886}4887}4888}4889else if (valueType == TYPES.o)4890value = [value[_strX] || defaultValue, value[_strY] || defaultValue];4891else4892value = resultDefault;4893return { x: value[0], y: value[1] };4894}4895function generateMargin(marginTopRightBottomLeftArray) {4896var result = [];4897var currValue;4898var currValueType;4899var valueDirections = [_strTop, _strRight, _strBottom, _strLeft];4900for (i = 0; i < marginTopRightBottomLeftArray[strLength]; i++) {4901if (i === valueDirections[strLength])4902break;4903currValue = marginTopRightBottomLeftArray[i];4904currValueType = type(currValue);4905if (currValueType == TYPES.b)4906result.push(currValue ? parseToZeroOrNumber(finalElement.css(_strMarginMinus + valueDirections[i])) : 0);4907else4908result.push(currValueType == TYPES.n ? currValue : 0);4909}4910return result;4911}4912
4913if (possibleElementIsJQuery || possibleElementIsHTMLElement) {4914//get settings4915var margin = coordinatesIsElementObj ? coordinates.margin : 0;4916var axis = coordinatesIsElementObj ? coordinates.axis : 0;4917var scroll = coordinatesIsElementObj ? coordinates.scroll : 0;4918var block = coordinatesIsElementObj ? coordinates.block : 0;4919var marginDefault = [0, 0, 0, 0];4920var marginType = type(margin);4921var marginLength;4922finalElement = possibleElementIsJQuery ? possibleElement : FRAMEWORK(possibleElement);4923
4924if (finalElement[strLength] > 0) {4925//margin can be [ boolean, number, array of 2, array of 4, object ]4926if (marginType == TYPES.n || marginType == TYPES.b)4927margin = generateMargin([margin, margin, margin, margin]);4928else if (marginType == TYPES.a) {4929marginLength = margin[strLength];4930if (marginLength === 2)4931margin = generateMargin([margin[0], margin[1], margin[0], margin[1]]);4932else if (marginLength >= 4)4933margin = generateMargin(margin);4934else4935margin = marginDefault;4936}4937else if (marginType == TYPES.o)4938margin = generateMargin([margin[_strTop], margin[_strRight], margin[_strBottom], margin[_strLeft]]);4939else4940margin = marginDefault;4941
4942//block = type(block) === TYPES.b ? block ? [ strNearest, strBegin ] : [ strNearest, strEnd ] : block;4943settingsAxis = checkSettingsStringValue(axis, elementObjSettingsAxisValues) ? axis : 'xy';4944settingsScroll = getPerAxisValue(scroll, TYPES.s, strAlways, elementObjSettingsScrollValues);4945settingsBlock = getPerAxisValue(block, TYPES.s, strBegin, elementObjSettingsBlockValues);4946settingsMargin = margin;4947
4948var viewportScroll = {4949l: _scrollHorizontalInfo._currentScroll,4950t: _scrollVerticalInfo._currentScroll4951};4952// use padding element instead of viewport element because padding element has never padding, margin or position applied.4953var viewportOffset = _paddingElement.offset();4954
4955//get coordinates4956var elementOffset = finalElement.offset();4957var doNotScroll = {4958x: settingsScroll.x == strNever || settingsAxis == _strY,4959y: settingsScroll.y == strNever || settingsAxis == _strX4960};4961elementOffset[_strTop] -= settingsMargin[0];4962elementOffset[_strLeft] -= settingsMargin[3];4963var elementScrollCoordinates = {4964x: MATH.round(elementOffset[_strLeft] - viewportOffset[_strLeft] + viewportScroll.l),4965y: MATH.round(elementOffset[_strTop] - viewportOffset[_strTop] + viewportScroll.t)4966};4967if (_isRTL) {4968if (!_rtlScrollBehavior.n && !_rtlScrollBehavior.i)4969elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + viewportScroll.l);4970if (_rtlScrollBehavior.n && normalizeRTL)4971elementScrollCoordinates.x *= -1;4972if (_rtlScrollBehavior.i && normalizeRTL)4973elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + (_scrollHorizontalInfo._maxScroll - viewportScroll.l));4974}4975
4976//measuring is required4977if (settingsBlock.x != strBegin || settingsBlock.y != strBegin || settingsScroll.x == strIfNeeded || settingsScroll.y == strIfNeeded || _isRTL) {4978var measuringElm = finalElement[0];4979var rawElementSize = _supportTransform ? measuringElm[LEXICON.bCR]() : {4980width: measuringElm[LEXICON.oW],4981height: measuringElm[LEXICON.oH]4982};4983var elementSize = {4984w: rawElementSize[_strWidth] + settingsMargin[3] + settingsMargin[1],4985h: rawElementSize[_strHeight] + settingsMargin[0] + settingsMargin[2]4986};4987var finalizeBlock = function (isX) {4988var vars = getScrollbarVars(isX);4989var wh = vars._w_h;4990var lt = vars._left_top;4991var xy = vars._x_y;4992var blockIsEnd = settingsBlock[xy] == (isX ? _isRTL ? strBegin : strEnd : strEnd);4993var blockIsCenter = settingsBlock[xy] == strCenter;4994var blockIsNearest = settingsBlock[xy] == strNearest;4995var scrollNever = settingsScroll[xy] == strNever;4996var scrollIfNeeded = settingsScroll[xy] == strIfNeeded;4997var vpSize = _viewportSize[wh];4998var vpOffset = viewportOffset[lt];4999var elSize = elementSize[wh];5000var elOffset = elementOffset[lt];5001var divide = blockIsCenter ? 2 : 1;5002var elementCenterOffset = elOffset + (elSize / 2);5003var viewportCenterOffset = vpOffset + (vpSize / 2);5004var isInView =5005elSize <= vpSize5006&& elOffset >= vpOffset5007&& elOffset + elSize <= vpOffset + vpSize;5008
5009if (scrollNever)5010doNotScroll[xy] = true;5011else if (!doNotScroll[xy]) {5012if (blockIsNearest || scrollIfNeeded) {5013doNotScroll[xy] = scrollIfNeeded ? isInView : false;5014blockIsEnd = elSize < vpSize ? elementCenterOffset > viewportCenterOffset : elementCenterOffset < viewportCenterOffset;5015}5016elementScrollCoordinates[xy] -= blockIsEnd || blockIsCenter ? ((vpSize / divide) - (elSize / divide)) * (isX && _isRTL && normalizeRTL ? -1 : 1) : 0;5017}5018};5019finalizeBlock(true);5020finalizeBlock(false);5021}5022
5023if (doNotScroll.y)5024delete elementScrollCoordinates.y;5025if (doNotScroll.x)5026delete elementScrollCoordinates.x;5027
5028coordinates = elementScrollCoordinates;5029}5030}5031
5032finalScroll[_strScrollLeft] = getFinalScroll(true, getRawScroll(true, coordinates));5033finalScroll[_strScrollTop] = getFinalScroll(false, getRawScroll(false, coordinates));5034doScrollLeft = finalScroll[_strScrollLeft] !== undefined;5035doScrollTop = finalScroll[_strScrollTop] !== undefined;5036
5037if ((doScrollLeft || doScrollTop) && (duration > 0 || durationIsObject)) {5038if (durationIsObject) {5039duration.complete = proxyCompleteCallback;5040_viewportElement.animate(finalScroll, duration);5041}5042else {5043animationOptions = {5044duration: duration,5045complete: proxyCompleteCallback5046};5047if (COMPATIBILITY.isA(easing) || FRAMEWORK.isPlainObject(easing)) {5048specialEasing[_strScrollLeft] = easing[0] || easing.x;5049specialEasing[_strScrollTop] = easing[1] || easing.y;5050animationOptions.specialEasing = specialEasing;5051}5052else {5053animationOptions.easing = easing;5054}5055_viewportElement.animate(finalScroll, animationOptions);5056}5057}5058else {5059if (doScrollLeft)5060_viewportElement[_strScrollLeft](finalScroll[_strScrollLeft]);5061if (doScrollTop)5062_viewportElement[_strScrollTop](finalScroll[_strScrollTop]);5063updateScrollbarInfos();5064}5065};5066
5067/**5068* Stops all scroll animations.
5069* @returns {*} The current OverlayScrollbars instance (for chaining).
5070*/
5071_base.scrollStop = function (param1, param2, param3) {5072_viewportElement.stop(param1, param2, param3);5073return _base;5074};5075
5076/**5077* Returns all relevant elements.
5078* @param elementName The name of the element which shall be returned.
5079* @returns {{target: *, host: *, padding: *, viewport: *, content: *, scrollbarHorizontal: {scrollbar: *, track: *, handle: *}, scrollbarVertical: {scrollbar: *, track: *, handle: *}, scrollbarCorner: *} | *}
5080*/
5081_base.getElements = function (elementName) {5082var obj = {5083target: _targetElementNative,5084host: _hostElementNative,5085padding: _paddingElementNative,5086viewport: _viewportElementNative,5087content: _contentElementNative,5088scrollbarHorizontal: {5089scrollbar: _scrollbarHorizontalElement[0],5090track: _scrollbarHorizontalTrackElement[0],5091handle: _scrollbarHorizontalHandleElement[0]5092},5093scrollbarVertical: {5094scrollbar: _scrollbarVerticalElement[0],5095track: _scrollbarVerticalTrackElement[0],5096handle: _scrollbarVerticalHandleElement[0]5097},5098scrollbarCorner: _scrollbarCornerElement[0]5099};5100return type(elementName) == TYPES.s ? getObjectPropVal(obj, elementName) : obj;5101};5102
5103/**5104* Returns a object which describes the current state of this instance.
5105* @param stateProperty A specific property from the state object which shall be returned.
5106* @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *}
5107*/
5108_base.getState = function (stateProperty) {5109function prepare(obj) {5110if (!FRAMEWORK.isPlainObject(obj))5111return obj;5112var extended = extendDeep({}, obj);5113var changePropertyName = function (from, to) {5114if (extended[LEXICON.hOP](from)) {5115extended[to] = extended[from];5116delete extended[from];5117}5118};5119changePropertyName('w', _strWidth); //change w to width5120changePropertyName('h', _strHeight); //change h to height5121delete extended.c; //delete c (the 'changed' prop)5122return extended;5123};5124var obj = {5125destroyed: !!prepare(_destroyed),5126sleeping: !!prepare(_sleeping),5127autoUpdate: prepare(!_mutationObserversConnected),5128widthAuto: prepare(_widthAutoCache),5129heightAuto: prepare(_heightAutoCache),5130padding: prepare(_cssPaddingCache),5131overflowAmount: prepare(_overflowAmountCache),5132hideOverflow: prepare(_hideOverflowCache),5133hasOverflow: prepare(_hasOverflowCache),5134contentScrollSize: prepare(_contentScrollSizeCache),5135viewportSize: prepare(_viewportSize),5136hostSize: prepare(_hostSizeCache),5137documentMixed: prepare(_documentMixed)5138};5139return type(stateProperty) == TYPES.s ? getObjectPropVal(obj, stateProperty) : obj;5140};5141
5142/**5143* Gets all or specific extension instance.
5144* @param extName The name of the extension from which the instance shall be got.
5145* @returns {{}} The instance of the extension with the given name or undefined if the instance couldn't be found.
5146*/
5147_base.ext = function (extName) {5148var result;5149var privateMethods = _extensionsPrivateMethods.split(' ');5150var i = 0;5151if (type(extName) == TYPES.s) {5152if (_extensions[LEXICON.hOP](extName)) {5153result = extendDeep({}, _extensions[extName]);5154for (; i < privateMethods.length; i++)5155delete result[privateMethods[i]];5156}5157}5158else {5159result = {};5160for (i in _extensions)5161result[i] = extendDeep({}, _base.ext(i));5162}5163return result;5164};5165
5166/**5167* Adds a extension to this instance.
5168* @param extName The name of the extension which shall be added.
5169* @param extensionOptions The extension options which shall be used.
5170* @returns {{}} The instance of the added extension or undefined if the extension couldn't be added properly.
5171*/
5172_base.addExt = function (extName, extensionOptions) {5173var registeredExtensionObj = _plugin.extension(extName);5174var instance;5175var instanceAdded;5176var instanceContract;5177var contractResult;5178var contractFulfilled = true;5179if (registeredExtensionObj) {5180if (!_extensions[LEXICON.hOP](extName)) {5181instance = registeredExtensionObj.extensionFactory.call(_base,5182extendDeep({}, registeredExtensionObj.defaultOptions),5183FRAMEWORK,5184COMPATIBILITY);5185
5186if (instance) {5187instanceContract = instance.contract;5188if (type(instanceContract) == TYPES.f) {5189contractResult = instanceContract(window);5190contractFulfilled = type(contractResult) == TYPES.b ? contractResult : contractFulfilled;5191}5192if (contractFulfilled) {5193_extensions[extName] = instance;5194instanceAdded = instance.added;5195if (type(instanceAdded) == TYPES.f)5196instanceAdded(extensionOptions);5197
5198return _base.ext(extName);5199}5200}5201}5202else5203return _base.ext(extName);5204}5205else5206console.warn("A extension with the name \"" + extName + "\" isn't registered.");5207};5208
5209/**5210* Removes a extension from this instance.
5211* @param extName The name of the extension which shall be removed.
5212* @returns {boolean} True if the extension was removed, false otherwise e.g. if the extension wasn't added before.
5213*/
5214_base.removeExt = function (extName) {5215var instance = _extensions[extName];5216var instanceRemoved;5217if (instance) {5218delete _extensions[extName];5219
5220instanceRemoved = instance.removed;5221if (type(instanceRemoved) == TYPES.f)5222instanceRemoved();5223
5224return true;5225}5226return false;5227};5228
5229/**5230* Constructs the plugin.
5231* @param targetElement The element to which the plugin shall be applied.
5232* @param options The initial options of the plugin.
5233* @param extensions The extension(s) which shall be added right after the initialization.
5234* @returns {boolean} True if the plugin was successfully initialized, false otherwise.
5235*/
5236function construct(targetElement, options, extensions) {5237_defaultOptions = globals.defaultOptions;5238_nativeScrollbarStyling = globals.nativeScrollbarStyling;5239_nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);5240_nativeScrollbarIsOverlaid = extendDeep({}, globals.nativeScrollbarIsOverlaid);5241_overlayScrollbarDummySize = extendDeep({}, globals.overlayScrollbarDummySize);5242_rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior);5243
5244//parse & set options but don't update5245setOptions(extendDeep({}, _defaultOptions, options));5246
5247_cssCalc = globals.cssCalc;5248_msieVersion = globals.msie;5249_autoUpdateRecommended = globals.autoUpdateRecommended;5250_supportTransition = globals.supportTransition;5251_supportTransform = globals.supportTransform;5252_supportPassiveEvents = globals.supportPassiveEvents;5253_supportResizeObserver = globals.supportResizeObserver;5254_supportMutationObserver = globals.supportMutationObserver;5255_restrictedMeasuring = globals.restrictedMeasuring;5256_documentElement = FRAMEWORK(targetElement.ownerDocument);5257_documentElementNative = _documentElement[0];5258_windowElement = FRAMEWORK(_documentElementNative.defaultView || _documentElementNative.parentWindow);5259_windowElementNative = _windowElement[0];5260_htmlElement = findFirst(_documentElement, 'html');5261_bodyElement = findFirst(_htmlElement, 'body');5262_targetElement = FRAMEWORK(targetElement);5263_targetElementNative = _targetElement[0];5264_isTextarea = _targetElement.is('textarea');5265_isBody = _targetElement.is('body');5266_documentMixed = _documentElementNative !== document;5267
5268/* On a div Element The if checks only whether:5269* - the targetElement has the class "os-host"
5270* - the targetElement has a a child with the class "os-padding"
5271*
5272* If that's the case, its assumed the DOM has already the following structure:
5273* (The ".os-host" element is the targetElement)
5274*
5275* <div class="os-host">
5276* <div class="os-resize-observer-host"></div>
5277* <div class="os-padding">
5278* <div class="os-viewport">
5279* <div class="os-content"></div>
5280* </div>
5281* </div>
5282* <div class="os-scrollbar os-scrollbar-horizontal ">
5283* <div class="os-scrollbar-track">
5284* <div class="os-scrollbar-handle"></div>
5285* </div>
5286* </div>
5287* <div class="os-scrollbar os-scrollbar-vertical">
5288* <div class="os-scrollbar-track">
5289* <div class="os-scrollbar-handle"></div>
5290* </div>
5291* </div>
5292* <div class="os-scrollbar-corner"></div>
5293* </div>
5294*
5295* =====================================================================================
5296*
5297* On a Textarea Element The if checks only whether:
5298* - the targetElement has the class "os-textarea"
5299* - the targetElement is inside a element with the class "os-content"
5300*
5301* If that's the case, its assumed the DOM has already the following structure:
5302* (The ".os-textarea" (textarea) element is the targetElement)
5303*
5304* <div class="os-host-textarea">
5305* <div class="os-resize-observer-host"></div>
5306* <div class="os-padding os-text-inherit">
5307* <div class="os-viewport os-text-inherit">
5308* <div class="os-content os-text-inherit">
5309* <div class="os-textarea-cover"></div>
5310* <textarea class="os-textarea os-text-inherit"></textarea>
5311* </div>
5312* </div>
5313* </div>
5314* <div class="os-scrollbar os-scrollbar-horizontal ">
5315* <div class="os-scrollbar-track">
5316* <div class="os-scrollbar-handle"></div>
5317* </div>
5318* </div>
5319* <div class="os-scrollbar os-scrollbar-vertical">
5320* <div class="os-scrollbar-track">
5321* <div class="os-scrollbar-handle"></div>
5322* </div>
5323* </div>
5324* <div class="os-scrollbar-corner"></div>
5325* </div>
5326*/
5327_domExists = _isTextarea5328? _targetElement.hasClass(_classNameTextareaElement) && _targetElement.parent().hasClass(_classNameContentElement)5329: _targetElement.hasClass(_classNameHostElement) && _targetElement.children(_strDot + _classNamePaddingElement)[LEXICON.l];5330
5331var initBodyScroll;5332var bodyMouseTouchDownListener;5333
5334//check if the plugin hasn't to be initialized5335if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) {5336dispatchCallback('onInitializationWithdrawn');5337if (_domExists) {5338setupStructureDOM(true);5339setupScrollbarsDOM(true);5340setupScrollbarCornerDOM(true);5341}5342
5343_destroyed = true;5344_sleeping = true;5345
5346return _base;5347}5348
5349if (_isBody) {5350initBodyScroll = {};5351initBodyScroll.l = MATH.max(_targetElement[_strScrollLeft](), _htmlElement[_strScrollLeft](), _windowElement[_strScrollLeft]());5352initBodyScroll.t = MATH.max(_targetElement[_strScrollTop](), _htmlElement[_strScrollTop](), _windowElement[_strScrollTop]());5353
5354bodyMouseTouchDownListener = function () {5355_viewportElement.removeAttr(LEXICON.ti);5356setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, true, true);5357}5358}5359
5360//build OverlayScrollbars DOM5361setupStructureDOM();5362setupScrollbarsDOM();5363setupScrollbarCornerDOM();5364
5365//create OverlayScrollbars events5366setupStructureEvents();5367setupScrollbarEvents(true);5368setupScrollbarEvents(false);5369setupScrollbarCornerEvents();5370
5371//create mutation observers5372createMutationObservers();5373
5374//build resize observer for the host element5375setupResizeObserver(_sizeObserverElement, hostOnResized);5376
5377if (_isBody) {5378//apply the body scroll to handle it right in the update method5379_viewportElement[_strScrollLeft](initBodyScroll.l)[_strScrollTop](initBodyScroll.t);5380
5381//set the focus on the viewport element so you dont have to click on the page to use keyboard keys (up / down / space) for scrolling5382if (document.activeElement == targetElement && _viewportElementNative.focus) {5383//set a tabindex to make the viewportElement focusable5384_viewportElement.attr(LEXICON.ti, '-1');5385_viewportElementNative.focus();5386
5387/* the tabindex has to be removed due to;5388* If you set the tabindex attribute on an <div>, then its child content cannot be scrolled with the arrow keys unless you set tabindex on the content, too
5389* https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
5390*/
5391setupResponsiveEventListener(_viewportElement, _strMouseTouchDownEvent, bodyMouseTouchDownListener, false, true);5392}5393}5394
5395//update for the first time & initialize cache5396_base.update(_strAuto);5397
5398//the plugin is initialized now!5399_initialized = true;5400dispatchCallback('onInitialized');5401
5402//call all callbacks which would fire before the initialized was complete5403each(_callbacksInitQeueue, function (index, value) { dispatchCallback(value.n, value.a); });5404_callbacksInitQeueue = [];5405
5406//add extensions5407if (type(extensions) == TYPES.s)5408extensions = [extensions];5409if (COMPATIBILITY.isA(extensions))5410each(extensions, function (index, value) { _base.addExt(value); });5411else if (FRAMEWORK.isPlainObject(extensions))5412each(extensions, function (key, value) { _base.addExt(key, value); });5413
5414//add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions)5415setTimeout(function () {5416if (_supportTransition && !_destroyed)5417addClass(_hostElement, _classNameHostTransition);5418}, 333);5419
5420return _base;5421}5422
5423if (_plugin.valid(construct(pluginTargetElement, options, extensions))) {5424INSTANCES(pluginTargetElement, _base);5425}5426
5427return _base;5428}5429
5430/**5431* Initializes a new OverlayScrollbarsInstance object or changes options if already initialized or returns the current instance.
5432* @param pluginTargetElements The elements to which the Plugin shall be initialized.
5433* @param options The custom options with which the plugin shall be initialized.
5434* @param extensions The extension(s) which shall be added right after initialization.
5435* @returns {*}
5436*/
5437_plugin = window[PLUGINNAME] = function (pluginTargetElements, options, extensions) {5438if (arguments[LEXICON.l] === 0)5439return this;5440
5441var arr = [];5442var optsIsPlainObj = FRAMEWORK.isPlainObject(options);5443var inst;5444var result;5445
5446//pluginTargetElements is null or undefined5447if (!pluginTargetElements)5448return optsIsPlainObj || !options ? result : arr;5449
5450/*5451pluginTargetElements will be converted to:
54521. A jQueryElement Array
54532. A HTMLElement Array
54543. A Array with a single HTML Element
5455so pluginTargetElements is always a array.
5456*/
5457pluginTargetElements = pluginTargetElements[LEXICON.l] != undefined ? pluginTargetElements : [pluginTargetElements[0] || pluginTargetElements];5458initOverlayScrollbarsStatics();5459
5460if (pluginTargetElements[LEXICON.l] > 0) {5461if (optsIsPlainObj) {5462FRAMEWORK.each(pluginTargetElements, function (i, v) {5463inst = v;5464if (inst !== undefined)5465arr.push(OverlayScrollbarsInstance(inst, options, extensions, _pluginsGlobals, _pluginsAutoUpdateLoop));5466});5467}5468else {5469FRAMEWORK.each(pluginTargetElements, function (i, v) {5470inst = INSTANCES(v);5471if ((options === '!' && _plugin.valid(inst)) || (COMPATIBILITY.type(options) == TYPES.f && options(v, inst)))5472arr.push(inst);5473else if (options === undefined)5474arr.push(inst);5475});5476}5477result = arr[LEXICON.l] === 1 ? arr[0] : arr;5478}5479return result;5480};5481
5482/**5483* Returns a object which contains global information about the plugin and each instance of it.
5484* The returned object is just a copy, that means that changes to the returned object won't have any effect to the original object.
5485*/
5486_plugin.globals = function () {5487initOverlayScrollbarsStatics();5488var globals = FRAMEWORK.extend(true, {}, _pluginsGlobals);5489delete globals['msie'];5490return globals;5491};5492
5493/**5494* Gets or Sets the default options for each new plugin initialization.
5495* @param newDefaultOptions The object with which the default options shall be extended.
5496*/
5497_plugin.defaultOptions = function (newDefaultOptions) {5498initOverlayScrollbarsStatics();5499var currDefaultOptions = _pluginsGlobals.defaultOptions;5500if (newDefaultOptions === undefined)5501return FRAMEWORK.extend(true, {}, currDefaultOptions);5502
5503//set the new default options5504_pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, {}, currDefaultOptions, _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true, currDefaultOptions)._default);5505};5506
5507/**5508* Checks whether the passed instance is a non-destroyed OverlayScrollbars instance.
5509* @param osInstance The potential OverlayScrollbars instance which shall be checked.
5510* @returns {boolean} True if the passed value is a non-destroyed OverlayScrollbars instance, false otherwise.
5511*/
5512_plugin.valid = function (osInstance) {5513return osInstance instanceof _plugin && !osInstance.getState().destroyed;5514};5515
5516/**5517* Registers, Unregisters or returns a extension.
5518* Register: Pass the name and the extension. (defaultOptions is optional)
5519* Unregister: Pass the name and anything except a function as extension parameter.
5520* Get extension: Pass the name of the extension which shall be got.
5521* Get all extensions: Pass no arguments.
5522* @param extensionName The name of the extension which shall be registered, unregistered or returned.
5523* @param extension A function which generates the instance of the extension or anything other to remove a already registered extension.
5524* @param defaultOptions The default options which shall be used for the registered extension.
5525*/
5526_plugin.extension = function (extensionName, extension, defaultOptions) {5527var extNameTypeString = COMPATIBILITY.type(extensionName) == TYPES.s;5528var argLen = arguments[LEXICON.l];5529var i = 0;5530if (argLen < 1 || !extNameTypeString) {5531//return a copy of all extension objects5532return FRAMEWORK.extend(true, { length: _pluginsExtensions[LEXICON.l] }, _pluginsExtensions);5533}5534else if (extNameTypeString) {5535if (COMPATIBILITY.type(extension) == TYPES.f) {5536//register extension5537_pluginsExtensions.push({5538name: extensionName,5539extensionFactory: extension,5540defaultOptions: defaultOptions5541});5542}5543else {5544for (; i < _pluginsExtensions[LEXICON.l]; i++) {5545if (_pluginsExtensions[i].name === extensionName) {5546if (argLen > 1)5547_pluginsExtensions.splice(i, 1); //remove extension5548else5549return FRAMEWORK.extend(true, {}, _pluginsExtensions[i]); //return extension with the given name5550}5551}5552}5553}5554};5555
5556return _plugin;5557})();5558
5559if (JQUERY && JQUERY.fn) {5560/**5561* The jQuery initialization interface.
5562* @param options The initial options for the construction of the plugin. To initialize the plugin, this option has to be a object! If it isn't a object, the instance(s) are returned and the plugin wont be initialized.
5563* @param extensions The extension(s) which shall be added right after initialization.
5564* @returns {*} After initialization it returns the jQuery element array, else it returns the instance(s) of the elements which are selected.
5565*/
5566JQUERY.fn.overlayScrollbars = function (options, extensions) {5567var _elements = this;5568if (JQUERY.isPlainObject(options)) {5569JQUERY.each(_elements, function () { PLUGIN(this, options, extensions); });5570return _elements;5571}5572else5573return PLUGIN(_elements, options);5574};5575}5576return PLUGIN;5577}5578));