jquery.overlayScrollbars.js 295 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295
  1. /*!
  2. * OverlayScrollbars
  3. * https://github.com/KingSora/OverlayScrollbars
  4. *
  5. * Version: 1.7.1
  6. *
  7. * Copyright KingSora.
  8. * https://github.com/KingSora
  9. *
  10. * Released under the MIT license.
  11. * Date: 22.05.2019
  12. */
  13. (function (global, factory) {
  14. if (typeof define === 'function' && define.amd)
  15. define(['jquery'], function(framework) { return factory(global, global.document, undefined, framework); });
  16. else if (typeof module === 'object' && typeof module.exports === 'object')
  17. module.exports = factory(global, global.document, undefined, require('jquery'));
  18. else
  19. factory(global, global.document, undefined, global.jQuery);
  20. }(typeof window !== 'undefined' ? window : this,
  21. function(window, document, undefined, framework) {
  22. 'use strict';
  23. var PLUGINNAME = 'OverlayScrollbars';
  24. var TYPES = {
  25. o : 'object',
  26. f : 'function',
  27. a : 'array',
  28. s : 'string',
  29. b : 'boolean',
  30. n : 'number',
  31. u : 'undefined',
  32. z : 'null'
  33. //d : 'date',
  34. //e : 'error',
  35. //r : 'regexp',
  36. //y : 'symbol'
  37. };
  38. var LEXICON = {
  39. c : 'class',
  40. s : 'style',
  41. i : 'id',
  42. l : 'length',
  43. p : 'prototype',
  44. oH : 'offsetHeight',
  45. cH : 'clientHeight',
  46. sH : 'scrollHeight',
  47. oW : 'offsetWidth',
  48. cW : 'clientWidth',
  49. sW : 'scrollWidth'
  50. };
  51. var VENDORS = {
  52. //https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix
  53. _jsCache : { },
  54. _cssCache : { },
  55. _cssPrefixes : ['-webkit-', '-moz-', '-o-', '-ms-'],
  56. _jsPrefixes : ['WebKit', 'Moz', 'O', 'MS'],
  57. _cssProperty : function(name) {
  58. var cache = this._cssCache;
  59. if(cache[name])
  60. return cache[name];
  61. var prefixes = this._cssPrefixes;
  62. var uppercasedName = this._firstLetterToUpper(name);
  63. var elmStyle = document.createElement('div')[LEXICON.s];
  64. var resultPossibilities;
  65. var i = 0;
  66. var v = 0;
  67. var currVendorWithoutDashes;
  68. for (; i < prefixes.length; i++) {
  69. currVendorWithoutDashes = prefixes[i].replace(/-/g, '');
  70. resultPossibilities = [
  71. name, //transition
  72. prefixes[i] + name, //-webkit-transition
  73. currVendorWithoutDashes + uppercasedName, //webkitTransition
  74. this._firstLetterToUpper(currVendorWithoutDashes) + uppercasedName //WebkitTransition
  75. ];
  76. for(v = 0; v < resultPossibilities[LEXICON.l]; v++) {
  77. if(elmStyle[resultPossibilities[v]] !== undefined) {
  78. cache[name] = resultPossibilities[v];
  79. return resultPossibilities[v];
  80. }
  81. }
  82. }
  83. return null;
  84. },
  85. _jsAPI : function(name, isInterface, fallback) {
  86. var prefixes = this._jsPrefixes;
  87. var cache = this._jsCache;
  88. var i = 0;
  89. var result = cache[name];
  90. if(!result) {
  91. result = window[name];
  92. for(; i < prefixes[LEXICON.l]; i++)
  93. result = result || window[(isInterface ? prefixes[i] : prefixes[i].toLowerCase()) + this._firstLetterToUpper(name)];
  94. cache[name] = result;
  95. }
  96. return result || fallback;
  97. },
  98. _firstLetterToUpper : function(str) {
  99. return str.charAt(0).toUpperCase() + str.slice(1);
  100. }
  101. };
  102. var COMPATIBILITY = {
  103. /**
  104. * Gets the current window width.
  105. * @returns {Number|number} The current window width in pixel.
  106. */
  107. wW: function() {
  108. return window.innerWidth || document.documentElement[LEXICON.cW] || document.body[LEXICON.cW];
  109. },
  110. /**
  111. * Gets the current window height.
  112. * @returns {Number|number} The current window height in pixel.
  113. */
  114. wH: function() {
  115. return window.innerHeight || document.documentElement[LEXICON.cH] || document.body[LEXICON.cH];
  116. },
  117. /**
  118. * Gets the MutationObserver Object or undefined if not supported.
  119. * @returns {MutationObserver|*|undefined} The MutationsObserver Object or undefined.
  120. */
  121. mO: function() {
  122. return VENDORS._jsAPI('MutationObserver', true);
  123. },
  124. /**
  125. * Gets the ResizeObserver Object or undefined if not supported.
  126. * @returns {MutationObserver|*|undefined} The ResizeObserver Object or undefined.
  127. */
  128. rO: function() {
  129. return VENDORS._jsAPI('ResizeObserver', true);
  130. },
  131. /**
  132. * Gets the RequestAnimationFrame method or it's corresponding polyfill.
  133. * @returns {*|Function} The RequestAnimationFrame method or it's corresponding polyfill.
  134. */
  135. rAF: function() {
  136. return VENDORS._jsAPI('requestAnimationFrame', false, function (func) { return window.setTimeout(func, 1000 / 60); });
  137. },
  138. /**
  139. * Gets the CancelAnimationFrame method or it's corresponding polyfill.
  140. * @returns {*|Function} The CancelAnimationFrame method or it's corresponding polyfill.
  141. */
  142. cAF: function() {
  143. return VENDORS._jsAPI('cancelAnimationFrame', false, function (id) { return window.clearTimeout(id); });
  144. },
  145. /**
  146. * Gets the current time.
  147. * @returns {number} The current time.
  148. */
  149. now: function() {
  150. return Date.now && Date.now() || new Date().getTime();
  151. },
  152. /**
  153. * Stops the propagation of the given event.
  154. * @param event The event of which the propagation shall be stoped.
  155. */
  156. stpP: function(event) {
  157. if(event.stopPropagation)
  158. event.stopPropagation();
  159. else
  160. event.cancelBubble = true;
  161. },
  162. /**
  163. * Prevents the default action of the given event.
  164. * @param event The event of which the default action shall be prevented.
  165. */
  166. prvD: function(event) {
  167. if(event.preventDefault && event.cancelable)
  168. event.preventDefault();
  169. else
  170. event.returnValue = false;
  171. },
  172. /**
  173. * Gets the pageX and pageY values of the given mouse event.
  174. * @param event The mouse event of which the pageX and pageX shall be got.
  175. * @returns {{x: number, y: number}} x = pageX value, y = pageY value.
  176. */
  177. page: function(event) {
  178. event = event.originalEvent || event;
  179. var strPage = 'page';
  180. var strClient = 'client';
  181. var strX = 'X';
  182. var strY = 'Y';
  183. var target = event.target || event.srcElement || document;
  184. var eventDoc = target.ownerDocument || document;
  185. var doc = eventDoc.documentElement;
  186. var body = eventDoc.body;
  187. //if touch event return return pageX/Y of it
  188. if(event.touches !== undefined) {
  189. var touch = event.touches[0];
  190. return {
  191. x : touch[strPage + strX],
  192. y : touch[strPage + strY]
  193. }
  194. }
  195. // Calculate pageX/Y if not native supported
  196. if (!event[strPage + strX] && event[strClient + strX] && event[strClient + strX] != null) {
  197. return {
  198. x : event[strClient + strX] +
  199. (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
  200. (doc && doc.clientLeft || body && body.clientLeft || 0),
  201. y : event[strClient + strY] +
  202. (doc && doc.scrollTop || body && body.scrollTop || 0) -
  203. (doc && doc.clientTop || body && body.clientTop || 0)
  204. }
  205. }
  206. return {
  207. x : event[strPage + strX],
  208. y : event[strPage + strY]
  209. };
  210. },
  211. /**
  212. * Gets the clicked mouse button of the given mouse event.
  213. * @param event The mouse event of which the clicked button shal be got.
  214. * @returns {number} The number of the clicked mouse button. (0 : none | 1 : leftButton | 2 : middleButton | 3 : rightButton)
  215. */
  216. mBtn: function(event) {
  217. var button = event.button;
  218. if (!event.which && button !== undefined)
  219. return (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));
  220. else
  221. return event.which;
  222. },
  223. /**
  224. * Checks whether a item is in the given array and returns its index.
  225. * @param item The item of which the position in the array shall be determined.
  226. * @param arr The array.
  227. * @returns {number} The zero based index of the item or -1 if the item isn't in the array.
  228. */
  229. inA : function(item, arr) {
  230. for (var i = 0; i < arr[LEXICON.l]; i++)
  231. //Sometiems in IE a "SCRIPT70" Permission denied error occurs if HTML elements in a iFrame are compared
  232. try {
  233. if (arr[i] === item)
  234. return i;
  235. }
  236. catch(e) { }
  237. return -1;
  238. },
  239. /**
  240. * Returns true if the given value is a array.
  241. * @param arr The potential array.
  242. * @returns {boolean} True if the given value is a array, false otherwise.
  243. */
  244. isA: function(arr) {
  245. var def = Array.isArray;
  246. return def ? def(arr) : this.type(arr) == TYPES.a;
  247. },
  248. /**
  249. * Determine the internal JavaScript [[Class]] of the given object.
  250. * @param obj The object of which the type shall be determined.
  251. * @returns {string} The type of the given object.
  252. */
  253. type: function(obj) {
  254. if (obj === undefined)
  255. return obj + "";
  256. if (obj === null)
  257. return obj + "";
  258. return Object[LEXICON.p].toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
  259. },
  260. bind: function(func, thisObj) {
  261. if (typeof func != TYPES.f) {
  262. throw "Can't bind function!";
  263. // closest thing possible to the ECMAScript 5
  264. // internal IsCallable function
  265. //throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
  266. }
  267. var proto = LEXICON.p;
  268. var aArgs = Array[proto].slice.call(arguments, 2);
  269. var fNOP = function() {};
  270. var fBound = function() { return func.apply(this instanceof fNOP ? this : thisObj, aArgs.concat(Array[proto].slice.call(arguments))); };
  271. if (func[proto])
  272. fNOP[proto] = func[proto]; // Function.prototype doesn't have a prototype property
  273. fBound[proto] = new fNOP();
  274. return fBound;
  275. }
  276. /**
  277. * Gets the vendor-prefixed CSS property by the given name.
  278. * For example the given name is "transform" and you're using a old Firefox browser then the returned value would be "-moz-transform".
  279. * If the browser doesn't need a vendor-prefix, then the returned string is the given name.
  280. * If the browser doesn't support the given property name at all (not even with a vendor-prefix) the returned value is null.
  281. * @param propName The unprefixed CSS property name.
  282. * @returns {string|null} The vendor-prefixed CSS property or null if the browser doesn't support the given CSS property.
  283. cssProp : function(propName) {
  284. return VENDORS._cssProperty(propName);
  285. }
  286. */
  287. };
  288. var MATH = Math;
  289. var JQUERY = framework;
  290. var EASING = framework.easing;
  291. var FRAMEWORK = framework;
  292. var INSTANCES = (function() {
  293. var _targets = [ ];
  294. var _instancePropertyString = '__overlayScrollbars__';
  295. /**
  296. * Register, unregister or get a certain (or all) instances.
  297. * Register: Pass the target and the instance.
  298. * Unregister: Pass the target and null.
  299. * Get Instance: Pass the target from which the instance shall be got.
  300. * Get Targets: Pass no arguments.
  301. * @param target The target to which the instance shall be registered / from which the instance shall be unregistered / the instance shall be got
  302. * @param instance The instance.
  303. * @returns {*|void} Returns the instance from the given target.
  304. */
  305. return function (target, instance) {
  306. var argLen = arguments[LEXICON.l];
  307. if(argLen < 1) {
  308. //return all targets
  309. return _targets;
  310. }
  311. else {
  312. if(instance) {
  313. //register instance
  314. target[_instancePropertyString] = instance;
  315. _targets.push(target);
  316. }
  317. else {
  318. var index = COMPATIBILITY.inA(target, _targets);
  319. if (index > -1) {
  320. if(argLen > 1) {
  321. //unregister instance
  322. delete target[_instancePropertyString];
  323. _targets.splice(index, 1);
  324. }
  325. else {
  326. //get instance from target
  327. return _targets[index][_instancePropertyString];
  328. }
  329. }
  330. }
  331. }
  332. }
  333. })();
  334. var PLUGIN = (function() {
  335. var _pluginsGlobals;
  336. var _pluginsAutoUpdateLoop;
  337. var _pluginsExtensions = [ ];
  338. var _pluginsOptions = (function() {
  339. var possibleTemplateTypes = [
  340. TYPES.b, //boolean
  341. TYPES.n, //number
  342. TYPES.s, //string
  343. TYPES.a, //array
  344. TYPES.o, //object
  345. TYPES.f, //function
  346. TYPES.z //null
  347. ];
  348. var restrictedStringsSplit = ' ';
  349. var restrictedStringsPossibilitiesSplit = ':';
  350. var classNameAllowedValues = [TYPES.z, TYPES.s];
  351. var numberAllowedValues = TYPES.n;
  352. var booleanNullAllowedValues = [TYPES.z, TYPES.b];
  353. var booleanTrueTemplate = [true, TYPES.b];
  354. var booleanFalseTemplate = [false, TYPES.b];
  355. var callbackTemplate = [null, [TYPES.z, TYPES.f]];
  356. var inheritedAttrsTemplate = [['style', 'class'], [TYPES.s, TYPES.a, TYPES.z]];
  357. var resizeAllowedValues = 'n:none b:both h:horizontal v:vertical';
  358. var overflowBehaviorAllowedValues = 'v-h:visible-hidden v-s:visible-scroll s:scroll h:hidden';
  359. var scrollbarsVisibilityAllowedValues = 'v:visible h:hidden a:auto';
  360. var scrollbarsAutoHideAllowedValues = 'n:never s:scroll l:leave m:move';
  361. var optionsDefaultsAndTemplate = {
  362. className: ['os-theme-dark', classNameAllowedValues], //null || string
  363. resize: ['none', resizeAllowedValues], //none || both || horizontal || vertical || n || b || h || v
  364. sizeAutoCapable: booleanTrueTemplate, //true || false
  365. clipAlways: booleanTrueTemplate, //true || false
  366. normalizeRTL: booleanTrueTemplate, //true || false
  367. paddingAbsolute: booleanFalseTemplate, //true || false
  368. autoUpdate: [null, booleanNullAllowedValues], //true || false || null
  369. autoUpdateInterval: [33, numberAllowedValues], //number
  370. nativeScrollbarsOverlaid: {
  371. showNativeScrollbars: booleanFalseTemplate, //true || false
  372. initialize: booleanTrueTemplate //true || false
  373. },
  374. overflowBehavior: {
  375. x: ['scroll', overflowBehaviorAllowedValues], //visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
  376. y: ['scroll', overflowBehaviorAllowedValues] //visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
  377. },
  378. scrollbars: {
  379. visibility: ['auto', scrollbarsVisibilityAllowedValues], //visible || hidden || auto || v || h || a
  380. autoHide: ['never', scrollbarsAutoHideAllowedValues], //never || scroll || leave || move || n || s || l || m
  381. autoHideDelay: [800, numberAllowedValues], //number
  382. dragScrolling: booleanTrueTemplate, //true || false
  383. clickScrolling: booleanFalseTemplate, //true || false
  384. touchSupport: booleanTrueTemplate, //true || false
  385. snapHandle: booleanFalseTemplate //true || false
  386. },
  387. textarea: {
  388. dynWidth: booleanFalseTemplate, //true || false
  389. dynHeight: booleanFalseTemplate, //true || false
  390. inheritedAttrs : inheritedAttrsTemplate //string || array || null
  391. },
  392. callbacks: {
  393. onInitialized: callbackTemplate, //null || function
  394. onInitializationWithdrawn: callbackTemplate, //null || function
  395. onDestroyed: callbackTemplate, //null || function
  396. onScrollStart: callbackTemplate, //null || function
  397. onScroll: callbackTemplate, //null || function
  398. onScrollStop: callbackTemplate, //null || function
  399. onOverflowChanged: callbackTemplate, //null || function
  400. onOverflowAmountChanged: callbackTemplate, //null || function
  401. onDirectionChanged: callbackTemplate, //null || function
  402. onContentSizeChanged: callbackTemplate, //null || function
  403. onHostSizeChanged: callbackTemplate, //null || function
  404. onUpdated: callbackTemplate //null || function
  405. }
  406. };
  407. var convert = function(template) {
  408. var recursive = function(obj) {
  409. var key;
  410. var val;
  411. var valType;
  412. for(key in obj) {
  413. if(!obj.hasOwnProperty(key))
  414. continue;
  415. val = obj[key];
  416. valType = COMPATIBILITY.type(val);
  417. if(valType == TYPES.a)
  418. obj[key] = val[template ? 1 : 0];
  419. else if(valType == TYPES.o)
  420. obj[key] = recursive(val);
  421. }
  422. return obj;
  423. };
  424. return recursive(FRAMEWORK.extend(true, { }, optionsDefaultsAndTemplate));
  425. };
  426. return {
  427. _defaults : convert(),
  428. _template : convert(true),
  429. /**
  430. * Validates the passed object by the passed template.
  431. * @param obj The object which shall be validated.
  432. * @param template The template which defines the allowed values and types.
  433. * @param writeErrors True if errors shall be logged to the console.
  434. * @param usePreparedValues True if the validated main values shall be returned in the validated object, false otherwise.
  435. * @param keepForeignProps True if properties which aren't in the template shall be added to the validated object, false otherwise.
  436. * @returns {{}} A object which contains only the valid properties of the passed original object.
  437. */
  438. _validate : function (obj, template, writeErrors, usePreparedValues, keepForeignProps) {
  439. var validatedOptions = { };
  440. var objectCopy = FRAMEWORK.extend(true, { }, obj);
  441. var checkObjectProps = function(data, template, validatedOptions, prevPropName) {
  442. for (var prop in template) {
  443. if (template.hasOwnProperty(prop) && data.hasOwnProperty(prop)) {
  444. var isValid = false;
  445. var templateValue = template[prop];
  446. var templateValueType = COMPATIBILITY.type(templateValue);
  447. var templateIsComplext = templateValueType == TYPES.o;
  448. var templateTypes = COMPATIBILITY.type(templateValue) != TYPES.a ? [ templateValue ] : templateValue;
  449. var dataValue = data[prop];
  450. var dataValueType = COMPATIBILITY.type(dataValue);
  451. var propPrefix = prevPropName ? prevPropName + "." : "";
  452. var error = "The option \"" + propPrefix + prop + "\" wasn't set, because";
  453. var errorPossibleTypes = [ ];
  454. var errorRestrictedStrings = [ ];
  455. var restrictedStringValuesSplit;
  456. var restrictedStringValuesPossibilitiesSplit;
  457. var isRestrictedValue;
  458. var mainPossibility;
  459. var currType;
  460. var i;
  461. var v;
  462. var j;
  463. //if the template has a object as value, it means that the options are complex (verschachtelt)
  464. if(templateIsComplext && dataValueType == TYPES.o) {
  465. validatedOptions[prop] = { };
  466. checkObjectProps(dataValue, templateValue, validatedOptions[prop], propPrefix + prop);
  467. if(FRAMEWORK.isEmptyObject(dataValue))
  468. delete data[prop];
  469. }
  470. else if(!templateIsComplext) {
  471. for(i = 0; i < templateTypes.length; i++) {
  472. currType = templateTypes[i];
  473. templateValueType = COMPATIBILITY.type(currType);
  474. //if currtype is string and starts with restrictedStringPrefix and end with restrictedStringSuffix
  475. isRestrictedValue = templateValueType == TYPES.s && FRAMEWORK.inArray(currType, possibleTemplateTypes) === -1;
  476. if(isRestrictedValue) {
  477. errorPossibleTypes.push(TYPES.s);
  478. //split it into a array which contains all possible values for example: ["y:yes", "n:no", "m:maybe"]
  479. restrictedStringValuesSplit = currType.split(restrictedStringsSplit);
  480. errorRestrictedStrings = errorRestrictedStrings.concat(restrictedStringValuesSplit);
  481. for(v = 0; v < restrictedStringValuesSplit.length; v++) {
  482. //split the possible values into their possibiliteis for example: ["y", "yes"] -> the first is always the mainPossibility
  483. restrictedStringValuesPossibilitiesSplit = restrictedStringValuesSplit[v].split(restrictedStringsPossibilitiesSplit);
  484. mainPossibility = restrictedStringValuesPossibilitiesSplit[0];
  485. for(j = 0; j < restrictedStringValuesPossibilitiesSplit.length; j++) {
  486. //if any possibility matches with the dataValue, its valid
  487. if(dataValue === restrictedStringValuesPossibilitiesSplit[j]) {
  488. isValid = true;
  489. break;
  490. }
  491. }
  492. if(isValid)
  493. break;
  494. }
  495. }
  496. else {
  497. errorPossibleTypes.push(currType);
  498. if(dataValueType === currType) {
  499. isValid = true;
  500. break;
  501. }
  502. }
  503. }
  504. if(isValid) {
  505. validatedOptions[prop] = isRestrictedValue && usePreparedValues ? mainPossibility : dataValue;
  506. }
  507. else if(writeErrors) {
  508. console.warn(error + " it doesn't accept the type [ " + dataValueType.toUpperCase() + " ] with the value of \"" + dataValue + "\".\r\n" +
  509. "Accepted types are: [ " + errorPossibleTypes.join(", ").toUpperCase() + " ]." +
  510. (errorRestrictedStrings.length > 0 ? "\r\nValid strings are: [ " + errorRestrictedStrings.join(", ").split(restrictedStringsPossibilitiesSplit).join(", ") + " ]." : ""));
  511. }
  512. delete data[prop];
  513. }
  514. }
  515. }
  516. };
  517. checkObjectProps(objectCopy, template, validatedOptions);
  518. //add values which aren't specified in the template to the finished validated object to prevent them from being discarded
  519. if(keepForeignProps)
  520. FRAMEWORK.extend(true, validatedOptions, objectCopy);
  521. else if(!FRAMEWORK.isEmptyObject(objectCopy) && writeErrors)
  522. console.warn("The following options are discarded due to invalidity:\r\n" + window.JSON.stringify(objectCopy, null, 2));
  523. return validatedOptions;
  524. }
  525. }
  526. }());
  527. /**
  528. * Initializes the object which contains global information about the plugin and each instance of it.
  529. */
  530. function initOverlayScrollbarsStatics() {
  531. if(!_pluginsGlobals)
  532. _pluginsGlobals = new OverlayScrollbarsGlobals(_pluginsOptions._defaults);
  533. if(!_pluginsAutoUpdateLoop)
  534. _pluginsAutoUpdateLoop = new OverlayScrollbarsAutoUpdateLoop(_pluginsGlobals);
  535. }
  536. /**
  537. * 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.
  538. * @param defaultOptions
  539. * @constructor
  540. */
  541. function OverlayScrollbarsGlobals(defaultOptions) {
  542. var _base = this;
  543. var strOverflow = 'overflow';
  544. var strHidden = 'hidden';
  545. var strScroll = 'scroll';
  546. var bodyElement = FRAMEWORK('body');
  547. var scrollbarDummyElement = FRAMEWORK('<div id="os-dummy-scrollbar-size"><div></div></div>');
  548. var scrollbarDummyElement0 = scrollbarDummyElement[0];
  549. var dummyContainerChild = FRAMEWORK(scrollbarDummyElement.children('div').eq(0));
  550. bodyElement.append(scrollbarDummyElement);
  551. scrollbarDummyElement.hide().show(); //fix IE8 bug (incorrect measuring)
  552. var nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement0);
  553. var nativeScrollbarIsOverlaid = {
  554. x: nativeScrollbarSize.x === 0,
  555. y: nativeScrollbarSize.y === 0
  556. };
  557. FRAMEWORK.extend(_base, {
  558. defaultOptions : defaultOptions,
  559. autoUpdateLoop : false,
  560. autoUpdateRecommended : !COMPATIBILITY.mO(),
  561. nativeScrollbarSize : nativeScrollbarSize,
  562. nativeScrollbarIsOverlaid : nativeScrollbarIsOverlaid,
  563. nativeScrollbarStyling : (function() {
  564. scrollbarDummyElement.addClass('os-viewport-native-scrollbars-invisible');
  565. //fix opera bug: scrollbar styles will only appear if overflow value is scroll or auto during the activation of the style.
  566. //and set overflow to scroll
  567. scrollbarDummyElement.css(strOverflow, strHidden).hide().css(strOverflow, strScroll).show();
  568. return (scrollbarDummyElement0[LEXICON.oH] - scrollbarDummyElement0[LEXICON.cH]) === 0 && (scrollbarDummyElement0[LEXICON.oW] - scrollbarDummyElement0[LEXICON.cW]) === 0;
  569. })(),
  570. overlayScrollbarDummySize : { x: 30, y: 30 },
  571. msie : (function() {
  572. var ua = window.navigator.userAgent;
  573. var strIndexOf = 'indexOf';
  574. var strSubString = 'substring';
  575. var msie = ua[strIndexOf]('MSIE ');
  576. var trident = ua[strIndexOf]('Trident/');
  577. var edge = ua[strIndexOf]('Edge/');
  578. var rv = ua[strIndexOf]('rv:');
  579. var result;
  580. var parseIntFunc = parseInt;
  581. // IE 10 or older => return version number
  582. if (msie > 0)
  583. result = parseIntFunc(ua[strSubString](msie + 5, ua[strIndexOf]('.', msie)), 10);
  584. // IE 11 => return version number
  585. else if (trident > 0)
  586. result = parseIntFunc(ua[strSubString](rv + 3, ua[strIndexOf]('.', rv)), 10);
  587. // Edge (IE 12+) => return version number
  588. else if (edge > 0)
  589. result = parseIntFunc(ua[strSubString](edge + 5, ua[strIndexOf]('.', edge)), 10);
  590. // other browser
  591. return result;
  592. })(),
  593. cssCalc : (function() {
  594. var dummyStyle = document.createElement('div')[LEXICON.s];
  595. var strCalc = 'calc';
  596. var i = -1;
  597. var prop;
  598. for(; i < VENDORS._cssPrefixes[LEXICON.l]; i++) {
  599. prop = i < 0 ? strCalc : VENDORS._cssPrefixes[i] + strCalc;
  600. dummyStyle.cssText = 'width:' + prop + '(1px);';
  601. if (dummyStyle[LEXICON.l])
  602. return prop;
  603. }
  604. return null;
  605. })(),
  606. restrictedMeasuring : (function() {
  607. //https://bugzilla.mozilla.org/show_bug.cgi?id=1439305
  608. scrollbarDummyElement.css(strOverflow, strHidden);
  609. var scrollSize = {
  610. w : scrollbarDummyElement0[LEXICON.sW],
  611. h : scrollbarDummyElement0[LEXICON.sH]
  612. };
  613. scrollbarDummyElement.css(strOverflow, 'visible');
  614. var scrollSize2 = {
  615. w : scrollbarDummyElement0[LEXICON.sW],
  616. h : scrollbarDummyElement0[LEXICON.sH]
  617. };
  618. return (scrollSize.w - scrollSize2.w) !== 0 || (scrollSize.h - scrollSize2.h) !== 0;
  619. })(),
  620. rtlScrollBehavior : (function() {
  621. scrollbarDummyElement.css({ 'overflow-y' : strHidden, 'overflow-x' : strScroll, 'direction' : 'rtl' }).scrollLeft(0);
  622. var dummyContainerOffset = scrollbarDummyElement.offset();
  623. var dummyContainerChildOffset = dummyContainerChild.offset();
  624. scrollbarDummyElement.scrollLeft(999);
  625. var dummyContainerScrollOffsetAfterScroll = dummyContainerChild.offset();
  626. return {
  627. //origin direction = determines if the zero scroll position is on the left or right side
  628. //'i' means 'invert' (i === true means that the axis must be inverted to be correct)
  629. //true = on the left side
  630. //false = on the right side
  631. i : dummyContainerOffset.left === dummyContainerChildOffset.left,
  632. //negative = determines if the maximum scroll is positive or negative
  633. //'n' means 'negate' (n === true means that the axis must be negated to be correct)
  634. //true = negative
  635. //false = positive
  636. n : dummyContainerChildOffset.left - dummyContainerScrollOffsetAfterScroll.left === 0
  637. };
  638. })(),
  639. supportTransform : VENDORS._cssProperty('transform') !== null,
  640. supportTransition : VENDORS._cssProperty('transition') !== null,
  641. supportPassiveEvents : (function() {
  642. var supportsPassive = false;
  643. try {
  644. window.addEventListener('test', null, Object.defineProperty({ }, 'passive', {
  645. get: function() {
  646. supportsPassive = true;
  647. }
  648. }));
  649. } catch (e) { }
  650. return supportsPassive;
  651. })(),
  652. supportResizeObserver : !!COMPATIBILITY.rO(),
  653. supportMutationObserver : !!COMPATIBILITY.mO()
  654. });
  655. scrollbarDummyElement.removeAttr(LEXICON.s).remove();
  656. //Catch zoom event:
  657. (function () {
  658. if(nativeScrollbarIsOverlaid.x && nativeScrollbarIsOverlaid.y)
  659. return;
  660. var abs = MATH.abs;
  661. var windowWidth = COMPATIBILITY.wW();
  662. var windowHeight = COMPATIBILITY.wH();
  663. var windowDpr = getWindowDPR();
  664. var onResize = function() {
  665. if(INSTANCES().length > 0) {
  666. var newW = COMPATIBILITY.wW();
  667. var newH = COMPATIBILITY.wH();
  668. var deltaW = newW - windowWidth;
  669. var deltaH = newH - windowHeight;
  670. if (deltaW === 0 && deltaH === 0)
  671. return;
  672. var deltaWRatio = MATH.round(newW / (windowWidth / 100.0));
  673. var deltaHRatio = MATH.round(newH / (windowHeight / 100.0));
  674. var absDeltaW = abs(deltaW);
  675. var absDeltaH = abs(deltaH);
  676. var absDeltaWRatio = abs(deltaWRatio);
  677. var absDeltaHRatio = abs(deltaHRatio);
  678. var newDPR = getWindowDPR();
  679. var deltaIsBigger = absDeltaW > 2 && absDeltaH > 2;
  680. var difference = !differenceIsBiggerThanOne(absDeltaWRatio, absDeltaHRatio);
  681. var dprChanged = newDPR !== windowDpr && windowDpr > 0;
  682. var isZoom = deltaIsBigger && difference && dprChanged;
  683. var oldScrollbarSize = _base.nativeScrollbarSize;
  684. var newScrollbarSize;
  685. if (isZoom) {
  686. bodyElement.append(scrollbarDummyElement);
  687. newScrollbarSize = _base.nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement[0]);
  688. scrollbarDummyElement.remove();
  689. if(oldScrollbarSize.x !== newScrollbarSize.x || oldScrollbarSize.y !== newScrollbarSize.y) {
  690. FRAMEWORK.each(INSTANCES(), function () {
  691. if(INSTANCES(this))
  692. INSTANCES(this).update('zoom');
  693. });
  694. }
  695. }
  696. windowWidth = newW;
  697. windowHeight = newH;
  698. windowDpr = newDPR;
  699. }
  700. };
  701. function differenceIsBiggerThanOne(valOne, valTwo) {
  702. var absValOne = abs(valOne);
  703. var absValTwo = abs(valTwo);
  704. return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
  705. }
  706. function getWindowDPR() {
  707. var dDPI = window.screen.deviceXDPI || 0;
  708. var sDPI = window.screen.logicalXDPI || 1;
  709. return window.devicePixelRatio || (dDPI / sDPI);
  710. }
  711. FRAMEWORK(window).on('resize', onResize);
  712. })();
  713. function calcNativeScrollbarSize(measureElement) {
  714. return {
  715. x: measureElement[LEXICON.oH] - measureElement[LEXICON.cH],
  716. y: measureElement[LEXICON.oW] - measureElement[LEXICON.cW]
  717. };
  718. }
  719. }
  720. /**
  721. * 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.
  722. * @constructor
  723. */
  724. function OverlayScrollbarsAutoUpdateLoop(globals) {
  725. var _base = this;
  726. var _strAutoUpdate = 'autoUpdate';
  727. var _strAutoUpdateInterval = _strAutoUpdate + 'Interval';
  728. var _strLength = LEXICON.l;
  729. var _loopingInstances = [ ];
  730. var _loopingInstancesIntervalCache = [ ];
  731. var _loopIsActive = false;
  732. var _loopIntervalDefault = 33;
  733. var _loopInterval = _loopIntervalDefault;
  734. var _loopTimeOld = COMPATIBILITY.now();
  735. var _loopID;
  736. /**
  737. * The auto update loop which will run every 50 milliseconds or less if the update interval of a instance is lower than 50 milliseconds.
  738. */
  739. var loop = function() {
  740. if(_loopingInstances[_strLength] > 0 && _loopIsActive) {
  741. _loopID = COMPATIBILITY.rAF()(function () {
  742. loop();
  743. });
  744. var timeNew = COMPATIBILITY.now();
  745. var timeDelta = timeNew - _loopTimeOld;
  746. var lowestInterval;
  747. var instance;
  748. var instanceOptions;
  749. var instanceAutoUpdateAllowed;
  750. var instanceAutoUpdateInterval;
  751. var now;
  752. if (timeDelta > _loopInterval) {
  753. _loopTimeOld = timeNew - (timeDelta % _loopInterval);
  754. lowestInterval = _loopIntervalDefault;
  755. for(var i = 0; i < _loopingInstances[_strLength]; i++) {
  756. instance = _loopingInstances[i];
  757. if (instance !== undefined) {
  758. instanceOptions = instance.options();
  759. instanceAutoUpdateAllowed = instanceOptions[_strAutoUpdate];
  760. instanceAutoUpdateInterval = MATH.max(1, instanceOptions[_strAutoUpdateInterval]);
  761. now = COMPATIBILITY.now();
  762. if ((instanceAutoUpdateAllowed === true || instanceAutoUpdateAllowed === null) && (now - _loopingInstancesIntervalCache[i]) > instanceAutoUpdateInterval) {
  763. instance.update('auto');
  764. _loopingInstancesIntervalCache[i] = new Date(now += instanceAutoUpdateInterval);
  765. }
  766. lowestInterval = MATH.max(1, MATH.min(lowestInterval, instanceAutoUpdateInterval));
  767. }
  768. }
  769. _loopInterval = lowestInterval;
  770. }
  771. } else {
  772. _loopInterval = _loopIntervalDefault;
  773. }
  774. };
  775. /**
  776. * Add OverlayScrollbars instance to the auto update loop. Only successful if the instance isn't already added.
  777. * @param instance The instance which shall be updated in a loop automatically.
  778. */
  779. _base.add = function(instance) {
  780. if(FRAMEWORK.inArray(instance, _loopingInstances) === -1) {
  781. _loopingInstances.push(instance);
  782. _loopingInstancesIntervalCache.push(COMPATIBILITY.now());
  783. if (_loopingInstances[_strLength] > 0 && !_loopIsActive) {
  784. _loopIsActive = true;
  785. globals.autoUpdateLoop = _loopIsActive;
  786. loop();
  787. }
  788. }
  789. };
  790. /**
  791. * Remove OverlayScrollbars instance from the auto update loop. Only successful if the instance was added before.
  792. * @param instance The instance which shall be updated in a loop automatically.
  793. */
  794. _base.remove = function(instance) {
  795. var index = FRAMEWORK.inArray(instance, _loopingInstances);
  796. if(index > -1) {
  797. //remove from loopingInstances list
  798. _loopingInstancesIntervalCache.splice(index, 1);
  799. _loopingInstances.splice(index, 1);
  800. //correct update loop behavior
  801. if (_loopingInstances[_strLength] === 0 && _loopIsActive) {
  802. _loopIsActive = false;
  803. globals.autoUpdateLoop = _loopIsActive;
  804. if(_loopID !== undefined) {
  805. COMPATIBILITY.cAF()(_loopID);
  806. _loopID = -1;
  807. }
  808. }
  809. }
  810. };
  811. }
  812. /**
  813. * A object which manages the scrollbars visibility of the target element.
  814. * @param pluginTargetElement The element from which the scrollbars shall be hidden.
  815. * @param options The custom options.
  816. * @param extensions The custom extensions.
  817. * @param globals
  818. * @param autoUpdateLoop
  819. * @returns {*}
  820. * @constructor
  821. */
  822. function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) {
  823. //if passed element is no HTML element: skip and return
  824. if(!isHTMLElement(pluginTargetElement))
  825. return;
  826. //if passed element is already initialized: set passed options if there are any and return its instance
  827. if(INSTANCES(pluginTargetElement)) {
  828. var inst = INSTANCES(pluginTargetElement);
  829. inst.options(options);
  830. return inst;
  831. }
  832. //make correct instanceof
  833. var _base = new window[PLUGINNAME]();
  834. var _frameworkProto = FRAMEWORK[LEXICON.p];
  835. //globals:
  836. var _nativeScrollbarIsOverlaid;
  837. var _overlayScrollbarDummySize;
  838. var _rtlScrollBehavior;
  839. var _autoUpdateRecommended;
  840. var _msieVersion;
  841. var _nativeScrollbarStyling;
  842. var _cssCalc;
  843. var _nativeScrollbarSize;
  844. var _supportTransition;
  845. var _supportTransform;
  846. var _supportPassiveEvents;
  847. var _supportResizeObserver;
  848. var _supportMutationObserver;
  849. var _restrictedMeasuring;
  850. //general readonly:
  851. var _initialized;
  852. var _destroyed;
  853. var _isTextarea;
  854. var _isBody;
  855. var _documentMixed;
  856. var _isTextareaHostGenerated;
  857. //general:
  858. var _isBorderBox;
  859. var _sizeAutoObserverAdded;
  860. var _paddingX;
  861. var _paddingY;
  862. var _borderX;
  863. var _borderY;
  864. var _marginX;
  865. var _marginY;
  866. var _isRTL;
  867. var _isSleeping;
  868. var _contentBorderSize = { };
  869. var _scrollHorizontalInfo = { };
  870. var _scrollVerticalInfo = { };
  871. var _viewportSize = { };
  872. var _nativeScrollbarMinSize = { };
  873. //naming:
  874. var _strMinusHidden = '-hidden';
  875. var _strMarginMinus = 'margin-';
  876. var _strPaddingMinus = 'padding-';
  877. var _strBorderMinus = 'border-';
  878. var _strTop = 'top';
  879. var _strRight = 'right';
  880. var _strBottom = 'bottom';
  881. var _strLeft = 'left';
  882. var _strMinMinus = 'min-';
  883. var _strMaxMinus = 'max-';
  884. var _strWidth = 'width';
  885. var _strHeight = 'height';
  886. var _strFloat = 'float';
  887. var _strEmpty = '';
  888. var _strAuto = 'auto';
  889. var _strScroll = 'scroll';
  890. var _strHundredPercent = '100%';
  891. var _strX = 'x';
  892. var _strY = 'y';
  893. var _strDot = '.';
  894. var _strSpace = ' ';
  895. var _strScrollbar = 'scrollbar';
  896. var _strMinusHorizontal = '-horizontal';
  897. var _strMinusVertical = '-vertical';
  898. var _strScrollLeft = _strScroll + 'Left';
  899. var _strScrollTop = _strScroll + 'Top';
  900. var _strMouseTouchDownEvent = 'mousedown touchstart';
  901. var _strMouseTouchUpEvent = 'mouseup touchend touchcancel';
  902. var _strMouseTouchMoveEvent = 'mousemove touchmove';
  903. var _strMouseTouchEnter = 'mouseenter';
  904. var _strMouseTouchLeave = 'mouseleave';
  905. var _strKeyDownEvent = 'keydown';
  906. var _strKeyUpEvent = 'keyup';
  907. var _strSelectStartEvent = 'selectstart';
  908. var _strTransitionEndEvent = 'transitionend webkitTransitionEnd oTransitionEnd';
  909. var _strResizeObserverProperty = '__overlayScrollbarsRO__';
  910. //class names:
  911. var _cassNamesPrefix = 'os-';
  912. var _classNameHTMLElement = _cassNamesPrefix + 'html';
  913. var _classNameHostElement = _cassNamesPrefix + 'host';
  914. var _classNameHostTextareaElement = _classNameHostElement + '-textarea';
  915. var _classNameHostScrollbarHorizontalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusHorizontal + _strMinusHidden;
  916. var _classNameHostScrollbarVerticalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusVertical + _strMinusHidden;
  917. var _classNameHostTransition = _classNameHostElement + '-transition';
  918. var _classNameHostRTL = _classNameHostElement + '-rtl';
  919. var _classNameHostResizeDisabled = _classNameHostElement + '-resize-disabled';
  920. var _classNameHostScrolling = _classNameHostElement + '-scrolling';
  921. var _classNameHostOverflow = _classNameHostElement + '-overflow';
  922. var _classNameHostOverflowX = _classNameHostOverflow + '-x';
  923. var _classNameHostOverflowY = _classNameHostOverflow + '-y';
  924. var _classNameTextareaElement = _cassNamesPrefix + 'textarea';
  925. var _classNameTextareaCoverElement = _classNameTextareaElement + '-cover';
  926. var _classNamePaddingElement = _cassNamesPrefix + 'padding';
  927. var _classNameViewportElement = _cassNamesPrefix + 'viewport';
  928. var _classNameViewportNativeScrollbarsInvisible = _classNameViewportElement + '-native-scrollbars-invisible';
  929. var _classNameViewportNativeScrollbarsOverlaid = _classNameViewportElement + '-native-scrollbars-overlaid';
  930. var _classNameContentElement = _cassNamesPrefix + 'content';
  931. var _classNameContentArrangeElement = _cassNamesPrefix + 'content-arrange';
  932. var _classNameContentGlueElement = _cassNamesPrefix + 'content-glue';
  933. var _classNameSizeAutoObserverElement = _cassNamesPrefix + 'size-auto-observer';
  934. var _classNameResizeObserverElement = _cassNamesPrefix + 'resize-observer';
  935. var _classNameResizeObserverItemElement = _cassNamesPrefix + 'resize-observer-item';
  936. var _classNameResizeObserverItemFinalElement = _classNameResizeObserverItemElement + '-final';
  937. var _classNameTextInherit = _cassNamesPrefix + 'text-inherit';
  938. var _classNameScrollbar = _cassNamesPrefix + _strScrollbar;
  939. var _classNameScrollbarTrack = _classNameScrollbar + '-track';
  940. var _classNameScrollbarTrackOff = _classNameScrollbarTrack + '-off';
  941. var _classNameScrollbarHandle = _classNameScrollbar + '-handle';
  942. var _classNameScrollbarHandleOff = _classNameScrollbarHandle + '-off';
  943. var _classNameScrollbarUnusable = _classNameScrollbar + '-unusable';
  944. var _classNameScrollbarAutoHidden = _classNameScrollbar + '-' + _strAuto + _strMinusHidden;
  945. var _classNameScrollbarCorner = _classNameScrollbar + '-corner';
  946. var _classNameScrollbarCornerResize = _classNameScrollbarCorner + '-resize';
  947. var _classNameScrollbarCornerResizeB = _classNameScrollbarCornerResize + '-both';
  948. var _classNameScrollbarCornerResizeH = _classNameScrollbarCornerResize + _strMinusHorizontal;
  949. var _classNameScrollbarCornerResizeV = _classNameScrollbarCornerResize + _strMinusVertical;
  950. var _classNameScrollbarHorizontal = _classNameScrollbar + _strMinusHorizontal;
  951. var _classNameScrollbarVertical = _classNameScrollbar + _strMinusVertical;
  952. var _classNameDragging = _cassNamesPrefix + 'dragging';
  953. var _classNameThemeNone = _cassNamesPrefix + 'theme-none';
  954. //callbacks:
  955. var _callbacksInitQeueue = [ ];
  956. //options:
  957. var _defaultOptions;
  958. var _currentOptions;
  959. var _currentPreparedOptions;
  960. //extensions:
  961. var _extensions = { };
  962. var _extensionsPrivateMethods = "added removed on contract";
  963. //update
  964. var _lastUpdateTime;
  965. var _swallowedUpdateParams = { };
  966. var _swallowedUpdateTimeout;
  967. var _swallowUpdateLag = 42;
  968. var _imgs = [ ];
  969. //DOM elements:
  970. var _windowElement;
  971. var _documentElement;
  972. var _htmlElement;
  973. var _bodyElement;
  974. var _targetElement; //the target element of this OverlayScrollbars object
  975. var _hostElement; //the host element of this OverlayScrollbars object -> may be the same as targetElement
  976. var _sizeAutoObserverElement; //observes size auto changes
  977. var _sizeObserverElement; //observes size and padding changes
  978. var _paddingElement; //manages the padding
  979. var _viewportElement; //is the viewport of our scrollbar model
  980. var _contentElement; //the element which holds the content
  981. var _contentArrangeElement; //is needed for correct sizing of the content element (only if native scrollbars are overlays)
  982. var _contentGlueElement; //has always the size of the content element
  983. var _textareaCoverElement; //only applied if target is a textarea element. Used for correct size calculation and for prevention of uncontrolled scrolling
  984. var _scrollbarCornerElement;
  985. var _scrollbarHorizontalElement;
  986. var _scrollbarHorizontalTrackElement;
  987. var _scrollbarHorizontalHandleElement;
  988. var _scrollbarVerticalElement;
  989. var _scrollbarVerticalTrackElement;
  990. var _scrollbarVerticalHandleElement;
  991. var _windowElementNative;
  992. var _documentElementNative;
  993. var _targetElementNative;
  994. var _hostElementNative;
  995. var _sizeAutoObserverElementNative;
  996. var _sizeObserverElementNative;
  997. var _paddingElementNative;
  998. var _viewportElementNative;
  999. var _contentElementNative;
  1000. //Cache:
  1001. var _hostSizeCache;
  1002. var _contentScrollSizeCache;
  1003. var _arrangeContentSizeCache;
  1004. var _hasOverflowCache;
  1005. var _hideOverflowCache;
  1006. var _widthAutoCache;
  1007. var _heightAutoCache;
  1008. var _cssMaxValueCache;
  1009. var _cssBoxSizingCache;
  1010. var _cssPaddingCache;
  1011. var _cssBorderCache;
  1012. var _cssMarginCache;
  1013. var _cssDirectionCache;
  1014. var _cssDirectionDetectedCache;
  1015. var _paddingAbsoluteCache;
  1016. var _clipAlwaysCache;
  1017. var _contentGlueSizeCache;
  1018. var _overflowBehaviorCache;
  1019. var _overflowAmountCache;
  1020. var _ignoreOverlayScrollbarHidingCache;
  1021. var _autoUpdateCache;
  1022. var _sizeAutoCapableCache;
  1023. var _textareaAutoWrappingCache;
  1024. var _textareaInfoCache;
  1025. var _updateAutoHostElementIdCache;
  1026. var _updateAutoHostElementClassCache;
  1027. var _updateAutoHostElementStyleCache;
  1028. var _updateAutoHostElementVisibleCache;
  1029. var _updateAutoTargetElementRowsCache;
  1030. var _updateAutoTargetElementColsCache;
  1031. var _updateAutoTargetElementWrapCache;
  1032. var _contentElementScrollSizeChangeDetectedCache;
  1033. var _hostElementSizeChangeDetectedCache;
  1034. var _scrollbarsVisibilityCache;
  1035. var _scrollbarsAutoHideCache;
  1036. var _scrollbarsClickScrollingCache;
  1037. var _scrollbarsDragScrollingCache;
  1038. var _resizeCache;
  1039. var _normalizeRTLCache;
  1040. var _classNameCache;
  1041. var _oldClassName;
  1042. var _textareaDynHeightCache;
  1043. var _textareaDynWidthCache;
  1044. var _bodyMinSizeCache;
  1045. var _viewportScrollSizeCache;
  1046. var _displayIsHiddenCache;
  1047. //MutationObserver:
  1048. var _mutationObserverHost;
  1049. var _mutationObserverContent;
  1050. var _mutationObserversConnected;
  1051. //textarea:
  1052. var _textareaEvents;
  1053. var _textareaHasFocus;
  1054. //scrollbars:
  1055. var _scrollbarsAutoHideTimeoutId;
  1056. var _scrollbarsAutoHideMoveTimeoutId;
  1057. var _scrollbarsAutoHideDelay;
  1058. var _scrollbarsAutoHideNever;
  1059. var _scrollbarsAutoHideScroll;
  1060. var _scrollbarsAutoHideMove;
  1061. var _scrollbarsAutoHideLeave;
  1062. var _scrollbarsHandleHovered;
  1063. var _scrollbarsHandleAsync;
  1064. //resize
  1065. var _resizeReconnectMutationObserver;
  1066. var _resizeNone;
  1067. var _resizeBoth;
  1068. var _resizeHorizontal;
  1069. var _resizeVertical;
  1070. var _resizeOnMouseTouchDown;
  1071. //==== Passive Event Listener ====//
  1072. /**
  1073. * Adds a passive event listener to the given element.
  1074. * @param element The element to which the event listener shall be applied.
  1075. * @param eventNames The name(s) of the event listener.
  1076. * @param listener The listener method which shall be called.
  1077. */
  1078. function addPassiveEventListener(element, eventNames, listener) {
  1079. var events = eventNames.split(_strSpace);
  1080. for (var i = 0; i < events.length; i++)
  1081. element[0].addEventListener(events[i], listener, {passive: true});
  1082. }
  1083. /**
  1084. * Removes a passive event listener to the given element.
  1085. * @param element The element from which the event listener shall be removed.
  1086. * @param eventNames The name(s) of the event listener.
  1087. * @param listener The listener method which shall be removed.
  1088. */
  1089. function removePassiveEventListener(element, eventNames, listener) {
  1090. var events = eventNames.split(_strSpace);
  1091. for (var i = 0; i < events.length; i++)
  1092. element[0].removeEventListener(events[i], listener, {passive: true});
  1093. }
  1094. //==== Resize Observer ====//
  1095. /**
  1096. * Adds a resize observer to the given element.
  1097. * @param targetElement The element to which the resize observer shall be applied.
  1098. * @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change.
  1099. */
  1100. function addResizeObserver(targetElement, onElementResizedCallback) {
  1101. var constMaximum = 3333333;
  1102. var resizeObserver = COMPATIBILITY.rO();
  1103. var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart';
  1104. var strChildNodes = 'childNodes';
  1105. var callback = function () {
  1106. targetElement[_strScrollTop](constMaximum)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum : constMaximum);
  1107. onElementResizedCallback();
  1108. };
  1109. if (_supportResizeObserver) {
  1110. var element = targetElement.append(generateDiv(_classNameResizeObserverElement + ' observed')).contents()[0];
  1111. var observer = element[_strResizeObserverProperty] = new resizeObserver(callback);
  1112. observer.observe(element);
  1113. }
  1114. else {
  1115. if (_msieVersion > 9 || !_autoUpdateRecommended) {
  1116. targetElement.prepend(
  1117. generateDiv(_classNameResizeObserverElement,
  1118. generateDiv({ className : _classNameResizeObserverItemElement, dir : "ltr" },
  1119. generateDiv(_classNameResizeObserverItemElement,
  1120. generateDiv(_classNameResizeObserverItemFinalElement)
  1121. ) +
  1122. generateDiv(_classNameResizeObserverItemElement,
  1123. generateDiv({ className : _classNameResizeObserverItemFinalElement, style : 'width: 200%; height: 200%' })
  1124. )
  1125. )
  1126. )
  1127. );
  1128. var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0];
  1129. var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]);
  1130. var expandElement = FRAMEWORK(observerElement[strChildNodes][0]);
  1131. var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]);
  1132. var widthCache = observerElement[LEXICON.oW];
  1133. var heightCache = observerElement[LEXICON.oH];
  1134. var isDirty;
  1135. var rAFId;
  1136. var currWidth;
  1137. var currHeight;
  1138. var factor = 2;
  1139. var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!!
  1140. var reset = function () {
  1141. /*
  1142. var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
  1143. var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
  1144. var expandChildCSS = {};
  1145. expandChildCSS[_strWidth] = sizeResetWidth;
  1146. expandChildCSS[_strHeight] = sizeResetHeight;
  1147. expandElementChild.css(expandChildCSS);
  1148. expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
  1149. shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
  1150. */
  1151. expandElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum);
  1152. shrinkElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum);
  1153. };
  1154. var onResized = function () {
  1155. rAFId = 0;
  1156. if (!isDirty)
  1157. return;
  1158. widthCache = currWidth;
  1159. heightCache = currHeight;
  1160. callback();
  1161. };
  1162. var onScroll = function (event) {
  1163. currWidth = observerElement[LEXICON.oW];
  1164. currHeight = observerElement[LEXICON.oH];
  1165. isDirty = currWidth != widthCache || currHeight != heightCache;
  1166. if (event && isDirty && !rAFId) {
  1167. COMPATIBILITY.cAF()(rAFId);
  1168. rAFId = COMPATIBILITY.rAF()(onResized);
  1169. }
  1170. else if(!event)
  1171. onResized();
  1172. reset();
  1173. if (event) {
  1174. COMPATIBILITY.prvD(event);
  1175. COMPATIBILITY.stpP(event);
  1176. }
  1177. return false;
  1178. };
  1179. var expandChildCSS = {};
  1180. var observerElementCSS = {};
  1181. setTopRightBottomLeft(observerElementCSS, _strEmpty, [
  1182. -((nativeScrollbarSize.y + 1) * factor),
  1183. nativeScrollbarSize.x * -factor,
  1184. nativeScrollbarSize.y * -factor,
  1185. -((nativeScrollbarSize.x + 1) * factor)
  1186. ]);
  1187. FRAMEWORK(observerElement).css(observerElementCSS);
  1188. expandElement.on(_strScroll, onScroll);
  1189. shrinkElement.on(_strScroll, onScroll);
  1190. targetElement.on(strAnimationStartEvent, function () {
  1191. onScroll(false);
  1192. });
  1193. //lets assume that the divs will never be that large and a constant value is enough
  1194. expandChildCSS[_strWidth] = constMaximum;
  1195. expandChildCSS[_strHeight] = constMaximum;
  1196. expandElementChild.css(expandChildCSS);
  1197. reset();
  1198. }
  1199. else {
  1200. var attachEvent = _documentElementNative.attachEvent;
  1201. var isIE = _msieVersion !== undefined;
  1202. if (attachEvent) {
  1203. targetElement.prepend(generateDiv(_classNameResizeObserverElement));
  1204. findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback);
  1205. }
  1206. else {
  1207. var obj = _documentElementNative.createElement(TYPES.o);
  1208. obj.setAttribute('tabindex', '-1');
  1209. obj.setAttribute(LEXICON.c, _classNameResizeObserverElement);
  1210. obj.onload = function () {
  1211. var wnd = this.contentDocument.defaultView;
  1212. wnd.addEventListener('resize', callback);
  1213. wnd.document.documentElement.style.display = 'none';
  1214. };
  1215. obj.type = 'text/html';
  1216. if (isIE)
  1217. targetElement.prepend(obj);
  1218. obj.data = 'about:blank';
  1219. if (!isIE)
  1220. targetElement.prepend(obj);
  1221. targetElement.on(strAnimationStartEvent, callback);
  1222. }
  1223. }
  1224. }
  1225. //direction change detection:
  1226. if (targetElement[0] === _sizeObserverElementNative) {
  1227. var directionChanged = function () {
  1228. var dir = _hostElement.css('direction');
  1229. var css = {};
  1230. var scrollLeftValue = 0;
  1231. var result = false;
  1232. if (dir !== _cssDirectionDetectedCache) {
  1233. if (dir === 'ltr') {
  1234. css[_strLeft] = 0;
  1235. css[_strRight] = _strAuto;
  1236. scrollLeftValue = constMaximum;
  1237. }
  1238. else {
  1239. css[_strLeft] = _strAuto;
  1240. css[_strRight] = 0;
  1241. scrollLeftValue = _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum;
  1242. }
  1243. _sizeObserverElement.children().eq(0).css(css);
  1244. targetElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constMaximum);
  1245. _cssDirectionDetectedCache = dir;
  1246. result = true;
  1247. }
  1248. return result;
  1249. };
  1250. directionChanged();
  1251. targetElement.on(_strScroll, function (event) {
  1252. if (directionChanged())
  1253. update();
  1254. COMPATIBILITY.prvD(event);
  1255. COMPATIBILITY.stpP(event);
  1256. return false;
  1257. });
  1258. }
  1259. }
  1260. /**
  1261. * Removes a resize observer from the given element.
  1262. * @param targetElement The element to which the target resize observer is applied.
  1263. */
  1264. function removeResizeObserver(targetElement) {
  1265. if (_supportResizeObserver) {
  1266. var element = targetElement.contents()[0];
  1267. element[_strResizeObserverProperty].disconnect();
  1268. delete element[_strResizeObserverProperty];
  1269. }
  1270. else {
  1271. remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0));
  1272. }
  1273. }
  1274. /**
  1275. * Freezes the given resize observer.
  1276. * @param targetElement The element to which the target resize observer is applied.
  1277. */
  1278. function freezeResizeObserver(targetElement) {
  1279. if (targetElement !== undefined) {
  1280. /*
  1281. if (_supportResizeObserver) {
  1282. var element = targetElement.contents()[0];
  1283. element[_strResizeObserverProperty].unobserve(element);
  1284. }
  1285. else {
  1286. targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0);
  1287. var w = targetElement.css(_strWidth);
  1288. var h = targetElement.css(_strHeight);
  1289. var css = {};
  1290. css[_strWidth] = w;
  1291. css[_strHeight] = h;
  1292. targetElement.css(css);
  1293. }
  1294. */
  1295. }
  1296. }
  1297. /**
  1298. * Unfreezes the given resize observer.
  1299. * @param targetElement The element to which the target resize observer is applied.
  1300. */
  1301. function unfreezeResizeObserver(targetElement) {
  1302. if (targetElement !== undefined) {
  1303. /*
  1304. if (_supportResizeObserver) {
  1305. var element = targetElement.contents()[0];
  1306. element[_strResizeObserverProperty].observe(element);
  1307. }
  1308. else {
  1309. var css = { };
  1310. css[_strHeight] = _strEmpty;
  1311. css[_strWidth] = _strEmpty;
  1312. targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css);
  1313. }
  1314. */
  1315. }
  1316. }
  1317. //==== Mutation Observers ====//
  1318. /**
  1319. * Creates MutationObservers for the host and content Element if they are supported.
  1320. */
  1321. function createMutationObservers() {
  1322. if (_supportMutationObserver) {
  1323. var mutationObserverContentLag = 11;
  1324. var mutationObserver = COMPATIBILITY.mO();
  1325. var contentLastUpdate = COMPATIBILITY.now();
  1326. var mutationTarget;
  1327. var mutationAttrName;
  1328. var contentTimeout;
  1329. var now;
  1330. var sizeAuto;
  1331. var action;
  1332. _mutationObserverHost = new mutationObserver(function (mutations) {
  1333. if (!_initialized || _isSleeping)
  1334. return;
  1335. var doUpdate = false;
  1336. var mutation;
  1337. FRAMEWORK.each(mutations, function () {
  1338. mutation = this;
  1339. mutationTarget = mutation.target;
  1340. mutationAttrName = mutation.attributeName;
  1341. if (mutationAttrName === LEXICON.c)
  1342. doUpdate = hostClassNamesChanged(mutation.oldValue, mutationTarget.className);
  1343. else if (mutationAttrName === LEXICON.s)
  1344. doUpdate = mutation.oldValue !== mutationTarget[LEXICON.s].cssText;
  1345. else
  1346. doUpdate = true;
  1347. if (doUpdate)
  1348. return false;
  1349. });
  1350. if (doUpdate)
  1351. _base.update(_strAuto);
  1352. });
  1353. _mutationObserverContent = new mutationObserver(function (mutations) {
  1354. if (!_initialized || _isSleeping)
  1355. return;
  1356. var doUpdate = false;
  1357. var mutation;
  1358. FRAMEWORK.each(mutations, function () {
  1359. mutation = this;
  1360. doUpdate = isUnknownMutation(mutation);
  1361. return !doUpdate;
  1362. });
  1363. if (doUpdate) {
  1364. now = COMPATIBILITY.now();
  1365. sizeAuto = (_heightAutoCache || _widthAutoCache);
  1366. action = function () {
  1367. if(!_destroyed) {
  1368. contentLastUpdate = now;
  1369. //if cols, rows or wrap attr was changed
  1370. if (_isTextarea)
  1371. textareaUpdate();
  1372. if (sizeAuto)
  1373. update();
  1374. else
  1375. _base.update(_strAuto);
  1376. }
  1377. };
  1378. clearTimeout(contentTimeout);
  1379. if (mutationObserverContentLag <= 0 || now - contentLastUpdate > mutationObserverContentLag || !sizeAuto)
  1380. action();
  1381. else
  1382. contentTimeout = setTimeout(action, mutationObserverContentLag);
  1383. }
  1384. });
  1385. }
  1386. }
  1387. /**
  1388. * Connects the MutationObservers if they are supported.
  1389. */
  1390. function connectMutationObservers() {
  1391. if (_supportMutationObserver && !_mutationObserversConnected) {
  1392. _mutationObserverHost.observe(_hostElementNative, {
  1393. attributes: true,
  1394. attributeOldValue: true,
  1395. attributeFilter: [LEXICON.i, LEXICON.c, LEXICON.s]
  1396. });
  1397. _mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, {
  1398. attributes: true,
  1399. attributeOldValue: true,
  1400. subtree: !_isTextarea,
  1401. childList: !_isTextarea,
  1402. characterData: !_isTextarea,
  1403. attributeFilter: _isTextarea ? ['wrap', 'cols', 'rows'] : [LEXICON.i, LEXICON.c, LEXICON.s]
  1404. });
  1405. _mutationObserversConnected = true;
  1406. }
  1407. }
  1408. /**
  1409. * Disconnects the MutationObservers if they are supported.
  1410. */
  1411. function disconnectMutationObservers() {
  1412. if (_supportMutationObserver && _mutationObserversConnected) {
  1413. _mutationObserverHost.disconnect();
  1414. _mutationObserverContent.disconnect();
  1415. _mutationObserversConnected = false;
  1416. }
  1417. }
  1418. //==== Events of elements ====//
  1419. /**
  1420. * This method gets called every time the host element gets resized. IMPORTANT: Padding changes are detected too!!
  1421. * It refreshes the hostResizedEventArgs and the hostSizeResizeCache.
  1422. * If there are any size changes, the update method gets called.
  1423. */
  1424. function hostOnResized() {
  1425. if (_isSleeping)
  1426. return;
  1427. var changed;
  1428. var hostSize = {
  1429. w: _sizeObserverElementNative[LEXICON.sW],
  1430. h: _sizeObserverElementNative[LEXICON.sH]
  1431. };
  1432. if (_initialized) {
  1433. changed = checkCacheDouble(hostSize, _hostElementSizeChangeDetectedCache);
  1434. _hostElementSizeChangeDetectedCache = hostSize;
  1435. if (changed)
  1436. update(true, false);
  1437. }
  1438. else {
  1439. _hostElementSizeChangeDetectedCache = hostSize;
  1440. }
  1441. }
  1442. /**
  1443. * The mouse enter event of the host element. This event is only needed for the autoHide feature.
  1444. */
  1445. function hostOnMouseEnter() {
  1446. if (_scrollbarsAutoHideLeave)
  1447. refreshScrollbarsAutoHide(true);
  1448. }
  1449. /**
  1450. * The mouse leave event of the host element. This event is only needed for the autoHide feature.
  1451. */
  1452. function hostOnMouseLeave() {
  1453. if (_scrollbarsAutoHideLeave && !_bodyElement.hasClass(_classNameDragging))
  1454. refreshScrollbarsAutoHide(false);
  1455. }
  1456. /**
  1457. * The mouse move event of the host element. This event is only needed for the autoHide "move" feature.
  1458. */
  1459. function hostOnMouseMove() {
  1460. if (_scrollbarsAutoHideMove) {
  1461. refreshScrollbarsAutoHide(true);
  1462. clearTimeout(_scrollbarsAutoHideMoveTimeoutId);
  1463. _scrollbarsAutoHideMoveTimeoutId = setTimeout(function () {
  1464. if (_scrollbarsAutoHideMove && !_destroyed)
  1465. refreshScrollbarsAutoHide(false);
  1466. }, 100);
  1467. }
  1468. }
  1469. /**
  1470. * Adds or removes mouse & touch events of the host element. (for handling auto-hiding of the scrollbars)
  1471. * @param destroy Indicates whether the events shall be added or removed.
  1472. */
  1473. function setupHostMouseTouchEvents(destroy) {
  1474. var passiveEvent = destroy ? removePassiveEventListener : addPassiveEventListener;
  1475. var strOnOff = destroy ? 'off' : 'on';
  1476. var setupEvent = function(target, name, listener) {
  1477. if(_supportPassiveEvents)
  1478. passiveEvent(target, name, listener);
  1479. else
  1480. target[strOnOff](name, listener);
  1481. };
  1482. if(_scrollbarsAutoHideMove && !destroy)
  1483. setupEvent(_hostElement, _strMouseTouchMoveEvent, hostOnMouseMove);
  1484. else {
  1485. if(destroy)
  1486. setupEvent(_hostElement, _strMouseTouchMoveEvent, hostOnMouseMove);
  1487. setupEvent(_hostElement, _strMouseTouchEnter, hostOnMouseEnter);
  1488. setupEvent(_hostElement, _strMouseTouchLeave, hostOnMouseLeave);
  1489. }
  1490. //if the plugin is initialized and the mouse is over the host element, make the scrollbars visible
  1491. if(!_initialized && !destroy)
  1492. _hostElement.one("mouseover", hostOnMouseEnter);
  1493. }
  1494. /**
  1495. * Prevents text from deselection if attached to the document element on the mousedown event of a DOM element.
  1496. * @param event The select start event.
  1497. */
  1498. function documentOnSelectStart(event) {
  1499. COMPATIBILITY.prvD(event);
  1500. return false;
  1501. }
  1502. /**
  1503. * A callback which will be called after a img element has downloaded its src asynchronous.
  1504. */
  1505. function imgOnLoad() {
  1506. update(false, true);
  1507. }
  1508. //==== Update Detection ====//
  1509. /**
  1510. * Measures the min width and min height of the body element and refreshes the related cache.
  1511. * @returns {boolean} True if the min width or min height has changed, false otherwise.
  1512. */
  1513. function bodyMinSizeChanged() {
  1514. var bodyMinSize = {};
  1515. if (_isBody && _contentArrangeElement) {
  1516. bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth));
  1517. bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight));
  1518. bodyMinSize.c = checkCacheDouble(bodyMinSize, _bodyMinSizeCache);
  1519. bodyMinSize.f = true; //flag for "measured at least once"
  1520. }
  1521. _bodyMinSizeCache = bodyMinSize;
  1522. return bodyMinSize.c || false;
  1523. }
  1524. /**
  1525. * Returns true if the class names really changed (new class without plugin host prefix)
  1526. * @param oldCassNames The old ClassName string.
  1527. * @param newClassNames The new ClassName string.
  1528. * @returns {boolean} True if the class names has really changed, false otherwise.
  1529. */
  1530. function hostClassNamesChanged(oldCassNames, newClassNames) {
  1531. var currClasses = (newClassNames !== undefined && newClassNames !== null) ? newClassNames.split(_strSpace) : _strEmpty;
  1532. var oldClasses = (oldCassNames !== undefined && oldCassNames !== null) ? oldCassNames.split(_strSpace) : _strEmpty;
  1533. if (currClasses === _strEmpty && oldClasses === _strEmpty)
  1534. return false;
  1535. var diff = getArrayDifferences(oldClasses, currClasses);
  1536. var changed = false;
  1537. var oldClassNames = _oldClassName !== undefined && _oldClassName !== null ? _oldClassName.split(_strSpace) : [_strEmpty];
  1538. var currClassNames = _classNameCache !== undefined && _classNameCache !== null ? _classNameCache.split(_strSpace) : [_strEmpty];
  1539. //remove none theme from diff list to prevent update
  1540. var idx = FRAMEWORK.inArray(_classNameThemeNone, diff);
  1541. var curr;
  1542. var i;
  1543. var v;
  1544. var o;
  1545. var c;
  1546. if (idx > -1)
  1547. diff.splice(idx, 1);
  1548. for (i = 0; i < diff.length; i++) {
  1549. curr = diff[i];
  1550. if (curr.indexOf(_classNameHostElement) !== 0) {
  1551. o = true;
  1552. c = true;
  1553. for (v = 0; v < oldClassNames.length; v++) {
  1554. if (curr === oldClassNames[v]) {
  1555. o = false;
  1556. break;
  1557. }
  1558. }
  1559. for (v = 0; v < currClassNames.length; v++) {
  1560. if (curr === currClassNames[v]) {
  1561. c = false;
  1562. break;
  1563. }
  1564. }
  1565. if (o && c) {
  1566. changed = true;
  1567. break;
  1568. }
  1569. }
  1570. }
  1571. return changed;
  1572. }
  1573. /**
  1574. * 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.
  1575. * @param mutation The mutation which shall be checked.
  1576. * @returns {boolean} True if the mutation is from a unknown element, false otherwise.
  1577. */
  1578. function isUnknownMutation(mutation) {
  1579. var attributeName = mutation.attributeName;
  1580. var mutationTarget = mutation.target;
  1581. var mutationType = mutation.type;
  1582. var strClosest = 'closest';
  1583. if (mutationTarget === _contentElementNative)
  1584. return attributeName === null;
  1585. if (mutationType === 'attributes' && (attributeName === LEXICON.c || attributeName === LEXICON.s) && !_isTextarea) {
  1586. //ignore className changes by the plugin
  1587. if (attributeName === LEXICON.c && FRAMEWORK(mutationTarget).hasClass(_classNameHostElement))
  1588. return hostClassNamesChanged(mutation.oldValue, mutationTarget.getAttribute(LEXICON.c));
  1589. //only do it of browser support it natively
  1590. if (typeof mutationTarget[strClosest] != TYPES.f)
  1591. return true;
  1592. if (mutationTarget[strClosest](_strDot + _classNameResizeObserverElement) !== null ||
  1593. mutationTarget[strClosest](_strDot + _classNameScrollbar) !== null ||
  1594. mutationTarget[strClosest](_strDot + _classNameScrollbarCorner) !== null)
  1595. return false;
  1596. }
  1597. return true;
  1598. }
  1599. /**
  1600. * Returns true if the content size was changed since the last time this method was called.
  1601. * @returns {boolean} True if the content size was changed, false otherwise.
  1602. */
  1603. function updateAutoContentSizeChanged() {
  1604. if (_isSleeping)
  1605. return false;
  1606. var float;
  1607. var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0;
  1608. var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea;
  1609. var viewportScrollSize = { };
  1610. var css = { };
  1611. var bodyMinSizeC;
  1612. var changed;
  1613. var viewportScrollSizeChanged;
  1614. //fix for https://bugzilla.mozilla.org/show_bug.cgi?id=1439305, it only works with "clipAlways : true"
  1615. //it can work with "clipAlways : false" too, but we had to set the overflow of the viewportElement to hidden every time before measuring
  1616. if(_restrictedMeasuring) {
  1617. viewportScrollSize = {
  1618. x : _viewportElementNative[LEXICON.sW],
  1619. y : _viewportElementNative[LEXICON.sH]
  1620. }
  1621. }
  1622. if (setCSS) {
  1623. float = _contentElement.css(_strFloat);
  1624. css[_strFloat] = _isRTL ? _strRight : _strLeft;
  1625. css[_strWidth] = _strAuto;
  1626. _contentElement.css(css);
  1627. }
  1628. var contentElementScrollSize = {
  1629. w: getContentMeasureElement()[LEXICON.sW] + textareaValueLength,
  1630. h: getContentMeasureElement()[LEXICON.sH] + textareaValueLength
  1631. };
  1632. if (setCSS) {
  1633. css[_strFloat] = float;
  1634. css[_strWidth] = _strHundredPercent;
  1635. _contentElement.css(css);
  1636. }
  1637. bodyMinSizeC = bodyMinSizeChanged();
  1638. changed = checkCacheDouble(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache);
  1639. viewportScrollSizeChanged = checkCacheDouble(viewportScrollSize, _viewportScrollSizeCache, _strX, _strY);
  1640. _contentElementScrollSizeChangeDetectedCache = contentElementScrollSize;
  1641. _viewportScrollSizeCache = viewportScrollSize;
  1642. return changed || bodyMinSizeC || viewportScrollSizeChanged;
  1643. }
  1644. /**
  1645. * Returns true if the host element attributes (id, class, style) was changed since the last time this method was called.
  1646. * @returns {boolean}
  1647. */
  1648. function meaningfulAttrsChanged() {
  1649. if (_isSleeping || _mutationObserversConnected)
  1650. return false;
  1651. var hostElementId = _hostElement.attr(LEXICON.i) || _strEmpty;
  1652. var hostElementIdChanged = checkCacheSingle(hostElementId, _updateAutoHostElementIdCache);
  1653. var hostElementClass = _hostElement.attr(LEXICON.c) || _strEmpty;
  1654. var hostElementClassChanged = checkCacheSingle(hostElementClass, _updateAutoHostElementClassCache);
  1655. var hostElementStyle = _hostElement.attr(LEXICON.s) || _strEmpty;
  1656. var hostElementStyleChanged = checkCacheSingle(hostElementStyle, _updateAutoHostElementStyleCache);
  1657. var hostElementVisible = _hostElement.is(':visible') || _strEmpty;
  1658. var hostElementVisibleChanged = checkCacheSingle(hostElementVisible, _updateAutoHostElementVisibleCache);
  1659. var targetElementRows = _isTextarea ? (_targetElement.attr('rows') || _strEmpty) : _strEmpty;
  1660. var targetElementRowsChanged = checkCacheSingle(targetElementRows, _updateAutoTargetElementRowsCache);
  1661. var targetElementCols = _isTextarea ? (_targetElement.attr('cols') || _strEmpty) : _strEmpty;
  1662. var targetElementColsChanged = checkCacheSingle(targetElementCols, _updateAutoTargetElementColsCache);
  1663. var targetElementWrap = _isTextarea ? (_targetElement.attr('wrap') || _strEmpty) : _strEmpty;
  1664. var targetElementWrapChanged = checkCacheSingle(targetElementWrap, _updateAutoTargetElementWrapCache);
  1665. _updateAutoHostElementIdCache = hostElementId;
  1666. if (hostElementClassChanged)
  1667. hostElementClassChanged = hostClassNamesChanged(_updateAutoHostElementClassCache, hostElementClass);
  1668. _updateAutoHostElementClassCache = hostElementClass;
  1669. _updateAutoHostElementStyleCache = hostElementStyle;
  1670. _updateAutoHostElementVisibleCache = hostElementVisible;
  1671. _updateAutoTargetElementRowsCache = targetElementRows;
  1672. _updateAutoTargetElementColsCache = targetElementCols;
  1673. _updateAutoTargetElementWrapCache = targetElementWrap;
  1674. return hostElementIdChanged || hostElementClassChanged || hostElementStyleChanged || hostElementVisibleChanged || targetElementRowsChanged || targetElementColsChanged || targetElementWrapChanged;
  1675. }
  1676. /**
  1677. * Checks is a CSS Property of a child element is affecting the scroll size of the content.
  1678. * @param propertyName The CSS property name.
  1679. * @returns {boolean} True if the property is affecting the content scroll size, false otherwise.
  1680. */
  1681. function isSizeAffectingCSSProperty(propertyName) {
  1682. if (!_initialized)
  1683. return true;
  1684. var flexGrow = 'flex-grow';
  1685. var flexShrink = 'flex-shrink';
  1686. var flexBasis = 'flex-basis';
  1687. var affectingPropsX = [
  1688. _strWidth,
  1689. _strMinMinus + _strWidth,
  1690. _strMaxMinus + _strWidth,
  1691. _strMarginMinus + _strLeft,
  1692. _strMarginMinus + _strRight,
  1693. _strLeft,
  1694. _strRight,
  1695. 'font-weight',
  1696. 'word-spacing',
  1697. flexGrow,
  1698. flexShrink,
  1699. flexBasis
  1700. ];
  1701. var affectingPropsXContentBox = [
  1702. _strPaddingMinus + _strLeft,
  1703. _strPaddingMinus + _strRight,
  1704. _strBorderMinus + _strLeft + _strWidth,
  1705. _strBorderMinus + _strRight + _strWidth
  1706. ];
  1707. var affectingPropsY = [
  1708. _strHeight,
  1709. _strMinMinus + _strHeight,
  1710. _strMaxMinus + _strHeight,
  1711. _strMarginMinus + _strTop,
  1712. _strMarginMinus + _strBottom,
  1713. _strTop,
  1714. _strBottom,
  1715. 'line-height',
  1716. flexGrow,
  1717. flexShrink,
  1718. flexBasis
  1719. ];
  1720. var affectingPropsYContentBox = [
  1721. _strPaddingMinus + _strTop,
  1722. _strPaddingMinus + _strBottom,
  1723. _strBorderMinus + _strTop + _strWidth,
  1724. _strBorderMinus + _strBottom + _strWidth
  1725. ];
  1726. var _strS = 's';
  1727. var _strVS = 'v-s';
  1728. var checkX = _overflowBehaviorCache.x === _strS || _overflowBehaviorCache.x === _strVS;
  1729. var checkY = _overflowBehaviorCache.y === _strS || _overflowBehaviorCache.y === _strVS;
  1730. var sizeIsAffected = false;
  1731. var checkPropertyName = function (arr, name) {
  1732. for (var i = 0; i < arr[LEXICON.l]; i++) {
  1733. if (arr[i] === name)
  1734. return true;
  1735. }
  1736. return false;
  1737. };
  1738. if (checkY) {
  1739. sizeIsAffected = checkPropertyName(affectingPropsY, propertyName);
  1740. if (!sizeIsAffected && !_isBorderBox)
  1741. sizeIsAffected = checkPropertyName(affectingPropsYContentBox, propertyName);
  1742. }
  1743. if (checkX && !sizeIsAffected) {
  1744. sizeIsAffected = checkPropertyName(affectingPropsX, propertyName);
  1745. if (!sizeIsAffected && !_isBorderBox)
  1746. sizeIsAffected = checkPropertyName(affectingPropsXContentBox, propertyName);
  1747. }
  1748. return sizeIsAffected;
  1749. }
  1750. //==== Update ====//
  1751. /**
  1752. * Updates the variables and size of the textarea element, and manages the scroll on new line or new character.
  1753. */
  1754. function textareaUpdate() {
  1755. if (_isSleeping)
  1756. return;
  1757. var wrapAttrOff = !_textareaAutoWrappingCache;
  1758. var minWidth = _viewportSize.w /* - (!_isBorderBox && !_paddingAbsoluteCache && _widthAutoCache ? _paddingY + _borderY : 0) */;
  1759. var minHeight = _viewportSize.h /* - (!_isBorderBox && !_paddingAbsoluteCache && _heightAutoCache ? _paddingY + _borderY : 0) */;
  1760. var css = { };
  1761. var doMeasure = _widthAutoCache || wrapAttrOff;
  1762. var origWidth;
  1763. var width;
  1764. var origHeight;
  1765. var height;
  1766. //reset min size
  1767. css[_strMinMinus + _strWidth] = _strEmpty;
  1768. css[_strMinMinus + _strHeight] = _strEmpty;
  1769. //set width auto
  1770. css[_strWidth] = _strAuto;
  1771. _targetElement.css(css);
  1772. //measure width
  1773. origWidth = _targetElementNative[LEXICON.oW];
  1774. width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1;
  1775. /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/
  1776. //set measured width
  1777. css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent;
  1778. css[_strMinMinus + _strWidth] = _strHundredPercent;
  1779. //set height auto
  1780. css[_strHeight] = _strAuto;
  1781. _targetElement.css(css);
  1782. //measure height
  1783. origHeight = _targetElementNative[LEXICON.oH];
  1784. height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1);
  1785. //append correct size values
  1786. css[_strWidth] = width;
  1787. css[_strHeight] = height;
  1788. _textareaCoverElement.css(css);
  1789. //apply min width / min height to prevent textarea collapsing
  1790. css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/;
  1791. css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/;
  1792. _targetElement.css(css);
  1793. return {
  1794. _originalWidth: origWidth,
  1795. _originalHeight: origHeight,
  1796. _dynamicWidth: width,
  1797. _dynamicHeight: height
  1798. };
  1799. }
  1800. /**
  1801. * Updates the plugin and DOM to the current options.
  1802. * This method should only be called if a update is 100% required.
  1803. * @param hostSizeChanged True if this method was called due to a host size change.
  1804. * @param contentSizeChanged True if this method was called due to a content size change.
  1805. * @param force True if every property shall be updated and the cache shall be ignored.
  1806. * @param preventSwallowing True if this method shall be executed event if it could be swallowed.
  1807. */
  1808. function update(hostSizeChanged, contentSizeChanged, force, preventSwallowing) {
  1809. var now = COMPATIBILITY.now();
  1810. var swallow = _swallowUpdateLag > 0 && _initialized && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache) && !preventSwallowing;
  1811. var displayIsHidden = _hostElement.is(':hidden');
  1812. var displayIsHiddenChanged = checkCacheSingle(displayIsHidden, _displayIsHiddenCache, force);
  1813. _displayIsHiddenCache = displayIsHidden;
  1814. clearTimeout(_swallowedUpdateTimeout);
  1815. if (swallow) {
  1816. _swallowedUpdateParams.h = _swallowedUpdateParams.h || hostSizeChanged;
  1817. _swallowedUpdateParams.c = _swallowedUpdateParams.c || contentSizeChanged;
  1818. _swallowedUpdateParams.f = _swallowedUpdateParams.f || force;
  1819. _swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag);
  1820. }
  1821. //abort update due to:
  1822. //destroyed
  1823. //swallowing
  1824. //sleeping
  1825. //host is hidden or has false display
  1826. if (_destroyed || swallow || _isSleeping || (_initialized && !force && displayIsHidden) || _hostElement.css('display') === 'inline')
  1827. return;
  1828. _lastUpdateTime = now;
  1829. hostSizeChanged = hostSizeChanged || _swallowedUpdateParams.h;
  1830. contentSizeChanged = contentSizeChanged || _swallowedUpdateParams.c;
  1831. force = force || _swallowedUpdateParams.f;
  1832. _swallowedUpdateParams = {};
  1833. hostSizeChanged = hostSizeChanged === undefined ? false : hostSizeChanged;
  1834. contentSizeChanged = contentSizeChanged === undefined ? false : contentSizeChanged;
  1835. force = force === undefined ? false : force;
  1836. //if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely.
  1837. if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
  1838. //native scrollbars are hidden, so change the values to zero
  1839. _nativeScrollbarSize.x = 0;
  1840. _nativeScrollbarSize.y = 0;
  1841. }
  1842. else {
  1843. //refresh native scrollbar size (in case of zoom)
  1844. _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
  1845. }
  1846. // Scrollbar padding is needed for firefox, because firefox hides scrollbar automatically if the size of the div is too small.
  1847. // The calculation: [scrollbar size +3 *3]
  1848. // (+3 because of possible decoration e.g. borders, margins etc., but only if native scrollbar is NOT a overlaid scrollbar)
  1849. // (*3 because (1)increase / (2)decrease -button and (3)resize handle)
  1850. _nativeScrollbarMinSize = {
  1851. x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3,
  1852. y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 3
  1853. };
  1854. freezeResizeObserver(_sizeObserverElement);
  1855. freezeResizeObserver(_sizeAutoObserverElement);
  1856. //save current scroll offset
  1857. var currScroll = {
  1858. x: _viewportElement[_strScrollLeft](),
  1859. y: _viewportElement[_strScrollTop]()
  1860. };
  1861. var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars;
  1862. var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea;
  1863. //scrollbars visibility:
  1864. var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility;
  1865. var scrollbarsVisibilityChanged = checkCacheSingle(scrollbarsVisibility, _scrollbarsVisibilityCache, force);
  1866. //scrollbars autoHide:
  1867. var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide;
  1868. var scrollbarsAutoHideChanged = checkCacheSingle(scrollbarsAutoHide, _scrollbarsAutoHideCache, force);
  1869. //scrollbars click scrolling
  1870. var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling;
  1871. var scrollbarsClickScrollingChanged = checkCacheSingle(scrollbarsClickScrolling, _scrollbarsClickScrollingCache, force);
  1872. //scrollbars drag scrolling
  1873. var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling;
  1874. var scrollbarsDragScrollingChanged = checkCacheSingle(scrollbarsDragScrolling, _scrollbarsDragScrollingCache, force);
  1875. //className
  1876. var className = _currentPreparedOptions.className;
  1877. var classNameChanged = checkCacheSingle(className, _classNameCache, force);
  1878. //resize
  1879. var resize = _currentPreparedOptions.resize;
  1880. var resizeChanged = checkCacheSingle(resize, _resizeCache, force) && !_isBody; //body can't be resized since the window itself acts as resize possibility.
  1881. //textarea AutoWrapping
  1882. var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false;
  1883. var textareaAutoWrappingChanged = checkCacheSingle(textareaAutoWrapping, _textareaAutoWrappingCache, force);
  1884. //paddingAbsolute
  1885. var paddingAbsolute = _currentPreparedOptions.paddingAbsolute;
  1886. var paddingAbsoluteChanged = checkCacheSingle(paddingAbsolute, _paddingAbsoluteCache, force);
  1887. //clipAlways
  1888. var clipAlways = _currentPreparedOptions.clipAlways;
  1889. var clipAlwaysChanged = checkCacheSingle(clipAlways, _clipAlwaysCache, force);
  1890. //sizeAutoCapable
  1891. var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport.
  1892. var sizeAutoCapableChanged = checkCacheSingle(sizeAutoCapable, _sizeAutoCapableCache, force);
  1893. //showNativeScrollbars
  1894. var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars;
  1895. var ignoreOverlayScrollbarHidingChanged = checkCacheSingle(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache);
  1896. //autoUpdate
  1897. var autoUpdate = _currentPreparedOptions.autoUpdate;
  1898. var autoUpdateChanged = checkCacheSingle(autoUpdate, _autoUpdateCache);
  1899. //overflowBehavior
  1900. var overflowBehavior = _currentPreparedOptions.overflowBehavior;
  1901. var overflowBehaviorChanged = checkCacheDouble(overflowBehavior, _overflowBehaviorCache, _strX, _strY, force);
  1902. //dynWidth:
  1903. var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth;
  1904. var textareaDynWidthChanged = checkCacheSingle(_textareaDynWidthCache, textareaDynWidth);
  1905. //dynHeight:
  1906. var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight;
  1907. var textareaDynHeightChanged = checkCacheSingle(_textareaDynHeightCache, textareaDynHeight);
  1908. //scrollbars visibility
  1909. _scrollbarsAutoHideNever = scrollbarsAutoHide === 'n';
  1910. _scrollbarsAutoHideScroll = scrollbarsAutoHide === 's';
  1911. _scrollbarsAutoHideMove = scrollbarsAutoHide === 'm';
  1912. _scrollbarsAutoHideLeave = scrollbarsAutoHide === 'l';
  1913. //scrollbars autoHideDelay
  1914. _scrollbarsAutoHideDelay = currentPreparedOptionsScrollbars.autoHideDelay;
  1915. //old className
  1916. _oldClassName = _classNameCache;
  1917. //resize
  1918. _resizeNone = resize === 'n';
  1919. _resizeBoth = resize === 'b';
  1920. _resizeHorizontal = resize === 'h';
  1921. _resizeVertical = resize === 'v';
  1922. //normalizeRTL
  1923. _normalizeRTLCache = _currentPreparedOptions.normalizeRTL;
  1924. //ignore overlay scrollbar hiding
  1925. ignoreOverlayScrollbarHiding = ignoreOverlayScrollbarHiding && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y);
  1926. //refresh options cache
  1927. _scrollbarsVisibilityCache = scrollbarsVisibility;
  1928. _scrollbarsAutoHideCache = scrollbarsAutoHide;
  1929. _scrollbarsClickScrollingCache = scrollbarsClickScrolling;
  1930. _scrollbarsDragScrollingCache = scrollbarsDragScrolling;
  1931. _classNameCache = className;
  1932. _resizeCache = resize;
  1933. _textareaAutoWrappingCache = textareaAutoWrapping;
  1934. _paddingAbsoluteCache = paddingAbsolute;
  1935. _clipAlwaysCache = clipAlways;
  1936. _sizeAutoCapableCache = sizeAutoCapable;
  1937. _ignoreOverlayScrollbarHidingCache = ignoreOverlayScrollbarHiding;
  1938. _autoUpdateCache = autoUpdate;
  1939. _overflowBehaviorCache = extendDeep({}, overflowBehavior);
  1940. _textareaDynWidthCache = textareaDynWidth;
  1941. _textareaDynHeightCache = textareaDynHeight;
  1942. _hasOverflowCache = _hasOverflowCache || { x: false, y: false };
  1943. //set correct class name to the host element
  1944. if (classNameChanged) {
  1945. removeClass(_hostElement, _oldClassName + _strSpace + _classNameThemeNone);
  1946. addClass(_hostElement, className !== undefined && className !== null && className.length > 0 ? className : _classNameThemeNone);
  1947. }
  1948. //set correct auto Update
  1949. if (autoUpdateChanged) {
  1950. if (autoUpdate === true) {
  1951. disconnectMutationObservers();
  1952. autoUpdateLoop.add(_base);
  1953. }
  1954. else if (autoUpdate === null) {
  1955. if (_autoUpdateRecommended) {
  1956. disconnectMutationObservers();
  1957. autoUpdateLoop.add(_base);
  1958. }
  1959. else {
  1960. autoUpdateLoop.remove(_base);
  1961. connectMutationObservers();
  1962. }
  1963. }
  1964. else {
  1965. autoUpdateLoop.remove(_base);
  1966. connectMutationObservers();
  1967. }
  1968. }
  1969. //activate or deactivate size auto capability
  1970. if (sizeAutoCapableChanged) {
  1971. if (sizeAutoCapable) {
  1972. if (!_contentGlueElement) {
  1973. _contentGlueElement = FRAMEWORK(generateDiv(_classNameContentGlueElement));
  1974. _paddingElement.before(_contentGlueElement);
  1975. }
  1976. else {
  1977. _contentGlueElement.show();
  1978. }
  1979. if (_sizeAutoObserverAdded) {
  1980. _sizeAutoObserverElement.show();
  1981. }
  1982. else {
  1983. _sizeAutoObserverElement = FRAMEWORK(generateDiv(_classNameSizeAutoObserverElement));
  1984. _sizeAutoObserverElementNative = _sizeAutoObserverElement[0];
  1985. _contentGlueElement.before(_sizeAutoObserverElement);
  1986. var oldSize = {w: -1, h: -1};
  1987. addResizeObserver(_sizeAutoObserverElement, function () {
  1988. var newSize = {
  1989. w: _sizeAutoObserverElementNative[LEXICON.oW],
  1990. h: _sizeAutoObserverElementNative[LEXICON.oH]
  1991. };
  1992. if (checkCacheDouble(newSize, oldSize)) {
  1993. if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) {
  1994. update();
  1995. }
  1996. else if (_initialized && (!_heightAutoCache && newSize.h === 0) || (!_widthAutoCache && newSize.w === 0)) {
  1997. update();
  1998. }
  1999. }
  2000. oldSize = newSize;
  2001. });
  2002. _sizeAutoObserverAdded = true;
  2003. //fix heightAuto detector bug if height is fixed but contentHeight is 0.
  2004. //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.
  2005. if (_cssCalc !== null)
  2006. _sizeAutoObserverElement.css(_strHeight, _cssCalc + '(100% + 1px)');
  2007. }
  2008. }
  2009. else {
  2010. if (_sizeAutoObserverAdded)
  2011. _sizeAutoObserverElement.hide();
  2012. if (_contentGlueElement)
  2013. _contentGlueElement.hide();
  2014. }
  2015. }
  2016. //if force, update all resizeObservers too
  2017. if (force) {
  2018. _sizeObserverElement.find('*').trigger(_strScroll);
  2019. if (_sizeAutoObserverAdded)
  2020. _sizeAutoObserverElement.find('*').trigger(_strScroll);
  2021. }
  2022. //detect direction:
  2023. var cssDirection = _hostElement.css('direction');
  2024. var cssDirectionChanged = checkCacheSingle(cssDirection, _cssDirectionCache, force);
  2025. //detect box-sizing:
  2026. var boxSizing = _hostElement.css('box-sizing');
  2027. var boxSizingChanged = checkCacheSingle(boxSizing, _cssBoxSizingCache, force);
  2028. //detect padding:
  2029. var padding = {
  2030. c: force,
  2031. t: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strTop)),
  2032. r: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strRight)),
  2033. b: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strBottom)),
  2034. l: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strLeft))
  2035. };
  2036. //width + height auto detecting var:
  2037. var sizeAutoObserverElementBCRect;
  2038. //exception occurs in IE8 sometimes (unknown exception)
  2039. try {
  2040. sizeAutoObserverElementBCRect = _sizeAutoObserverAdded ? _sizeAutoObserverElementNative.getBoundingClientRect() : null;
  2041. } catch (ex) {
  2042. return;
  2043. }
  2044. _isRTL = cssDirection === 'rtl';
  2045. _isBorderBox = (boxSizing === 'border-box');
  2046. var isRTLLeft = _isRTL ? _strLeft : _strRight;
  2047. var isRTLRight = _isRTL ? _strRight : _strLeft;
  2048. //detect width auto:
  2049. var widthAutoResizeDetection = false;
  2050. var widthAutoObserverDetection = (_sizeAutoObserverAdded && (_hostElement.css(_strFloat) !== 'none' /*|| _isTextarea */)) ? (MATH.round(sizeAutoObserverElementBCRect.right - sizeAutoObserverElementBCRect.left) === 0) && (!paddingAbsolute ? (_hostElementNative[LEXICON.cW] - _paddingX) > 0 : true) : false;
  2051. if (sizeAutoCapable && !widthAutoObserverDetection) {
  2052. var tmpCurrHostWidth = _hostElementNative[LEXICON.oW];
  2053. var tmpCurrContentGlueWidth = _contentGlueElement.css(_strWidth);
  2054. _contentGlueElement.css(_strWidth, _strAuto);
  2055. var tmpNewHostWidth = _hostElementNative[LEXICON.oW];
  2056. _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
  2057. widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
  2058. if (!widthAutoResizeDetection) {
  2059. _contentGlueElement.css(_strWidth, tmpCurrHostWidth + 1);
  2060. tmpNewHostWidth = _hostElementNative[LEXICON.oW];
  2061. _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
  2062. widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
  2063. }
  2064. }
  2065. var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden;
  2066. var widthAutoChanged = checkCacheSingle(widthAuto, _widthAutoCache, force);
  2067. var wasWidthAuto = !widthAuto && _widthAutoCache;
  2068. //detect height auto:
  2069. var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false;
  2070. var heightAutoChanged = checkCacheSingle(heightAuto, _heightAutoCache, force);
  2071. var wasHeightAuto = !heightAuto && _heightAutoCache;
  2072. //detect border:
  2073. //we need the border only if border box and auto size
  2074. var strMinusWidth = '-' + _strWidth;
  2075. var updateBorderX = (widthAuto && _isBorderBox) || !_isBorderBox;
  2076. var updateBorderY = (heightAuto && _isBorderBox) || !_isBorderBox;
  2077. var border = {
  2078. c: force,
  2079. t: updateBorderY ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strTop + strMinusWidth), true) : 0,
  2080. r: updateBorderX ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strRight + strMinusWidth), true) : 0,
  2081. b: updateBorderY ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strBottom + strMinusWidth), true) : 0,
  2082. l: updateBorderX ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strLeft + strMinusWidth), true) : 0
  2083. };
  2084. //detect margin:
  2085. var margin = {
  2086. c: force,
  2087. t: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strTop)),
  2088. r: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strRight)),
  2089. b: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strBottom)),
  2090. l: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strLeft))
  2091. };
  2092. //detect css max width & height:
  2093. var cssMaxValue = {
  2094. h: String(_hostElement.css(_strMaxMinus + _strHeight)),
  2095. w: String(_hostElement.css(_strMaxMinus + _strWidth))
  2096. };
  2097. //vars to apply correct css
  2098. var contentElementCSS = { };
  2099. var contentGlueElementCSS = { };
  2100. //funcs
  2101. var getHostSize = function() {
  2102. //has to be clientSize because offsetSize respect borders
  2103. return {
  2104. w: _hostElementNative[LEXICON.cW],
  2105. h: _hostElementNative[LEXICON.cH]
  2106. };
  2107. };
  2108. var getViewportSize = function() {
  2109. //viewport size is padding container because it never has padding, margin and a border
  2110. //determine zoom rounding error -> sometimes scrollWidth/Height is smaller than clientWidth/Height
  2111. //if this happens add the difference to the viewportSize to compensate the rounding error
  2112. return {
  2113. w: _paddingElementNative[LEXICON.oW] + MATH.max(0, _contentElementNative[LEXICON.cW] - _contentElementNative[LEXICON.sW]),
  2114. h: _paddingElementNative[LEXICON.oH] + MATH.max(0, _contentElementNative[LEXICON.cH] - _contentElementNative[LEXICON.sH])
  2115. };
  2116. };
  2117. //set info for padding
  2118. var paddingAbsoluteX = _paddingX = padding.l + padding.r;
  2119. var paddingAbsoluteY = _paddingY = padding.t + padding.b;
  2120. paddingAbsoluteX *=
  2121. paddingAbsoluteY *= paddingAbsolute ? 1 : 0;
  2122. padding.c = checkCacheTRBL(padding, _cssPaddingCache);
  2123. //set info for border
  2124. _borderX = border.l + border.r;
  2125. _borderY = border.t + border.b;
  2126. border.c = checkCacheTRBL(border, _cssBorderCache);
  2127. //set info for margin
  2128. _marginX = margin.l + margin.r;
  2129. _marginY = margin.t + margin.b;
  2130. margin.c = checkCacheTRBL(margin, _cssMarginCache);
  2131. //set info for css max value
  2132. cssMaxValue.ih = parseToZeroOrNumber(cssMaxValue.h); //ih = integer height
  2133. cssMaxValue.iw = parseToZeroOrNumber(cssMaxValue.w); //iw = integer width
  2134. cssMaxValue.ch = cssMaxValue.h.indexOf('px') > -1; //ch = correct height
  2135. cssMaxValue.cw = cssMaxValue.w.indexOf('px') > -1; //cw = correct width
  2136. cssMaxValue.c = checkCacheDouble(cssMaxValue, _cssMaxValueCache, force);
  2137. //refresh cache
  2138. _cssDirectionCache = cssDirection;
  2139. _cssBoxSizingCache = boxSizing;
  2140. _widthAutoCache = widthAuto;
  2141. _heightAutoCache = heightAuto;
  2142. _cssPaddingCache = padding;
  2143. _cssBorderCache = border;
  2144. _cssMarginCache = margin;
  2145. _cssMaxValueCache = cssMaxValue;
  2146. //IEFix direction changed
  2147. if (cssDirectionChanged && _sizeAutoObserverAdded)
  2148. _sizeAutoObserverElement.css(_strFloat, isRTLRight);
  2149. //apply padding:
  2150. if (padding.c || cssDirectionChanged || paddingAbsoluteChanged || widthAutoChanged || heightAutoChanged || boxSizingChanged || sizeAutoCapableChanged) {
  2151. var paddingElementCSS = {};
  2152. var textareaCSS = {};
  2153. setTopRightBottomLeft(contentGlueElementCSS, _strMarginMinus, [-padding.t, -padding.r, -padding.b, -padding.l]);
  2154. if (paddingAbsolute) {
  2155. setTopRightBottomLeft(paddingElementCSS, _strEmpty, [padding.t, padding.r, padding.b, padding.l]);
  2156. if (_isTextarea)
  2157. setTopRightBottomLeft(textareaCSS, _strPaddingMinus);
  2158. else
  2159. setTopRightBottomLeft(contentElementCSS, _strPaddingMinus);
  2160. }
  2161. else {
  2162. setTopRightBottomLeft(paddingElementCSS, _strEmpty);
  2163. if (_isTextarea)
  2164. setTopRightBottomLeft(textareaCSS, _strPaddingMinus, [padding.t, padding.r, padding.b, padding.l]);
  2165. else
  2166. setTopRightBottomLeft(contentElementCSS, _strPaddingMinus, [padding.t, padding.r, padding.b, padding.l]);
  2167. }
  2168. _paddingElement.css(paddingElementCSS);
  2169. _targetElement.css(textareaCSS);
  2170. }
  2171. //viewport size is padding container because it never has padding, margin and a border.
  2172. _viewportSize = getViewportSize();
  2173. //update Textarea
  2174. var textareaSize = _isTextarea ? textareaUpdate() : false;
  2175. //fix height auto / width auto in cooperation with current padding & boxSizing behavior:
  2176. if (heightAuto && (heightAutoChanged || paddingAbsoluteChanged || boxSizingChanged || cssMaxValue.c || padding.c || border.c)) {
  2177. //if (cssMaxValue.ch)
  2178. contentElementCSS[_strMaxMinus + _strHeight] =
  2179. (cssMaxValue.ch ? (cssMaxValue.ih - paddingAbsoluteY + (_isBorderBox ? -_borderY : _paddingY))
  2180. : _strEmpty);
  2181. contentElementCSS[_strHeight] = _strAuto;
  2182. }
  2183. else if (heightAutoChanged || paddingAbsoluteChanged) {
  2184. contentElementCSS[_strMaxMinus + _strHeight] = _strEmpty;
  2185. contentElementCSS[_strHeight] = _strHundredPercent;
  2186. }
  2187. if (widthAuto && (widthAutoChanged || paddingAbsoluteChanged || boxSizingChanged || cssMaxValue.c || padding.c || border.c || cssDirectionChanged)) {
  2188. //if (cssMaxValue.cw)
  2189. contentElementCSS[_strMaxMinus + _strWidth] =
  2190. (cssMaxValue.cw ? (cssMaxValue.iw - paddingAbsoluteX + (_isBorderBox ? -_borderX : _paddingX)) +
  2191. (_nativeScrollbarIsOverlaid.y /*&& _hasOverflowCache.y && widthAuto */ ? _overlayScrollbarDummySize.y : 0)
  2192. : _strEmpty);
  2193. contentElementCSS[_strWidth] = _strAuto;
  2194. contentGlueElementCSS[_strMaxMinus + _strWidth] = _strHundredPercent; //IE Fix
  2195. }
  2196. else if (widthAutoChanged || paddingAbsoluteChanged) {
  2197. contentElementCSS[_strMaxMinus + _strWidth] = _strEmpty;
  2198. contentElementCSS[_strWidth] = _strHundredPercent;
  2199. contentElementCSS[_strFloat] = _strEmpty;
  2200. contentGlueElementCSS[_strMaxMinus + _strWidth] = _strEmpty; //IE Fix
  2201. }
  2202. if (widthAuto) {
  2203. if (!cssMaxValue.cw)
  2204. contentElementCSS[_strMaxMinus + _strWidth] = _strEmpty;
  2205. contentGlueElementCSS[_strWidth] = _isTextarea && textareaDynWidth ? textareaSize._dynamicWidth : _strAuto;
  2206. contentElementCSS[_strWidth] = _strAuto;
  2207. contentElementCSS[_strFloat] = isRTLRight;
  2208. }
  2209. else {
  2210. contentGlueElementCSS[_strWidth] = _strEmpty;
  2211. }
  2212. if (heightAuto) {
  2213. if (!cssMaxValue.ch)
  2214. contentElementCSS[_strMaxMinus + _strHeight] = _strEmpty;
  2215. //fix dyn height collapse bug: (doesn't works for width!)
  2216. //contentGlueElementCSS[_strHeight] = _isTextarea && textareaDynHeight ? textareaSize._dynamicHeight : _strAuto;
  2217. contentGlueElementCSS[_strHeight] = _isTextarea ? textareaDynHeight ? textareaSize._dynamicHeight : _strAuto : _contentElementNative[LEXICON.cH];
  2218. }
  2219. else {
  2220. contentGlueElementCSS[_strHeight] = _strEmpty;
  2221. }
  2222. if (sizeAutoCapable)
  2223. _contentGlueElement.css(contentGlueElementCSS);
  2224. _contentElement.css(contentElementCSS);
  2225. //CHECKPOINT HERE ~
  2226. contentElementCSS = {};
  2227. contentGlueElementCSS = {};
  2228. //if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true
  2229. if (hostSizeChanged || contentSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || cssMaxValue.c || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged || force) {
  2230. var strOverflow = 'overflow';
  2231. var strOverflowX = strOverflow + '-x';
  2232. var strOverflowY = strOverflow + '-y';
  2233. var strHidden = 'hidden';
  2234. var strVisible = 'visible';
  2235. //decide whether the content overflow must get hidden for correct overflow measuring, it !MUST! be always hidden if the height is auto
  2236. var hideOverflow4CorrectMeasuring = _restrictedMeasuring ?
  2237. (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) || //it must be hidden if native scrollbars are overlaid
  2238. (_viewportSize.w < _nativeScrollbarMinSize.y || _viewportSize.h < _nativeScrollbarMinSize.x) || //it must be hidden if host-element is too small
  2239. heightAuto || displayIsHiddenChanged //it must be hidden if height is auto or display was change
  2240. : heightAuto; //if there is not the restricted Measuring bug, it must be hidden if the height is auto
  2241. //Reset the viewport (very important for natively overlaid scrollbars and zoom change
  2242. //don't change the overflow prop as it is very expensive and affects performance !A LOT!
  2243. var viewportElementResetCSS = { };
  2244. var resetXTmp = _hasOverflowCache.y && _hideOverflowCache.ys && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.y ? _viewportElement.css(isRTLLeft) : -_nativeScrollbarSize.y) : 0;
  2245. var resetBottomTmp = _hasOverflowCache.x && _hideOverflowCache.xs && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.x ? _viewportElement.css(_strBottom) : -_nativeScrollbarSize.x) : 0;
  2246. setTopRightBottomLeft(viewportElementResetCSS, _strEmpty);
  2247. _viewportElement.css(viewportElementResetCSS);
  2248. if(hideOverflow4CorrectMeasuring)
  2249. _contentElement.css(strOverflow, strHidden);
  2250. //measure several sizes:
  2251. var contentMeasureElement = getContentMeasureElement();
  2252. //in Firefox content element has to have overflow hidden, else element margins aren't calculated properly, this element prevents this bug, but only if scrollbars aren't overlaid
  2253. var contentMeasureElementGuaranty = _restrictedMeasuring && !hideOverflow4CorrectMeasuring ? _viewportElementNative : contentMeasureElement;
  2254. var contentSize = {
  2255. //use clientSize because natively overlaidScrollbars add borders
  2256. w: _isTextarea && textareaSize ? (textareaDynWidth ? textareaSize._dynamicWidth : textareaSize._originalWidth) : contentMeasureElement[LEXICON.cW],
  2257. h: _isTextarea && textareaSize ? (textareaDynHeight ? textareaSize._dynamicHeight : textareaSize._originalHeight) : contentMeasureElement[LEXICON.cH]
  2258. };
  2259. var scrollSize = {
  2260. w: MATH.max(contentMeasureElement[LEXICON.sW], contentMeasureElementGuaranty[LEXICON.sW]),
  2261. h: MATH.max(contentMeasureElement[LEXICON.sH], contentMeasureElementGuaranty[LEXICON.sH])
  2262. };
  2263. //apply the correct viewport style and measure viewport size
  2264. viewportElementResetCSS[_strBottom] = wasHeightAuto ? _strEmpty : resetBottomTmp;
  2265. viewportElementResetCSS[isRTLLeft] = wasWidthAuto ? _strEmpty : resetXTmp;
  2266. _viewportElement.css(viewportElementResetCSS);
  2267. _viewportSize = getViewportSize();
  2268. //measure and correct several sizes
  2269. var hostSize = getHostSize();
  2270. var contentGlueSize = {
  2271. //client/scrollSize + AbsolutePadding -> because padding is only applied to the paddingElement if its absolute, so you have to add it manually
  2272. //hostSize is clientSize -> so padding should be added manually, right? FALSE! Because content glue is inside hostElement, so we don't have to worry about padding
  2273. w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostSize.w),
  2274. h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostSize.h)
  2275. };
  2276. contentGlueSize.c = checkCacheDouble(contentGlueSize, _contentGlueSizeCache, force);
  2277. _contentGlueSizeCache = contentGlueSize;
  2278. //apply correct contentGlue size
  2279. if (sizeAutoCapable) {
  2280. //size contentGlue correctly to make sure the element has correct size if the sizing switches to auto
  2281. if (contentGlueSize.c || (heightAuto || widthAuto)) {
  2282. contentGlueElementCSS[_strWidth] = contentGlueSize.w;
  2283. contentGlueElementCSS[_strHeight] = contentGlueSize.h;
  2284. //textarea-sizes are already calculated correctly at this point
  2285. if(!_isTextarea) {
  2286. contentSize = {
  2287. //use clientSize because natively overlaidScrollbars add borders
  2288. w: contentMeasureElement[LEXICON.cW],
  2289. h: contentMeasureElement[LEXICON.cH]
  2290. };
  2291. }
  2292. }
  2293. var textareaCoverCSS = {};
  2294. var setContentGlueElementCSSfunction = function(horizontal) {
  2295. var scrollbarVars = getScrollbarVars(horizontal);
  2296. var wh = scrollbarVars._w_h;
  2297. var strWH = scrollbarVars._width_height;
  2298. var autoSize = horizontal ? widthAuto : heightAuto;
  2299. var borderSize = horizontal ? _borderX : _borderY;
  2300. var paddingSize = horizontal ? _paddingX : _paddingY;
  2301. var marginSize = horizontal ? _marginX : _marginY;
  2302. var maxSize = contentGlueElementCSS[strWH] + (_isBorderBox ? borderSize : -paddingSize);
  2303. //make contentGlue size -1 if element is not auto sized, to make sure that a resize event happens when the element shrinks
  2304. if (!autoSize || (!autoSize && border.c))
  2305. contentGlueElementCSS[strWH] = hostSize[wh] - (_isBorderBox ? 0 : paddingSize + borderSize) - 1 - marginSize;
  2306. //if size is auto and host is same size as max size, make content glue size +1 to make sure size changes will be detected
  2307. if (autoSize && cssMaxValue['c' + wh] && cssMaxValue['i' + wh] === maxSize)
  2308. contentGlueElementCSS[strWH] = maxSize + (_isBorderBox ? 0 : paddingSize) + 1;
  2309. //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)
  2310. if (autoSize && (contentSize[wh] < _viewportSize[wh]) && (horizontal ? (_isTextarea ? !textareaAutoWrapping : false) : true)) {
  2311. if (_isTextarea)
  2312. textareaCoverCSS[strWH] = parseToZeroOrNumber(_textareaCoverElement.css(strWH)) - 1;
  2313. contentGlueElementCSS[strWH] -= 1;
  2314. }
  2315. //make sure content glue size is at least 1
  2316. if (contentSize[wh] > 0)
  2317. contentGlueElementCSS[strWH] = MATH.max(1, contentGlueElementCSS[strWH]);
  2318. };
  2319. setContentGlueElementCSSfunction(true);
  2320. setContentGlueElementCSSfunction(false);
  2321. if (_isTextarea)
  2322. _textareaCoverElement.css(textareaCoverCSS);
  2323. _contentGlueElement.css(contentGlueElementCSS);
  2324. }
  2325. if (widthAuto)
  2326. contentElementCSS[_strWidth] = _strHundredPercent;
  2327. if (widthAuto && !_isBorderBox && !_mutationObserversConnected)
  2328. contentElementCSS[_strFloat] = 'none';
  2329. //apply and reset content style
  2330. _contentElement.css(contentElementCSS);
  2331. contentElementCSS = {};
  2332. //measure again, but this time all correct sizes:
  2333. var contentScrollSize = {
  2334. w: MATH.max(contentMeasureElement[LEXICON.sW], contentMeasureElementGuaranty[LEXICON.sW]),
  2335. h: MATH.max(contentMeasureElement[LEXICON.sH], contentMeasureElementGuaranty[LEXICON.sH])
  2336. };
  2337. contentScrollSize.c = contentSizeChanged = checkCacheDouble(contentScrollSize, _contentScrollSizeCache, force);
  2338. _contentScrollSizeCache = contentScrollSize;
  2339. //remove overflow hidden to restore overflow
  2340. if(hideOverflow4CorrectMeasuring)
  2341. _contentElement.css(strOverflow, _strEmpty);
  2342. //refresh viewport size after correct measuring
  2343. _viewportSize = getViewportSize();
  2344. hostSize = getHostSize();
  2345. hostSizeChanged = checkCacheDouble(hostSize, _hostSizeCache);
  2346. _hostSizeCache = hostSize;
  2347. var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0);
  2348. var previousOverflow = _overflowAmountCache;
  2349. var overflowBehaviorIsVS = { };
  2350. var overflowBehaviorIsVH = { };
  2351. var overflowBehaviorIsS = { };
  2352. var overflowAmount = { };
  2353. var hasOverflow = { };
  2354. var hideOverflow = { };
  2355. var canScroll = { };
  2356. var viewportRect = _paddingElementNative.getBoundingClientRect();
  2357. var setOverflowVariables = function(horizontal) {
  2358. var scrollbarVars = getScrollbarVars(horizontal);
  2359. var scrollbarVarsInverted = getScrollbarVars(!horizontal);
  2360. var xyI = scrollbarVarsInverted._x_y;
  2361. var xy = scrollbarVars._x_y;
  2362. var wh = scrollbarVars._w_h;
  2363. var widthHeight = scrollbarVars._width_height;
  2364. var scrollMax = _strScroll + scrollbarVars._Left_Top + 'Max';
  2365. var fractionalOverflowAmount = viewportRect[widthHeight] ? MATH.abs(viewportRect[widthHeight] - _viewportSize[wh]) : 0;
  2366. overflowBehaviorIsVS[xy] = overflowBehavior[xy] === 'v-s';
  2367. overflowBehaviorIsVH[xy] = overflowBehavior[xy] === 'v-h';
  2368. overflowBehaviorIsS[xy] = overflowBehavior[xy] === 's';
  2369. overflowAmount[xy] = MATH.max(0, MATH.round((contentScrollSize[wh] - _viewportSize[wh]) * 100) / 100);
  2370. overflowAmount[xy] *= (hideOverflowForceTextarea || (_viewportElementNative[scrollMax] === 0 && fractionalOverflowAmount > 0 && fractionalOverflowAmount < 1)) ? 0 : 1;
  2371. hasOverflow[xy] = overflowAmount[xy] > 0;
  2372. //hideOverflow:
  2373. //x || y : true === overflow is hidden by "overflow: scroll" OR "overflow: hidden"
  2374. //xs || ys : true === overflow is hidden by "overflow: scroll"
  2375. hideOverflow[xy] = overflowBehaviorIsVS[xy] || overflowBehaviorIsVH[xy] ? (hasOverflow[xyI] && !overflowBehaviorIsVS[xyI] && !overflowBehaviorIsVH[xyI]) : hasOverflow[xy];
  2376. hideOverflow[xy + 's'] = hideOverflow[xy] ? (overflowBehaviorIsS[xy] || overflowBehaviorIsVS[xy]) : false;
  2377. canScroll[xy] = hasOverflow[xy] && hideOverflow[xy + 's'];
  2378. };
  2379. setOverflowVariables(true);
  2380. setOverflowVariables(false);
  2381. overflowAmount.c = checkCacheDouble(overflowAmount, _overflowAmountCache, _strX, _strY, force);
  2382. _overflowAmountCache = overflowAmount;
  2383. hasOverflow.c = checkCacheDouble(hasOverflow, _hasOverflowCache, _strX, _strY, force);
  2384. _hasOverflowCache = hasOverflow;
  2385. hideOverflow.c = checkCacheDouble(hideOverflow, _hideOverflowCache, _strX, _strY, force);
  2386. _hideOverflowCache = hideOverflow;
  2387. //if native scrollbar is overlay at x OR y axis, prepare DOM
  2388. if (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) {
  2389. var borderDesign = 'px solid transparent';
  2390. var contentArrangeElementCSS = { };
  2391. var arrangeContent = { };
  2392. var arrangeChanged = force;
  2393. var setContentElementCSS;
  2394. if (hasOverflow.x || hasOverflow.y) {
  2395. arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty;
  2396. arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty;
  2397. arrangeChanged = checkCacheSingle(arrangeContent, _arrangeContentSizeCache, force);
  2398. _arrangeContentSizeCache = arrangeContent;
  2399. }
  2400. if (hasOverflow.c || hideOverflow.c || contentScrollSize.c || cssDirectionChanged || widthAutoChanged || heightAutoChanged || widthAuto || heightAuto || ignoreOverlayScrollbarHidingChanged) {
  2401. contentElementCSS[_strMarginMinus + isRTLRight] = contentElementCSS[_strBorderMinus + isRTLRight] = _strEmpty;
  2402. setContentElementCSS = function(horizontal) {
  2403. var scrollbarVars = getScrollbarVars(horizontal);
  2404. var scrollbarVarsInverted = getScrollbarVars(!horizontal);
  2405. var xy = scrollbarVars._x_y;
  2406. var strDirection = horizontal ? _strBottom : isRTLLeft;
  2407. var invertedAutoSize = horizontal ? heightAuto : widthAuto;
  2408. if (_nativeScrollbarIsOverlaid[xy] && hasOverflow[xy] && hideOverflow[xy + 's']) {
  2409. contentElementCSS[_strMarginMinus + strDirection] = invertedAutoSize ? (ignoreOverlayScrollbarHiding ? _strEmpty : _overlayScrollbarDummySize[xy]) : _strEmpty;
  2410. contentElementCSS[_strBorderMinus + strDirection] = ((horizontal ? !invertedAutoSize : true) && !ignoreOverlayScrollbarHiding) ? (_overlayScrollbarDummySize[xy] + borderDesign) : _strEmpty;
  2411. }
  2412. else {
  2413. arrangeContent[scrollbarVarsInverted._w_h] =
  2414. contentElementCSS[_strMarginMinus + strDirection] =
  2415. contentElementCSS[_strBorderMinus + strDirection] = _strEmpty;
  2416. arrangeChanged = true;
  2417. }
  2418. };
  2419. setContentElementCSS(true);
  2420. setContentElementCSS(false);
  2421. }
  2422. if (ignoreOverlayScrollbarHiding) {
  2423. arrangeContent.w = arrangeContent.h = _strEmpty;
  2424. arrangeChanged = true;
  2425. }
  2426. if (arrangeChanged) {
  2427. contentArrangeElementCSS[_strWidth] = hideOverflow.y ? arrangeContent.w : _strEmpty;
  2428. contentArrangeElementCSS[_strHeight] = hideOverflow.x ? arrangeContent.h : _strEmpty;
  2429. if (!_contentArrangeElement) {
  2430. _contentArrangeElement = FRAMEWORK(generateDiv(_classNameContentArrangeElement));
  2431. _viewportElement.prepend(_contentArrangeElement);
  2432. }
  2433. _contentArrangeElement.css(contentArrangeElementCSS);
  2434. }
  2435. _contentElement.css(contentElementCSS);
  2436. }
  2437. var viewportElementCSS = {};
  2438. var paddingElementCSS = {};
  2439. var setViewportCSS;
  2440. if (hostSizeChanged || hasOverflow.c || hideOverflow.c || contentScrollSize.c || overflowBehaviorChanged || boxSizingChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged || clipAlwaysChanged || heightAutoChanged) {
  2441. viewportElementCSS[isRTLRight] = _strEmpty;
  2442. setViewportCSS = function(horizontal) {
  2443. var scrollbarVars = getScrollbarVars(horizontal);
  2444. var scrollbarVarsInverted = getScrollbarVars(!horizontal);
  2445. var xy = scrollbarVars._x_y;
  2446. var XY = scrollbarVars._X_Y;
  2447. var strDirection = horizontal ? _strBottom : isRTLLeft;
  2448. var reset = function () {
  2449. viewportElementCSS[strDirection] = _strEmpty;
  2450. _contentBorderSize[scrollbarVarsInverted._w_h] = 0;
  2451. };
  2452. if (hasOverflow[xy] && hideOverflow[xy + 's']) {
  2453. viewportElementCSS[strOverflow + XY] = _strScroll;
  2454. if (!ignoreOverlayScrollbarHiding) {
  2455. viewportElementCSS[strDirection] = -(_nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[xy] : _nativeScrollbarSize[xy]);
  2456. _contentBorderSize[scrollbarVarsInverted._w_h] = _nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[scrollbarVarsInverted._x_y] : 0;
  2457. }
  2458. else
  2459. reset();
  2460. } else {
  2461. viewportElementCSS[strOverflow + XY] = _strEmpty;
  2462. reset();
  2463. }
  2464. };
  2465. setViewportCSS(true);
  2466. setViewportCSS(false);
  2467. // if the scroll container is too small and if there is any overflow with not overlay scrollbar, make viewport element greater in size (Firefox hide Scrollbars fix)
  2468. // because firefox starts hiding scrollbars on too small elements
  2469. // with this behavior the overflow calculation may be incorrect or the scrollbars would appear suddenly
  2470. // https://bugzilla.mozilla.org/show_bug.cgi?id=292284
  2471. if ((_viewportSize.h < _nativeScrollbarMinSize.x || _viewportSize.w < _nativeScrollbarMinSize.y)
  2472. && ((hasOverflow.x && hideOverflow.x && !_nativeScrollbarIsOverlaid.x) || (hasOverflow.y && hideOverflow.y && !_nativeScrollbarIsOverlaid.y))) {
  2473. viewportElementCSS[_strPaddingMinus + _strTop] = _nativeScrollbarMinSize.x;
  2474. viewportElementCSS[_strMarginMinus + _strTop] = -_nativeScrollbarMinSize.x;
  2475. viewportElementCSS[_strPaddingMinus + isRTLRight] = _nativeScrollbarMinSize.y;
  2476. viewportElementCSS[_strMarginMinus + isRTLRight] = -_nativeScrollbarMinSize.y;
  2477. }
  2478. else {
  2479. viewportElementCSS[_strPaddingMinus + _strTop] =
  2480. viewportElementCSS[_strMarginMinus + _strTop] =
  2481. viewportElementCSS[_strPaddingMinus + isRTLRight] =
  2482. viewportElementCSS[_strMarginMinus + isRTLRight] = _strEmpty;
  2483. }
  2484. viewportElementCSS[_strPaddingMinus + isRTLLeft] =
  2485. viewportElementCSS[_strMarginMinus + isRTLLeft] = _strEmpty;
  2486. //if there is any overflow (x OR y axis) and this overflow shall be hidden, make overflow hidden, else overflow visible
  2487. if ((hasOverflow.x && hideOverflow.x) || (hasOverflow.y && hideOverflow.y) || hideOverflowForceTextarea) {
  2488. //only hide if is Textarea
  2489. if (_isTextarea && hideOverflowForceTextarea) {
  2490. paddingElementCSS[strOverflowX] =
  2491. paddingElementCSS[strOverflowY] = strHidden;
  2492. }
  2493. }
  2494. else {
  2495. if (!clipAlways || (overflowBehaviorIsVH.x || overflowBehaviorIsVS.x || overflowBehaviorIsVH.y || overflowBehaviorIsVS.y)) {
  2496. //only un-hide if Textarea
  2497. if (_isTextarea) {
  2498. paddingElementCSS[strOverflowX] =
  2499. paddingElementCSS[strOverflowY] = _strEmpty;
  2500. }
  2501. viewportElementCSS[strOverflowX] =
  2502. viewportElementCSS[strOverflowY] = strVisible;
  2503. }
  2504. }
  2505. _paddingElement.css(paddingElementCSS);
  2506. _viewportElement.css(viewportElementCSS);
  2507. viewportElementCSS = { };
  2508. //force soft redraw in webkit because without the scrollbars will may appear because DOM wont be redrawn under special conditions
  2509. if ((hasOverflow.c || boxSizingChanged || widthAutoChanged || heightAutoChanged) && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
  2510. var elementStyle = _contentElementNative[LEXICON.s];
  2511. var dump;
  2512. elementStyle.webkitTransform = 'scale(1)';
  2513. elementStyle.display = 'run-in';
  2514. dump = _contentElementNative[LEXICON.oH];
  2515. elementStyle.display = _strEmpty; //|| dump; //use dump to prevent it from deletion if minify
  2516. elementStyle.webkitTransform = _strEmpty;
  2517. }
  2518. /*
  2519. //force hard redraw in webkit if native overlaid scrollbars shall appear
  2520. if (ignoreOverlayScrollbarHidingChanged && ignoreOverlayScrollbarHiding) {
  2521. _hostElement.hide();
  2522. var dump = _hostElementNative[LEXICON.oH];
  2523. _hostElement.show();
  2524. }
  2525. */
  2526. }
  2527. //change to direction RTL and width auto Bugfix in Webkit
  2528. //without this fix, the DOM still thinks the scrollbar is LTR and thus the content is shifted to the left
  2529. contentElementCSS = {};
  2530. if (cssDirectionChanged || widthAutoChanged || heightAutoChanged) {
  2531. if (_isRTL && widthAuto) {
  2532. var floatTmp = _contentElement.css(_strFloat);
  2533. var posLeftWithoutFloat = MATH.round(_contentElement.css(_strFloat, _strEmpty).css(_strLeft, _strEmpty).position().left);
  2534. _contentElement.css(_strFloat, floatTmp);
  2535. var posLeftWithFloat = MATH.round(_contentElement.position().left);
  2536. if (posLeftWithoutFloat !== posLeftWithFloat)
  2537. contentElementCSS[_strLeft] = posLeftWithoutFloat;
  2538. }
  2539. else {
  2540. contentElementCSS[_strLeft] = _strEmpty;
  2541. }
  2542. }
  2543. _contentElement.css(contentElementCSS);
  2544. //handle scroll position
  2545. if (_isTextarea && contentSizeChanged) {
  2546. var textareaInfo = getTextareaInfo();
  2547. if (textareaInfo) {
  2548. var textareaRowsChanged = _textareaInfoCache === undefined ? true : textareaInfo._rows !== _textareaInfoCache._rows;
  2549. var cursorRow = textareaInfo._cursorRow;
  2550. var cursorCol = textareaInfo._cursorColumn;
  2551. var widestRow = textareaInfo._widestRow;
  2552. var lastRow = textareaInfo._rows;
  2553. var lastCol = textareaInfo._columns;
  2554. var cursorPos = textareaInfo._cursorPosition;
  2555. var cursorMax = textareaInfo._cursorMax;
  2556. var cursorIsLastPosition = (cursorPos >= cursorMax && _textareaHasFocus);
  2557. var textareaScrollAmount = {
  2558. x: (!textareaAutoWrapping && (cursorCol === lastCol && cursorRow === widestRow)) ? _overflowAmountCache.x : -1,
  2559. y: (textareaAutoWrapping ? cursorIsLastPosition || textareaRowsChanged && (previousOverflow !== undefined ? (currScroll.y === previousOverflow.y) : false) : (cursorIsLastPosition || textareaRowsChanged) && cursorRow === lastRow) ? _overflowAmountCache.y : -1
  2560. };
  2561. currScroll.x = textareaScrollAmount.x > -1 ? (_isRTL && _normalizeRTLCache && _rtlScrollBehavior.i ? 0 : textareaScrollAmount.x) : currScroll.x; //if inverted, scroll to 0 -> normalized this means to max scroll offset.
  2562. currScroll.y = textareaScrollAmount.y > -1 ? textareaScrollAmount.y : currScroll.y;
  2563. }
  2564. _textareaInfoCache = textareaInfo;
  2565. }
  2566. if (_isRTL && _rtlScrollBehavior.i && _nativeScrollbarIsOverlaid.y && hasOverflow.x && _normalizeRTLCache)
  2567. currScroll.x += _contentBorderSize.w || 0;
  2568. if(widthAuto)
  2569. _hostElement[_strScrollLeft](0);
  2570. if(heightAuto)
  2571. _hostElement[_strScrollTop](0);
  2572. _viewportElement[_strScrollLeft](currScroll.x)[_strScrollTop](currScroll.y);
  2573. //scrollbars management:
  2574. var scrollbarsVisibilityVisible = scrollbarsVisibility === 'v';
  2575. var scrollbarsVisibilityHidden = scrollbarsVisibility === 'h';
  2576. var scrollbarsVisibilityAuto = scrollbarsVisibility === 'a';
  2577. var showScrollbarH = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, true, true, canScroll.x);
  2578. var showScrollbarV = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, false, true, canScroll.y);
  2579. var hideScrollbarH = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, true, false, canScroll.x);
  2580. var hideScrollbarV = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, false, false, canScroll.y);
  2581. //manage class name which indicates scrollable overflow
  2582. if (hideOverflow.x || hideOverflow.y)
  2583. addClass(_hostElement, _classNameHostOverflow);
  2584. else
  2585. removeClass(_hostElement, _classNameHostOverflow);
  2586. if (hideOverflow.x)
  2587. addClass(_hostElement, _classNameHostOverflowX);
  2588. else
  2589. removeClass(_hostElement, _classNameHostOverflowX);
  2590. if (hideOverflow.y)
  2591. addClass(_hostElement, _classNameHostOverflowY);
  2592. else
  2593. removeClass(_hostElement, _classNameHostOverflowY);
  2594. //add or remove rtl class name for styling purposes
  2595. if (cssDirectionChanged) {
  2596. if (_isRTL)
  2597. addClass(_hostElement, _classNameHostRTL);
  2598. else
  2599. removeClass(_hostElement, _classNameHostRTL);
  2600. }
  2601. //manage the resize feature (CSS3 resize "polyfill" for this plugin)
  2602. if (_isBody)
  2603. addClass(_hostElement, _classNameHostResizeDisabled);
  2604. if (resizeChanged) {
  2605. var addCornerEvents = function () { _scrollbarCornerElement.on(_strMouseTouchDownEvent, _resizeOnMouseTouchDown); };
  2606. var removeCornerEvents = function () { _scrollbarCornerElement.off(_strMouseTouchDownEvent, _resizeOnMouseTouchDown); };
  2607. removeClass(_scrollbarCornerElement, [
  2608. _classNameHostResizeDisabled,
  2609. _classNameScrollbarCornerResize,
  2610. _classNameScrollbarCornerResizeB,
  2611. _classNameScrollbarCornerResizeH,
  2612. _classNameScrollbarCornerResizeV].join(_strSpace));
  2613. if (_resizeNone) {
  2614. addClass(_hostElement, _classNameHostResizeDisabled);
  2615. removeCornerEvents();
  2616. }
  2617. else {
  2618. addClass(_scrollbarCornerElement, _classNameScrollbarCornerResize);
  2619. if (_resizeBoth)
  2620. addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeB);
  2621. else if (_resizeHorizontal)
  2622. addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeH);
  2623. else if (_resizeVertical)
  2624. addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV);
  2625. removeCornerEvents();
  2626. addCornerEvents();
  2627. }
  2628. }
  2629. //manage the scrollbars general visibility + the scrollbar interactivity (unusable class name)
  2630. if (scrollbarsVisibilityChanged || overflowBehaviorChanged || hideOverflow.c || hasOverflow.c || ignoreOverlayScrollbarHidingChanged) {
  2631. if (ignoreOverlayScrollbarHiding) {
  2632. if (ignoreOverlayScrollbarHidingChanged) {
  2633. removeClass(_hostElement, _classNameHostScrolling);
  2634. if (ignoreOverlayScrollbarHiding) {
  2635. hideScrollbarH();
  2636. hideScrollbarV();
  2637. }
  2638. }
  2639. }
  2640. else if (scrollbarsVisibilityAuto) {
  2641. if (canScroll.x)
  2642. showScrollbarH();
  2643. else
  2644. hideScrollbarH();
  2645. if (canScroll.y)
  2646. showScrollbarV();
  2647. else
  2648. hideScrollbarV();
  2649. }
  2650. else if (scrollbarsVisibilityVisible) {
  2651. showScrollbarH();
  2652. showScrollbarV();
  2653. }
  2654. else if (scrollbarsVisibilityHidden) {
  2655. hideScrollbarH();
  2656. hideScrollbarV();
  2657. }
  2658. }
  2659. //manage the scrollbars auto hide feature (auto hide them after specific actions)
  2660. if (scrollbarsAutoHideChanged || ignoreOverlayScrollbarHidingChanged) {
  2661. if (_scrollbarsAutoHideLeave || _scrollbarsAutoHideMove) {
  2662. setupHostMouseTouchEvents(true);
  2663. setupHostMouseTouchEvents();
  2664. }
  2665. else {
  2666. setupHostMouseTouchEvents(true);
  2667. }
  2668. if (_scrollbarsAutoHideNever)
  2669. refreshScrollbarsAutoHide(true);
  2670. else
  2671. refreshScrollbarsAutoHide(false, true);
  2672. }
  2673. //manage scrollbars handle length & offset - don't remove!
  2674. if (hostSizeChanged || overflowAmount.c || heightAutoChanged || widthAutoChanged || resizeChanged || boxSizingChanged || paddingAbsoluteChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged) {
  2675. refreshScrollbarHandleLength(true);
  2676. refreshScrollbarHandleOffset(true);
  2677. refreshScrollbarHandleLength(false);
  2678. refreshScrollbarHandleOffset(false);
  2679. }
  2680. //manage interactivity
  2681. if (scrollbarsClickScrollingChanged)
  2682. refreshScrollbarsInteractive(true, scrollbarsClickScrolling);
  2683. if (scrollbarsDragScrollingChanged)
  2684. refreshScrollbarsInteractive(false, scrollbarsDragScrolling);
  2685. //callbacks:
  2686. if (cssDirectionChanged) {
  2687. dispatchCallback("onDirectionChanged", {
  2688. isRTL: _isRTL,
  2689. dir: cssDirection
  2690. });
  2691. }
  2692. if (hostSizeChanged) {
  2693. dispatchCallback("onHostSizeChanged", {
  2694. width: _hostSizeCache.w,
  2695. height: _hostSizeCache.h
  2696. });
  2697. }
  2698. if (contentSizeChanged) {
  2699. dispatchCallback("onContentSizeChanged", {
  2700. width: _contentScrollSizeCache.w,
  2701. height: _contentScrollSizeCache.h
  2702. });
  2703. }
  2704. if (hasOverflow.c || hideOverflow.c) {
  2705. dispatchCallback("onOverflowChanged", {
  2706. x: hasOverflow.x,
  2707. y: hasOverflow.y,
  2708. xScrollable: hideOverflow.xs,
  2709. yScrollable: hideOverflow.ys,
  2710. clipped: hideOverflow.x || hideOverflow.y
  2711. });
  2712. }
  2713. if (overflowAmount.c) {
  2714. dispatchCallback("onOverflowAmountChanged", {
  2715. x: overflowAmount.x,
  2716. y: overflowAmount.y
  2717. });
  2718. }
  2719. }
  2720. //fix body min size
  2721. if (_isBody && (_hasOverflowCache.c || _bodyMinSizeCache.c)) {
  2722. //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.
  2723. if (!_bodyMinSizeCache.f)
  2724. bodyMinSizeChanged();
  2725. if (_nativeScrollbarIsOverlaid.y && _hasOverflowCache.x)
  2726. _contentElement.css(_strMinMinus + _strWidth, _bodyMinSizeCache.w + _overlayScrollbarDummySize.y);
  2727. if (_nativeScrollbarIsOverlaid.x && _hasOverflowCache.y)
  2728. _contentElement.css(_strMinMinus + _strHeight, _bodyMinSizeCache.h + _overlayScrollbarDummySize.x);
  2729. _bodyMinSizeCache.c = false;
  2730. }
  2731. unfreezeResizeObserver(_sizeObserverElement);
  2732. unfreezeResizeObserver(_sizeAutoObserverElement);
  2733. dispatchCallback("onUpdated", { forced: force });
  2734. }
  2735. //==== Options ====//
  2736. /**
  2737. * Sets new options but doesn't call the update method.
  2738. * @param newOptions The object which contains the new options.
  2739. */
  2740. function setOptions(newOptions) {
  2741. _currentOptions = extendDeep({}, _currentOptions, _pluginsOptions._validate(newOptions, _pluginsOptions._template, true));
  2742. _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, _pluginsOptions._validate(newOptions, _pluginsOptions._template, false, true));
  2743. }
  2744. //==== Structure ====//
  2745. /**
  2746. * Builds or destroys the wrapper and helper DOM elements.
  2747. * @param destroy Indicates whether the DOM shall be build or destroyed.
  2748. */
  2749. function setupStructureDOM(destroy) {
  2750. var adoptAttrs = _currentPreparedOptions.textarea.inheritedAttrs;
  2751. var adoptAttrsMap = { };
  2752. var applyAdoptedAttrs = function() {
  2753. var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement;
  2754. FRAMEWORK.each(adoptAttrsMap, function(k, v) {
  2755. if(type(v) == TYPES.s) {
  2756. if(k == LEXICON.c)
  2757. applyAdoptedAttrsElm.addClass(v);
  2758. else
  2759. applyAdoptedAttrsElm.attr(k, v);
  2760. }
  2761. });
  2762. };
  2763. var hostElementClassNames = [
  2764. _classNameHostElement,
  2765. _classNameHostTextareaElement,
  2766. _classNameHostResizeDisabled,
  2767. _classNameHostRTL,
  2768. _classNameHostScrollbarHorizontalHidden,
  2769. _classNameHostScrollbarVerticalHidden,
  2770. _classNameHostTransition,
  2771. _classNameHostScrolling,
  2772. _classNameHostOverflow,
  2773. _classNameHostOverflowX,
  2774. _classNameHostOverflowY,
  2775. _classNameThemeNone,
  2776. _classNameTextareaElement,
  2777. _classNameTextInherit,
  2778. _classNameCache].join(_strSpace);
  2779. adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(' ') : adoptAttrs;
  2780. if(type(adoptAttrs) == TYPES.a) {
  2781. FRAMEWORK.each(adoptAttrs, function(i, v) {
  2782. if(type(v) == TYPES.s)
  2783. adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v);
  2784. });
  2785. }
  2786. if(!destroy) {
  2787. if (_isTextarea) {
  2788. var hostElementCSS = {};
  2789. var parent = _targetElement.parent();
  2790. _isTextareaHostGenerated = !(parent.hasClass(_classNameHostTextareaElement) && parent.children()[LEXICON.l] === 1);
  2791. if (!_currentPreparedOptions.sizeAutoCapable) {
  2792. hostElementCSS[_strWidth] = _targetElement.css(_strWidth);
  2793. hostElementCSS[_strHeight] = _targetElement.css(_strHeight);
  2794. }
  2795. if(_isTextareaHostGenerated)
  2796. _targetElement.wrap(generateDiv(_classNameHostTextareaElement));
  2797. _hostElement = _targetElement.parent();
  2798. _hostElement.css(hostElementCSS)
  2799. .wrapInner(generateDiv(_classNameContentElement + _strSpace + _classNameTextInherit))
  2800. .wrapInner(generateDiv(_classNameViewportElement + _strSpace + _classNameTextInherit))
  2801. .wrapInner(generateDiv(_classNamePaddingElement + _strSpace + _classNameTextInherit));
  2802. _contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);
  2803. _viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);
  2804. _paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);
  2805. _textareaCoverElement = FRAMEWORK(generateDiv(_classNameTextareaCoverElement));
  2806. _contentElement.prepend(_textareaCoverElement);
  2807. addClass(_targetElement, _classNameTextareaElement + _strSpace + _classNameTextInherit);
  2808. if(_isTextareaHostGenerated)
  2809. applyAdoptedAttrs();
  2810. }
  2811. else {
  2812. _hostElement = _targetElement;
  2813. _hostElement.wrapInner(generateDiv(_classNameContentElement))
  2814. .wrapInner(generateDiv(_classNameViewportElement))
  2815. .wrapInner(generateDiv(_classNamePaddingElement));
  2816. _contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);
  2817. _viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);
  2818. _paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);
  2819. addClass(_targetElement, _classNameHostElement);
  2820. }
  2821. if (_nativeScrollbarStyling)
  2822. addClass(_viewportElement, _nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y ? _classNameViewportNativeScrollbarsOverlaid : _classNameViewportNativeScrollbarsInvisible);
  2823. if (_isBody)
  2824. addClass(_htmlElement, _classNameHTMLElement);
  2825. _sizeObserverElement = FRAMEWORK(generateDiv('os-resize-observer-host'));
  2826. _hostElement.prepend(_sizeObserverElement);
  2827. _sizeObserverElementNative = _sizeObserverElement[0];
  2828. _hostElementNative = _hostElement[0];
  2829. _paddingElementNative = _paddingElement[0];
  2830. _viewportElementNative = _viewportElement[0];
  2831. _contentElementNative = _contentElement[0];
  2832. }
  2833. else {
  2834. _contentElement.contents()
  2835. .unwrap()
  2836. .unwrap()
  2837. .unwrap();
  2838. removeClass(_hostElement, hostElementClassNames);
  2839. if (_isTextarea) {
  2840. _targetElement.removeAttr(LEXICON.s);
  2841. if(_isTextareaHostGenerated)
  2842. applyAdoptedAttrs();
  2843. removeClass(_targetElement, hostElementClassNames);
  2844. remove(_textareaCoverElement);
  2845. if(_isTextareaHostGenerated) {
  2846. _targetElement.unwrap();
  2847. remove(_hostElement);
  2848. }
  2849. else {
  2850. addClass(_hostElement, _classNameHostTextareaElement);
  2851. }
  2852. }
  2853. else {
  2854. removeClass(_targetElement, _classNameHostElement);
  2855. }
  2856. if (_isBody)
  2857. removeClass(_htmlElement, _classNameHTMLElement);
  2858. remove(_sizeObserverElement);
  2859. }
  2860. }
  2861. /**
  2862. * Adds or removes all wrapper elements interactivity events.
  2863. * @param destroy Indicates whether the Events shall be added or removed.
  2864. */
  2865. function setupStructureEvents(destroy) {
  2866. var textareaKeyDownRestrictedKeyCodes = [
  2867. 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, //F1 to F12
  2868. 33, 34, //page up, page down
  2869. 37, 38, 39, 40, //left, up, right, down arrows
  2870. 16, 17, 18, 19, 20, 144 //Shift, Ctrl, Alt, Pause, CapsLock, NumLock
  2871. ];
  2872. var textareaKeyDownKeyCodesList = [ ];
  2873. var textareaUpdateIntervalID;
  2874. var scrollStopDelay = 175;
  2875. var scrollStopTimeoutId;
  2876. var strOnOff = destroy ? 'off' : 'on';
  2877. var updateTextarea;
  2878. var viewportOnScroll;
  2879. if(!destroy && _isTextarea) {
  2880. _textareaEvents = { };
  2881. updateTextarea = function(doClearInterval) {
  2882. textareaUpdate();
  2883. _base.update(_strAuto);
  2884. if(doClearInterval)
  2885. clearInterval(textareaUpdateIntervalID);
  2886. };
  2887. _textareaEvents[_strScroll] = function(event) {
  2888. _targetElement[_strScrollLeft](_rtlScrollBehavior.i && _normalizeRTLCache ? 9999999 : 0);
  2889. _targetElement[_strScrollTop](0);
  2890. COMPATIBILITY.prvD(event);
  2891. COMPATIBILITY.stpP(event);
  2892. return false;
  2893. };
  2894. _textareaEvents['drop'] = function() {
  2895. setTimeout(function () {
  2896. if(!_destroyed)
  2897. updateTextarea();
  2898. }, 50);
  2899. };
  2900. _textareaEvents['focus'] = function() {
  2901. _textareaHasFocus = true;
  2902. };
  2903. _textareaEvents['focusout'] = function() {
  2904. _textareaHasFocus = false;
  2905. textareaKeyDownKeyCodesList = [ ];
  2906. updateTextarea(true);
  2907. };
  2908. if (_msieVersion > 9 || !_autoUpdateRecommended) {
  2909. _textareaEvents['input'] = function textareaOnInput() {
  2910. updateTextarea();
  2911. }
  2912. }
  2913. else {
  2914. _textareaEvents[_strKeyDownEvent] = function textareaOnKeyDown(event) {
  2915. var keyCode = event.keyCode;
  2916. if (FRAMEWORK.inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1)
  2917. return;
  2918. if (!textareaKeyDownKeyCodesList.length) {
  2919. updateTextarea();
  2920. textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60);
  2921. }
  2922. if (FRAMEWORK.inArray(keyCode, textareaKeyDownKeyCodesList) === -1)
  2923. textareaKeyDownKeyCodesList.push(keyCode);
  2924. };
  2925. _textareaEvents[_strKeyUpEvent] = function(event) {
  2926. var keyCode = event.keyCode;
  2927. var index = FRAMEWORK.inArray(keyCode, textareaKeyDownKeyCodesList);
  2928. if (FRAMEWORK.inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1)
  2929. return;
  2930. if (index > -1)
  2931. textareaKeyDownKeyCodesList.splice(index, 1);
  2932. if (!textareaKeyDownKeyCodesList.length)
  2933. updateTextarea(true);
  2934. };
  2935. }
  2936. }
  2937. if (_isTextarea) {
  2938. FRAMEWORK.each(_textareaEvents, function(key, value) {
  2939. _targetElement[strOnOff](key, value);
  2940. });
  2941. }
  2942. else {
  2943. _contentElement[strOnOff](_strTransitionEndEvent, function (event) {
  2944. if (_autoUpdateCache === true)
  2945. return;
  2946. event = event.originalEvent || event;
  2947. if (isSizeAffectingCSSProperty(event.propertyName))
  2948. update(_strAuto);
  2949. });
  2950. }
  2951. if(!destroy) {
  2952. viewportOnScroll = function(event) {
  2953. if (_isSleeping)
  2954. return;
  2955. if (scrollStopTimeoutId !== undefined)
  2956. clearTimeout(scrollStopTimeoutId);
  2957. else {
  2958. if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
  2959. refreshScrollbarsAutoHide(true);
  2960. if (!nativeOverlayScrollbarsAreActive())
  2961. addClass(_hostElement, _classNameHostScrolling);
  2962. dispatchCallback("onScrollStart", event);
  2963. }
  2964. //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset
  2965. //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point
  2966. //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove
  2967. if(!_scrollbarsHandleAsync) {
  2968. refreshScrollbarHandleOffset(true);
  2969. refreshScrollbarHandleOffset(false);
  2970. }
  2971. dispatchCallback("onScroll", event);
  2972. scrollStopTimeoutId = setTimeout(function () {
  2973. if(!_destroyed) {
  2974. //OnScrollStop:
  2975. clearTimeout(scrollStopTimeoutId);
  2976. scrollStopTimeoutId = undefined;
  2977. if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
  2978. refreshScrollbarsAutoHide(false);
  2979. if (!nativeOverlayScrollbarsAreActive())
  2980. removeClass(_hostElement, _classNameHostScrolling);
  2981. dispatchCallback("onScrollStop", event);
  2982. }
  2983. }, scrollStopDelay);
  2984. };
  2985. if (_supportPassiveEvents)
  2986. addPassiveEventListener(_viewportElement, _strScroll, viewportOnScroll);
  2987. else
  2988. _viewportElement.on(_strScroll, viewportOnScroll);
  2989. }
  2990. }
  2991. //==== Scrollbars ====//
  2992. /**
  2993. * Builds or destroys all scrollbar DOM elements (scrollbar, track, handle)
  2994. * @param destroy Indicates whether the DOM shall be build or destroyed.
  2995. */
  2996. function setupScrollbarsDOM(destroy) {
  2997. if(!destroy) {
  2998. _scrollbarHorizontalElement = FRAMEWORK(generateDiv(_classNameScrollbar + _strSpace + _classNameScrollbarHorizontal));
  2999. _scrollbarHorizontalTrackElement = FRAMEWORK(generateDiv(_classNameScrollbarTrack));
  3000. _scrollbarHorizontalHandleElement = FRAMEWORK(generateDiv(_classNameScrollbarHandle));
  3001. _scrollbarVerticalElement = FRAMEWORK(generateDiv(_classNameScrollbar + _strSpace + _classNameScrollbarVertical));
  3002. _scrollbarVerticalTrackElement = FRAMEWORK(generateDiv(_classNameScrollbarTrack));
  3003. _scrollbarVerticalHandleElement = FRAMEWORK(generateDiv(_classNameScrollbarHandle));
  3004. _scrollbarHorizontalElement.append(_scrollbarHorizontalTrackElement);
  3005. _scrollbarHorizontalTrackElement.append(_scrollbarHorizontalHandleElement);
  3006. _scrollbarVerticalElement.append(_scrollbarVerticalTrackElement);
  3007. _scrollbarVerticalTrackElement.append(_scrollbarVerticalHandleElement);
  3008. _paddingElement.after(_scrollbarVerticalElement);
  3009. _paddingElement.after(_scrollbarHorizontalElement);
  3010. }
  3011. else {
  3012. remove(_scrollbarHorizontalElement);
  3013. remove(_scrollbarVerticalElement);
  3014. }
  3015. }
  3016. /**
  3017. * Initializes all scrollbar interactivity events. (track and handle dragging, clicking, scrolling)
  3018. * @param isHorizontal True if the target scrollbar is the horizontal scrollbar, false if the target scrollbar is the vertical scrollbar.
  3019. */
  3020. function setupScrollbarEvents(isHorizontal) {
  3021. var scrollbarVars = getScrollbarVars(isHorizontal);
  3022. var scrollbarVarsInfo = scrollbarVars._info;
  3023. var insideIFrame = _windowElementNative.top !== _windowElementNative;
  3024. var xy = scrollbarVars._x_y;
  3025. var XY = scrollbarVars._X_Y;
  3026. var scroll = _strScroll + scrollbarVars._Left_Top;
  3027. var strActive = 'active';
  3028. var strSnapHandle = 'snapHandle';
  3029. var scrollDurationFactor = 1;
  3030. var increaseDecreaseScrollAmountKeyCodes = [ 16, 17 ]; //shift, ctrl
  3031. var trackTimeout;
  3032. var mouseDownScroll;
  3033. var mouseDownOffset;
  3034. var mouseDownInvertedScale;
  3035. function getPointerPosition(event) {
  3036. return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames.
  3037. }
  3038. function getPreparedScrollbarsOption(name) {
  3039. return _currentPreparedOptions.scrollbars[name];
  3040. }
  3041. function increaseTrackScrollAmount() {
  3042. scrollDurationFactor = 0.5;
  3043. }
  3044. function decreaseTrackScrollAmount() {
  3045. scrollDurationFactor = 1;
  3046. }
  3047. function documentKeyDown(event) {
  3048. if (FRAMEWORK.inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
  3049. increaseTrackScrollAmount();
  3050. }
  3051. function documentKeyUp(event) {
  3052. if (FRAMEWORK.inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
  3053. decreaseTrackScrollAmount();
  3054. }
  3055. function onMouseTouchDownContinue(event) {
  3056. var originalEvent = event.originalEvent || event;
  3057. var isTouchEvent = originalEvent.touches !== undefined;
  3058. return _isSleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
  3059. }
  3060. function documentDragMove(event) {
  3061. if(onMouseTouchDownContinue(event)) {
  3062. var trackLength = scrollbarVarsInfo._trackLength;
  3063. var handleLength = scrollbarVarsInfo._handleLength;
  3064. var scrollRange = scrollbarVarsInfo._maxScroll;
  3065. var scrollRaw = (getPointerPosition(event) - mouseDownOffset) * mouseDownInvertedScale;
  3066. var scrollDeltaPercent = scrollRaw / (trackLength - handleLength);
  3067. var scrollDelta = (scrollRange * scrollDeltaPercent);
  3068. scrollDelta = isFinite(scrollDelta) ? scrollDelta : 0;
  3069. if (_isRTL && isHorizontal && !_rtlScrollBehavior.i)
  3070. scrollDelta *= -1;
  3071. _viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta));
  3072. if(_scrollbarsHandleAsync)
  3073. refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta);
  3074. if (!_supportPassiveEvents)
  3075. COMPATIBILITY.prvD(event);
  3076. }
  3077. else
  3078. documentMouseTouchUp(event);
  3079. }
  3080. function documentMouseTouchUp(event) {
  3081. event = event || event.originalEvent;
  3082. _documentElement.off(_strMouseTouchMoveEvent, documentDragMove)
  3083. .off(_strMouseTouchUpEvent, documentMouseTouchUp)
  3084. .off(_strKeyDownEvent, documentKeyDown)
  3085. .off(_strKeyUpEvent, documentKeyUp)
  3086. .off(_strSelectStartEvent, documentOnSelectStart);
  3087. if(_scrollbarsHandleAsync)
  3088. refreshScrollbarHandleOffset(isHorizontal, true);
  3089. _scrollbarsHandleAsync = false;
  3090. removeClass(_bodyElement, _classNameDragging);
  3091. removeClass(scrollbarVars._handle, strActive);
  3092. removeClass(scrollbarVars._track, strActive);
  3093. removeClass(scrollbarVars._scrollbar, strActive);
  3094. mouseDownScroll = undefined;
  3095. mouseDownOffset = undefined;
  3096. mouseDownInvertedScale = 1;
  3097. decreaseTrackScrollAmount();
  3098. if (trackTimeout !== undefined) {
  3099. _base.scrollStop();
  3100. clearTimeout(trackTimeout);
  3101. trackTimeout = undefined;
  3102. }
  3103. if(event) {
  3104. var rect = _hostElementNative.getBoundingClientRect();
  3105. var mouseInsideHost = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
  3106. //if mouse is outside host element
  3107. if (!mouseInsideHost)
  3108. hostOnMouseLeave();
  3109. if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
  3110. refreshScrollbarsAutoHide(false);
  3111. }
  3112. }
  3113. function onHandleMouseTouchDown(event) {
  3114. mouseDownScroll = _viewportElement[scroll]();
  3115. mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll;
  3116. if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL)
  3117. mouseDownScroll = mouseDownScroll < 0 ? 0 : mouseDownScroll;
  3118. mouseDownInvertedScale = getHostElementInvertedScale()[xy];
  3119. mouseDownOffset = getPointerPosition(event);
  3120. _scrollbarsHandleAsync = !getPreparedScrollbarsOption(strSnapHandle);
  3121. addClass(_bodyElement, _classNameDragging);
  3122. addClass(scrollbarVars._handle, strActive);
  3123. addClass(scrollbarVars._scrollbar, strActive);
  3124. _documentElement.on(_strMouseTouchMoveEvent, documentDragMove)
  3125. .on(_strMouseTouchUpEvent, documentMouseTouchUp)
  3126. .on(_strSelectStartEvent, documentOnSelectStart);
  3127. if(_msieVersion || !_documentMixed)
  3128. COMPATIBILITY.prvD(event);
  3129. COMPATIBILITY.stpP(event);
  3130. }
  3131. scrollbarVars._handle.on(_strMouseTouchDownEvent, function(event) {
  3132. if (onMouseTouchDownContinue(event))
  3133. onHandleMouseTouchDown(event);
  3134. });
  3135. scrollbarVars._track.on(_strMouseTouchDownEvent, function(event) {
  3136. if (onMouseTouchDownContinue(event)) {
  3137. var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h]);
  3138. var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top];
  3139. var ctrlKey = event.ctrlKey;
  3140. var instantScroll = event.shiftKey;
  3141. var instantScrollTransition = instantScroll && ctrlKey;
  3142. var isFirstIteration = true;
  3143. var easing = 'linear';
  3144. var decreaseScroll;
  3145. var finishedCondition;
  3146. var scrollActionFinsished = function(transition) {
  3147. if(_scrollbarsHandleAsync)
  3148. refreshScrollbarHandleOffset(isHorizontal, transition);
  3149. };
  3150. var scrollActionInstantFinished = function() {
  3151. scrollActionFinsished();
  3152. onHandleMouseTouchDown(event);
  3153. };
  3154. var scrollAction = function () {
  3155. if(!_destroyed) {
  3156. var mouseOffset = (mouseDownOffset - trackOffset) * mouseDownInvertedScale;
  3157. var handleOffset = scrollbarVarsInfo._handleOffset;
  3158. var trackLength = scrollbarVarsInfo._trackLength;
  3159. var handleLength = scrollbarVarsInfo._handleLength;
  3160. var scrollRange = scrollbarVarsInfo._maxScroll;
  3161. var currScroll = scrollbarVarsInfo._currentScroll;
  3162. var scrollDuration = 270 * scrollDurationFactor;
  3163. var timeoutDelay = isFirstIteration ? MATH.max(400, scrollDuration) : scrollDuration;
  3164. var instantScrollPosition = scrollRange * ((mouseOffset - (handleLength / 2)) / (trackLength - handleLength)); // 100% * positionPercent
  3165. var rtlIsNormal = _isRTL && isHorizontal && ((!_rtlScrollBehavior.i && !_rtlScrollBehavior.n) || _normalizeRTLCache);
  3166. var decreaseScrollCondition = rtlIsNormal ? handleOffset < mouseOffset : handleOffset > mouseOffset;
  3167. var scrollObj = { };
  3168. var animationObj = {
  3169. easing : easing,
  3170. step : function(now) {
  3171. if(_scrollbarsHandleAsync) {
  3172. _viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/4340
  3173. refreshScrollbarHandleOffset(isHorizontal, now);
  3174. }
  3175. }
  3176. };
  3177. instantScrollPosition = isFinite(instantScrollPosition) ? instantScrollPosition : 0;
  3178. instantScrollPosition = _isRTL && isHorizontal && !_rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
  3179. //_base.scrollStop();
  3180. if(instantScroll) {
  3181. _viewportElement[scroll](instantScrollPosition); //scroll instantly to new position
  3182. if(instantScrollTransition) {
  3183. //get the scroll position after instant scroll (in case CSS Snap Points are used) to get the correct snapped scroll position
  3184. //and the animation stops at the correct point
  3185. instantScrollPosition = _viewportElement[scroll]();
  3186. //scroll back to the position before instant scrolling so animation can be performed
  3187. _viewportElement[scroll](currScroll);
  3188. instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
  3189. instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.n ? -instantScrollPosition : instantScrollPosition;
  3190. scrollObj[xy] = instantScrollPosition;
  3191. _base.scroll(scrollObj, extendDeep(animationObj, {
  3192. duration : 130,
  3193. complete : scrollActionInstantFinished
  3194. }));
  3195. }
  3196. else
  3197. scrollActionInstantFinished();
  3198. }
  3199. else {
  3200. decreaseScroll = isFirstIteration ? decreaseScrollCondition : decreaseScroll;
  3201. finishedCondition = rtlIsNormal
  3202. ? (decreaseScroll ? handleOffset + handleLength >= mouseOffset : handleOffset <= mouseOffset)
  3203. : (decreaseScroll ? handleOffset <= mouseOffset : handleOffset + handleLength >= mouseOffset);
  3204. if (finishedCondition) {
  3205. clearTimeout(trackTimeout);
  3206. _base.scrollStop();
  3207. trackTimeout = undefined;
  3208. scrollActionFinsished(true);
  3209. }
  3210. else {
  3211. trackTimeout = setTimeout(scrollAction, timeoutDelay);
  3212. scrollObj[xy] = (decreaseScroll ? '-=' : '+=') + scrollDistance;
  3213. _base.scroll(scrollObj, extendDeep(animationObj, {
  3214. duration: scrollDuration
  3215. }));
  3216. }
  3217. isFirstIteration = false;
  3218. }
  3219. }
  3220. };
  3221. if (ctrlKey)
  3222. increaseTrackScrollAmount();
  3223. mouseDownInvertedScale = getHostElementInvertedScale()[xy];
  3224. mouseDownOffset = COMPATIBILITY.page(event)[xy];
  3225. _scrollbarsHandleAsync = !getPreparedScrollbarsOption(strSnapHandle);
  3226. addClass(_bodyElement, _classNameDragging);
  3227. addClass(scrollbarVars._track, strActive);
  3228. addClass(scrollbarVars._scrollbar, strActive);
  3229. _documentElement.on(_strMouseTouchUpEvent, documentMouseTouchUp)
  3230. .on(_strKeyDownEvent, documentKeyDown)
  3231. .on(_strKeyUpEvent, documentKeyUp)
  3232. .on(_strSelectStartEvent, documentOnSelectStart);
  3233. scrollAction();
  3234. COMPATIBILITY.prvD(event);
  3235. COMPATIBILITY.stpP(event);
  3236. }
  3237. }).on(_strMouseTouchEnter, function() { //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move".
  3238. _scrollbarsHandleHovered = true;
  3239. if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
  3240. refreshScrollbarsAutoHide(true);
  3241. }).on(_strMouseTouchLeave, function() {
  3242. _scrollbarsHandleHovered = false;
  3243. if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
  3244. refreshScrollbarsAutoHide(false);
  3245. });
  3246. scrollbarVars._scrollbar.on(_strMouseTouchDownEvent, function(event) {
  3247. COMPATIBILITY.stpP(event);
  3248. });
  3249. if (_supportTransition) {
  3250. scrollbarVars._scrollbar.on(_strTransitionEndEvent, function(event) {
  3251. if (event.target !== scrollbarVars._scrollbar[0])
  3252. return;
  3253. refreshScrollbarHandleLength(isHorizontal);
  3254. refreshScrollbarHandleOffset(isHorizontal);
  3255. });
  3256. }
  3257. }
  3258. /**
  3259. * Shows or hides the given scrollbar and applied a class name which indicates if the scrollbar is scrollable or not.
  3260. * @param isHorizontal True if the horizontal scrollbar is the target, false if the vertical scrollbar is the target.
  3261. * @param shallBeVisible True if the scrollbar shall be shown, false if hidden.
  3262. * @param canScroll True if the scrollbar is scrollable, false otherwise.
  3263. */
  3264. function refreshScrollbarAppearance(isHorizontal, shallBeVisible, canScroll) {
  3265. var scrollbarClassName = isHorizontal ? _classNameHostScrollbarHorizontalHidden : _classNameHostScrollbarVerticalHidden;
  3266. var scrollbarElement = isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement;
  3267. if (shallBeVisible)
  3268. removeClass(_hostElement, scrollbarClassName);
  3269. else
  3270. addClass(_hostElement, scrollbarClassName);
  3271. if (canScroll)
  3272. removeClass(scrollbarElement, _classNameScrollbarUnusable);
  3273. else
  3274. addClass(scrollbarElement, _classNameScrollbarUnusable);
  3275. }
  3276. /**
  3277. * Autoshows / autohides both scrollbars with.
  3278. * @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.
  3279. * @param delayfree True if the scrollbars shall be hidden without a delay, false or undefined otherwise.
  3280. */
  3281. function refreshScrollbarsAutoHide(shallBeVisible, delayfree) {
  3282. clearTimeout(_scrollbarsAutoHideTimeoutId);
  3283. if (shallBeVisible) {
  3284. //if(_hasOverflowCache.x && _hideOverflowCache.xs)
  3285. removeClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
  3286. //if(_hasOverflowCache.y && _hideOverflowCache.ys)
  3287. removeClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
  3288. }
  3289. else {
  3290. var anyActive;
  3291. var strActive = 'active';
  3292. var hide = function () {
  3293. if (!_scrollbarsHandleHovered && !_destroyed) {
  3294. anyActive = _scrollbarHorizontalHandleElement.hasClass(strActive) || _scrollbarVerticalHandleElement.hasClass(strActive);
  3295. if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
  3296. addClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
  3297. if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
  3298. addClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
  3299. }
  3300. };
  3301. if (_scrollbarsAutoHideDelay > 0 && delayfree !== true)
  3302. _scrollbarsAutoHideTimeoutId = setTimeout(hide, _scrollbarsAutoHideDelay);
  3303. else
  3304. hide();
  3305. }
  3306. }
  3307. /**
  3308. * Refreshes the handle length of the given scrollbar.
  3309. * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
  3310. */
  3311. function refreshScrollbarHandleLength(isHorizontal) {
  3312. var handleCSS = {};
  3313. var scrollbarVars = getScrollbarVars(isHorizontal);
  3314. var scrollbarVarsInfo = scrollbarVars._info;
  3315. var digit = 1000000;
  3316. //get and apply intended handle length
  3317. var handleRatio = MATH.min(1, (_hostSizeCache[scrollbarVars._w_h] - (_paddingAbsoluteCache ? (isHorizontal ? _paddingX : _paddingY) : 0)) / _contentScrollSizeCache[scrollbarVars._w_h]);
  3318. handleCSS[scrollbarVars._width_height] = (MATH.floor(handleRatio * 100 * digit) / digit) + "%"; //the last * digit / digit is for flooring to the 4th digit
  3319. if (!nativeOverlayScrollbarsAreActive())
  3320. scrollbarVars._handle.css(handleCSS);
  3321. //measure the handle length to respect min & max length
  3322. scrollbarVarsInfo._handleLength = scrollbarVars._handle[0]['offset' + scrollbarVars._Width_Height];
  3323. scrollbarVarsInfo._handleLengthRatio = handleRatio;
  3324. }
  3325. /**
  3326. * Refreshes the handle offset of the given scrollbar.
  3327. * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
  3328. * @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)
  3329. */
  3330. function refreshScrollbarHandleOffset(isHorizontal, scrollOrTransition) {
  3331. var transition = type(scrollOrTransition) == TYPES.b;
  3332. var transitionDuration = 250;
  3333. var isRTLisHorizontal = _isRTL && isHorizontal;
  3334. var scrollbarVars = getScrollbarVars(isHorizontal);
  3335. var scrollbarVarsInfo = scrollbarVars._info;
  3336. var strTranslateBrace = 'translate(';
  3337. var strTransform = VENDORS._cssProperty('transform');
  3338. var strTransition = VENDORS._cssProperty('transition');
  3339. var nativeScroll = isHorizontal ? _viewportElement[_strScrollLeft]() : _viewportElement[_strScrollTop]();
  3340. var currentScroll = scrollOrTransition === undefined || transition ? nativeScroll : scrollOrTransition;
  3341. //measure the handle length to respect min & max length
  3342. var handleLength = scrollbarVarsInfo._handleLength;
  3343. var trackLength = scrollbarVars._track[0]['offset' + scrollbarVars._Width_Height];
  3344. var handleTrackDiff = trackLength - handleLength;
  3345. var handleCSS = {};
  3346. var transformOffset;
  3347. var translateValue;
  3348. //DONT use the variable '_contentScrollSizeCache[scrollbarVars._w_h]' instead of '_viewportElement[0]['scroll' + scrollbarVars._Width_Height]'
  3349. // because its a bit behind during the small delay when content size updates
  3350. //(delay = mutationObserverContentLag, if its 0 then this var could be used)
  3351. var maxScroll = (_viewportElementNative[_strScroll + scrollbarVars._Width_Height] - _viewportElementNative['client' + scrollbarVars._Width_Height]) * (_rtlScrollBehavior.n && isRTLisHorizontal ? -1 : 1); //* -1 if rtl scroll max is negative
  3352. var getScrollRatio = function(base) {
  3353. return isNaN(base / maxScroll) ? 0 : MATH.max(0, MATH.min(1, base / maxScroll));
  3354. };
  3355. var getHandleOffset = function(scrollRatio) {
  3356. var offset = handleTrackDiff * scrollRatio;
  3357. offset = isNaN(offset) ? 0 : offset;
  3358. offset = (isRTLisHorizontal && !_rtlScrollBehavior.i) ? (trackLength - handleLength - offset) : offset;
  3359. offset = MATH.max(0, offset);
  3360. return offset;
  3361. };
  3362. var scrollRatio = getScrollRatio(nativeScroll);
  3363. var unsnappedScrollRatio = getScrollRatio(currentScroll);
  3364. var handleOffset = getHandleOffset(unsnappedScrollRatio);
  3365. var snappedHandleOffset = getHandleOffset(scrollRatio);
  3366. scrollbarVarsInfo._maxScroll = maxScroll;
  3367. scrollbarVarsInfo._currentScroll = nativeScroll;
  3368. scrollbarVarsInfo._currentScrollRatio = scrollRatio;
  3369. if (_supportTransform) {
  3370. transformOffset = isRTLisHorizontal ? -(trackLength - handleLength - handleOffset) : handleOffset; //in px
  3371. //transformOffset = (transformOffset / trackLength * 100) * (trackLength / handleLength); //in %
  3372. translateValue = isHorizontal ? strTranslateBrace + transformOffset + 'px, 0)' : strTranslateBrace + '0, ' + transformOffset + 'px)';
  3373. handleCSS[strTransform] = translateValue;
  3374. //apply or clear up transition
  3375. if(_supportTransition)
  3376. handleCSS[strTransition] = transition && MATH.abs(handleOffset - scrollbarVarsInfo._handleOffset) > 1 ? getCSSTransitionString(scrollbarVars._handle) + ', ' + (strTransform + _strSpace + transitionDuration + 'ms') : _strEmpty;
  3377. }
  3378. else
  3379. handleCSS[scrollbarVars._left_top] = handleOffset;
  3380. //only apply css if offset has changed and overflow exists.
  3381. if (!nativeOverlayScrollbarsAreActive()) {
  3382. scrollbarVars._handle.css(handleCSS);
  3383. //clear up transition
  3384. if(_supportTransform && _supportTransition && transition) {
  3385. scrollbarVars._handle.one(_strTransitionEndEvent, function() {
  3386. if(!_destroyed)
  3387. scrollbarVars._handle.css(strTransition, _strEmpty);
  3388. });
  3389. }
  3390. }
  3391. scrollbarVarsInfo._handleOffset = handleOffset;
  3392. scrollbarVarsInfo._snappedHandleOffset = snappedHandleOffset;
  3393. scrollbarVarsInfo._trackLength = trackLength;
  3394. }
  3395. /**
  3396. * Refreshes the interactivity of the given scrollbar element.
  3397. * @param isTrack True if the track element is the target, false if the handle element is the target.
  3398. * @param value True for interactivity false for no interactivity.
  3399. */
  3400. function refreshScrollbarsInteractive(isTrack, value) {
  3401. var action = value ? 'removeClass' : 'addClass';
  3402. var element1 = isTrack ? _scrollbarHorizontalTrackElement : _scrollbarHorizontalHandleElement;
  3403. var element2 = isTrack ? _scrollbarVerticalTrackElement : _scrollbarVerticalHandleElement;
  3404. var className = isTrack ? _classNameScrollbarTrackOff : _classNameScrollbarHandleOff;
  3405. element1[action](className);
  3406. element2[action](className);
  3407. }
  3408. /**
  3409. * Returns a object which is used for fast access for specific variables.
  3410. * @param isHorizontal True if the horizontal scrollbar vars shall be accessed, false if the vertical scrollbar vars shall be accessed.
  3411. * @returns {{wh: string, WH: string, lt: string, _wh: string, _lt: string, t: *, h: *, c: {}, s: *}}
  3412. */
  3413. function getScrollbarVars(isHorizontal) {
  3414. return {
  3415. _width_height: isHorizontal ? _strWidth : _strHeight,
  3416. _Width_Height: isHorizontal ? 'Width' : 'Height',
  3417. _left_top: isHorizontal ? _strLeft : _strTop,
  3418. _Left_Top: isHorizontal ? 'Left' : 'Top',
  3419. _x_y: isHorizontal ? _strX : _strY,
  3420. _X_Y: isHorizontal ? 'X' : 'Y',
  3421. _w_h: isHorizontal ? 'w' : 'h',
  3422. _l_t: isHorizontal ? 'l' : 't',
  3423. _track: isHorizontal ? _scrollbarHorizontalTrackElement : _scrollbarVerticalTrackElement,
  3424. _handle: isHorizontal ? _scrollbarHorizontalHandleElement : _scrollbarVerticalHandleElement,
  3425. _scrollbar: isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement,
  3426. _info: isHorizontal ? _scrollHorizontalInfo : _scrollVerticalInfo
  3427. };
  3428. }
  3429. //==== Scrollbar Corner ====//
  3430. /**
  3431. * Builds or destroys the scrollbar corner DOM element.
  3432. * @param destroy Indicates whether the DOM shall be build or destroyed.
  3433. */
  3434. function setupScrollbarCornerDOM(destroy) {
  3435. if(!destroy) {
  3436. _scrollbarCornerElement = FRAMEWORK(generateDiv(_classNameScrollbarCorner));
  3437. _hostElement.append(_scrollbarCornerElement);
  3438. }
  3439. else {
  3440. remove(_scrollbarCornerElement);
  3441. }
  3442. }
  3443. /**
  3444. * Initializes all scrollbar corner interactivity events.
  3445. */
  3446. function setupScrollbarCornerEvents() {
  3447. var insideIFrame = _windowElementNative.top !== _windowElementNative;
  3448. var mouseDownPosition = { };
  3449. var mouseDownSize = { };
  3450. var mouseDownInvertedScale = { };
  3451. _resizeOnMouseTouchDown = function(event) {
  3452. if (onMouseTouchDownContinue(event)) {
  3453. if (_mutationObserversConnected) {
  3454. _resizeReconnectMutationObserver = true;
  3455. disconnectMutationObservers();
  3456. }
  3457. mouseDownPosition = getCoordinates(event);
  3458. mouseDownSize.w = _hostElementNative[LEXICON.oW] - (!_isBorderBox ? _paddingX : 0);
  3459. mouseDownSize.h = _hostElementNative[LEXICON.oH] - (!_isBorderBox ? _paddingY : 0);
  3460. mouseDownInvertedScale = getHostElementInvertedScale();
  3461. _documentElement.on(_strSelectStartEvent, documentOnSelectStart)
  3462. .on(_strMouseTouchMoveEvent, documentDragMove)
  3463. .on(_strMouseTouchUpEvent, documentMouseTouchUp);
  3464. addClass(_bodyElement, _classNameDragging);
  3465. if (_scrollbarCornerElement.setCapture)
  3466. _scrollbarCornerElement.setCapture();
  3467. COMPATIBILITY.prvD(event);
  3468. COMPATIBILITY.stpP(event);
  3469. }
  3470. };
  3471. function documentDragMove(event) {
  3472. if (onMouseTouchDownContinue(event)) {
  3473. var pageOffset = getCoordinates(event);
  3474. var hostElementCSS = { };
  3475. if (_resizeHorizontal || _resizeBoth)
  3476. hostElementCSS[_strWidth] = (mouseDownSize.w + (pageOffset.x - mouseDownPosition.x) * mouseDownInvertedScale.x);
  3477. if (_resizeVertical || _resizeBoth)
  3478. hostElementCSS[_strHeight] = (mouseDownSize.h + (pageOffset.y - mouseDownPosition.y) * mouseDownInvertedScale.y);
  3479. _hostElement.css(hostElementCSS);
  3480. COMPATIBILITY.stpP(event);
  3481. }
  3482. else {
  3483. documentMouseTouchUp(event);
  3484. }
  3485. }
  3486. function documentMouseTouchUp(event) {
  3487. var eventIsTrusted = event !== undefined;
  3488. _documentElement.off(_strSelectStartEvent, documentOnSelectStart)
  3489. .off(_strMouseTouchMoveEvent, documentDragMove)
  3490. .off(_strMouseTouchUpEvent, documentMouseTouchUp);
  3491. removeClass(_bodyElement, _classNameDragging);
  3492. if (_scrollbarCornerElement.releaseCapture)
  3493. _scrollbarCornerElement.releaseCapture();
  3494. if (eventIsTrusted) {
  3495. if (_resizeReconnectMutationObserver)
  3496. connectMutationObservers();
  3497. _base.update(_strAuto);
  3498. }
  3499. _resizeReconnectMutationObserver = false;
  3500. }
  3501. function onMouseTouchDownContinue(event) {
  3502. var originalEvent = event.originalEvent || event;
  3503. var isTouchEvent = originalEvent.touches !== undefined;
  3504. return _isSleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
  3505. }
  3506. function getCoordinates(event) {
  3507. return _msieVersion && insideIFrame ? { x : event.screenX , y : event.screenY } : COMPATIBILITY.page(event);
  3508. }
  3509. }
  3510. //==== Utils ====//
  3511. /**
  3512. * Calls the callback with the given name. The Context of this callback is always _base (this).
  3513. * @param name The name of the target which shall be called.
  3514. * @param args The args with which the callback shall be called.
  3515. */
  3516. function dispatchCallback(name, args) {
  3517. if(_initialized) {
  3518. var callback = _currentPreparedOptions.callbacks[name];
  3519. var extensionOnName = name;
  3520. var ext;
  3521. if(extensionOnName.substr(0, 2) === "on")
  3522. extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3);
  3523. if(type(callback) == TYPES.f)
  3524. callback.call(_base, args);
  3525. FRAMEWORK.each(_extensions, function() {
  3526. ext = this;
  3527. if(type(ext.on) == TYPES.f)
  3528. ext.on(extensionOnName, args);
  3529. });
  3530. }
  3531. else if(!_destroyed)
  3532. _callbacksInitQeueue.push({ n : name, a : args });
  3533. }
  3534. /**
  3535. * Sets the "top, right, bottom, left" properties, with a given prefix, of the given css object.
  3536. * @param targetCSSObject The css object to which the values shall be applied.
  3537. * @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
  3538. * @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].
  3539. * If this argument is undefined the value '' (empty string) will be applied to all properties.
  3540. */
  3541. function setTopRightBottomLeft(targetCSSObject, prefix, values) {
  3542. if (values === undefined)
  3543. values = [_strEmpty, _strEmpty, _strEmpty, _strEmpty];
  3544. targetCSSObject[prefix + _strTop] = values[0];
  3545. targetCSSObject[prefix + _strRight] = values[1];
  3546. targetCSSObject[prefix + _strBottom] = values[2];
  3547. targetCSSObject[prefix + _strLeft] = values[3];
  3548. }
  3549. /**
  3550. * Returns the computed CSS transition string from the given element.
  3551. * @param element The element from which the transition string shall be returned.
  3552. * @returns {string} The CSS transition string from the given element.
  3553. */
  3554. function getCSSTransitionString(element) {
  3555. var transitionStr = VENDORS._cssProperty('transition');
  3556. var assembledValue = element.css(transitionStr);
  3557. if(assembledValue)
  3558. return assembledValue;
  3559. var regExpString = '\\s*(' + '([^,(]+(\\(.+?\\))?)+' + ')[\\s,]*';
  3560. var regExpMain = new RegExp(regExpString);
  3561. var regExpValidate = new RegExp('^(' + regExpString + ')+$');
  3562. var properties = 'property duration timing-function delay'.split(' ');
  3563. var result = [ ];
  3564. var strResult;
  3565. var valueArray;
  3566. var i = 0;
  3567. var j;
  3568. var splitCssStyleByComma = function(str) {
  3569. strResult = [ ];
  3570. if (!str.match(regExpValidate))
  3571. return str;
  3572. while (str.match(regExpMain)) {
  3573. strResult.push(RegExp.$1);
  3574. str = str.replace(regExpMain, _strEmpty);
  3575. }
  3576. return strResult;
  3577. };
  3578. for (; i < properties[LEXICON.l]; i++) {
  3579. valueArray = splitCssStyleByComma(element.css(transitionStr + '-' + properties[i]));
  3580. for (j = 0; j < valueArray[LEXICON.l]; j++)
  3581. result[j] = (result[j] ? result[j] + _strSpace : _strEmpty) + valueArray[j];
  3582. }
  3583. return result.join(', ');
  3584. }
  3585. /**
  3586. * Calculates the host-elements inverted scale. (invertedScale = 1 / scale)
  3587. * @returns {{x: number, y: number}} The scale of the host-element.
  3588. */
  3589. function getHostElementInvertedScale() {
  3590. var rect = _paddingElementNative.getBoundingClientRect();
  3591. return {
  3592. x : _supportTransform ? 1 / (MATH.round(rect.width) / _paddingElementNative[LEXICON.oW]) : 1,
  3593. y : _supportTransform ? 1 / (MATH.round(rect.height) / _paddingElementNative[LEXICON.oH]) : 1
  3594. };
  3595. }
  3596. /**
  3597. * Checks whether the given object is a HTMLElement.
  3598. * @param o The object which shall be checked.
  3599. * @returns {boolean} True the given object is a HTMLElement, false otherwise.
  3600. */
  3601. function isHTMLElement(o) {
  3602. var strOwnerDocument = 'ownerDocument';
  3603. var strHTMLElement = 'HTMLElement';
  3604. var wnd = o && o[strOwnerDocument] ? (o[strOwnerDocument].parentWindow || window) : window;
  3605. return (
  3606. typeof wnd[strHTMLElement] == TYPES.o ? o instanceof wnd[strHTMLElement] : //DOM2
  3607. o && typeof o == TYPES.o && o !== null && o.nodeType === 1 && typeof o.nodeName == TYPES.s
  3608. );
  3609. }
  3610. /**
  3611. * Compares 2 arrays and returns the differences between them as a array.
  3612. * @param a1 The first array which shall be compared.
  3613. * @param a2 The second array which shall be compared.
  3614. * @returns {Array} The differences between the two arrays.
  3615. */
  3616. function getArrayDifferences(a1, a2) {
  3617. var a = [ ];
  3618. var diff = [ ];
  3619. var i;
  3620. var k;
  3621. for (i = 0; i < a1.length; i++)
  3622. a[a1[i]] = true;
  3623. for (i = 0; i < a2.length; i++) {
  3624. if (a[a2[i]])
  3625. delete a[a2[i]];
  3626. else
  3627. a[a2[i]] = true;
  3628. }
  3629. for (k in a)
  3630. diff.push(k);
  3631. return diff;
  3632. }
  3633. /**
  3634. * Returns Zero or the number to which the value can be parsed.
  3635. * @param value The value which shall be parsed.
  3636. * @param toFloat Indicates whether the number shall be parsed to a float.
  3637. */
  3638. function parseToZeroOrNumber(value, toFloat) {
  3639. var num = toFloat ? parseFloat(value) : parseInt(value, 10);
  3640. return isNaN(num) ? 0 : num;
  3641. }
  3642. /**
  3643. * Gets several information of the textarea and returns them as a object or undefined if the browser doesn't support it.
  3644. * @returns {{cursorRow: Number, cursorCol, rows: Number, cols: number, wRow: number, pos: number, max : number}} or undefined if not supported.
  3645. */
  3646. function getTextareaInfo() {
  3647. //read needed values
  3648. var textareaCursorPosition = _targetElementNative.selectionStart;
  3649. if (textareaCursorPosition === undefined)
  3650. return;
  3651. var strLength = 'length';
  3652. var textareaValue = _targetElement.val();
  3653. var textareaLength = textareaValue[strLength];
  3654. var textareaRowSplit = textareaValue.split("\n");
  3655. var textareaLastRow = textareaRowSplit[strLength];
  3656. var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split("\n");
  3657. var widestRow = 0;
  3658. var textareaLastCol = 0;
  3659. var cursorRow = textareaCurrentCursorRowSplit[strLength];
  3660. var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[strLength] - 1][strLength];
  3661. var rowCols;
  3662. var i;
  3663. //get widest Row and the last column of the textarea
  3664. for (i = 0; i < textareaRowSplit[strLength]; i++) {
  3665. rowCols = textareaRowSplit[i][strLength];
  3666. if (rowCols > textareaLastCol) {
  3667. widestRow = i + 1;
  3668. textareaLastCol = rowCols;
  3669. }
  3670. }
  3671. return {
  3672. _cursorRow: cursorRow, //cursorRow
  3673. _cursorColumn: cursorCol, //cursorCol
  3674. _rows: textareaLastRow, //rows
  3675. _columns: textareaLastCol, //cols
  3676. _widestRow: widestRow, //wRow
  3677. _cursorPosition: textareaCursorPosition, //pos
  3678. _cursorMax: textareaLength //max
  3679. };
  3680. }
  3681. /**
  3682. * Determines whether native overlay scrollbars are active.
  3683. * @returns {boolean} True if native overlay scrollbars are active, false otherwise.
  3684. */
  3685. function nativeOverlayScrollbarsAreActive() {
  3686. return (_ignoreOverlayScrollbarHidingCache && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y));
  3687. }
  3688. /**
  3689. * Gets the element which is used to measure the content size.
  3690. * @returns {*} TextareaCover if target element is textarea else the ContentElement.
  3691. */
  3692. function getContentMeasureElement() {
  3693. return _isTextarea ? _textareaCoverElement[0] : _contentElementNative;
  3694. }
  3695. /**
  3696. * Generates a string which represents a HTML div with the given classes or attributes.
  3697. * @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".)
  3698. * @param content The content of the div as string.
  3699. * @returns {string} The concated string which represents a HTML div and its content.
  3700. */
  3701. function generateDiv(classesOrAttrs, content) {
  3702. return '<div ' + (classesOrAttrs ? type(classesOrAttrs) == TYPES.s ?
  3703. 'class="' + classesOrAttrs + '"' :
  3704. (function() {
  3705. var key;
  3706. var attrs = '';
  3707. if(FRAMEWORK.isPlainObject(classesOrAttrs)) {
  3708. for (key in classesOrAttrs)
  3709. attrs += (key === 'className' ? 'class' : key) + '="' + classesOrAttrs[key] + '" ';
  3710. }
  3711. return attrs;
  3712. })() :
  3713. _strEmpty) +
  3714. '>' +
  3715. (content ? content : _strEmpty) +
  3716. '</div>';
  3717. }
  3718. /**
  3719. * Gets the value of the given property from the given object.
  3720. * @param obj The object from which the property value shall be got.
  3721. * @param path The property of which the value shall be got.
  3722. * @returns {*} Returns the value of the searched property or undefined of the property wasn't found.
  3723. */
  3724. function getObjectPropVal(obj, path) {
  3725. var splits = path.split(_strDot);
  3726. var i = 0;
  3727. var val;
  3728. for(; i < splits.length; i++) {
  3729. if(!obj.hasOwnProperty(splits[i]))
  3730. return;
  3731. val = obj[splits[i]];
  3732. if(i < splits.length && type(val) == TYPES.o)
  3733. obj = val;
  3734. }
  3735. return val;
  3736. }
  3737. /**
  3738. * Sets the value of the given property from the given object.
  3739. * @param obj The object from which the property value shall be set.
  3740. * @param path The property of which the value shall be set.
  3741. * @param val The value of the property which shall be set.
  3742. */
  3743. function setObjectPropVal(obj, path, val) {
  3744. var splits = path.split(_strDot);
  3745. var splitsLength = splits.length;
  3746. var i = 0;
  3747. var extendObj = { };
  3748. var extendObjRoot = extendObj;
  3749. for(; i < splitsLength; i++)
  3750. extendObj = extendObj[splits[i]] = i + 1 < splitsLength ? { } : val;
  3751. FRAMEWORK.extend(obj, extendObjRoot, true);
  3752. }
  3753. //==== Utils Cache ====//
  3754. /**
  3755. * Compares two values and returns the result of the comparison as a boolean.
  3756. * @param current The first value which shall be compared.
  3757. * @param cache The second value which shall be compared.
  3758. * @param force If true the returned value is always true.
  3759. * @returns {boolean} True if both variables aren't equal or some of them is undefined or when the force parameter is true, false otherwise.
  3760. */
  3761. function checkCacheSingle(current, cache, force) {
  3762. if (force === true)
  3763. return force;
  3764. if (cache === undefined)
  3765. return true;
  3766. else if (current !== cache)
  3767. return true;
  3768. return false;
  3769. }
  3770. /**
  3771. * Compares two objects with two properties and returns the result of the comparison as a boolean.
  3772. * @param current The first object which shall be compared.
  3773. * @param cache The second object which shall be compared.
  3774. * @param prop1 The name of the first property of the objects which shall be compared.
  3775. * @param prop2 The name of the second property of the objects which shall be compared.
  3776. * @param force If true the returned value is always true.
  3777. * @returns {boolean} True if both variables aren't equal or some of them is undefined or when the force parameter is true, false otherwise.
  3778. */
  3779. function checkCacheDouble(current, cache, prop1, prop2, force) {
  3780. if (force === true)
  3781. return force;
  3782. if (prop2 === undefined && force === undefined) {
  3783. if (prop1 === true)
  3784. return prop1;
  3785. else
  3786. prop1 = undefined;
  3787. }
  3788. prop1 = prop1 === undefined ? 'w' : prop1;
  3789. prop2 = prop2 === undefined ? 'h' : prop2;
  3790. if (cache === undefined)
  3791. return true;
  3792. else if (current[prop1] !== cache[prop1] || current[prop2] !== cache[prop2])
  3793. return true;
  3794. return false;
  3795. }
  3796. /**
  3797. * Compares two objects which have four properties and returns the result of the comparison as a boolean.
  3798. * @param current The first object with four properties.
  3799. * @param cache The second object with four properties.
  3800. * @returns {boolean} True if both objects aren't equal or some of them is undefined, false otherwise.
  3801. */
  3802. function checkCacheTRBL(current, cache) {
  3803. if (cache === undefined)
  3804. return true;
  3805. else if (current.t !== cache.t ||
  3806. current.r !== cache.r ||
  3807. current.b !== cache.b ||
  3808. current.l !== cache.l)
  3809. return true;
  3810. return false;
  3811. }
  3812. //==== Shortcuts ====//
  3813. /**
  3814. * jQuery type method shortcut.
  3815. */
  3816. function type(obj) {
  3817. return COMPATIBILITY.type(obj);
  3818. }
  3819. /**
  3820. * jQuery extend method shortcut with a appended "true" as first argument.
  3821. */
  3822. function extendDeep() {
  3823. return FRAMEWORK.extend.apply(this, [ true ].concat([].slice.call(arguments)));
  3824. }
  3825. /**
  3826. * jQuery addClass method shortcut.
  3827. */
  3828. function addClass(el, classes) {
  3829. return _frameworkProto.addClass.call(el, classes);
  3830. }
  3831. /**
  3832. * jQuery removeClass method shortcut.
  3833. */
  3834. function removeClass(el, classes) {
  3835. return _frameworkProto.removeClass.call(el, classes);
  3836. }
  3837. /**
  3838. * jQuery remove method shortcut.
  3839. */
  3840. function remove(el) {
  3841. return _frameworkProto.remove.call(el);
  3842. }
  3843. /**
  3844. * Finds the first child element with the given selector of the given element.
  3845. * @param el The root element from which the selector shall be valid.
  3846. * @param selector The selector of the searched element.
  3847. * @returns {*} The first element which is a child of the given element and matches the givens selector.
  3848. */
  3849. function findFirst(el, selector) {
  3850. return _frameworkProto.find.call(el, selector).eq(0);
  3851. }
  3852. //==== API ====//
  3853. /**
  3854. * 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.
  3855. * This behavior can be reset by calling the update method.
  3856. */
  3857. _base.sleep = function () {
  3858. _isSleeping = true;
  3859. };
  3860. /**
  3861. * Updates the plugin and DOM to the current options.
  3862. * This method should only be called if a update is 100% required.
  3863. * @param force True if every property shall be updated and the cache shall be ignored.
  3864. * !INTERNAL USAGE! : force can be a string "auto", "auto+" or "zoom" too
  3865. * if this is the case 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.
  3866. */
  3867. _base.update = function (force) {
  3868. var attrsChanged;
  3869. var contentSizeC;
  3870. var isString = type(force) == TYPES.s;
  3871. var imgElementSelector = 'img';
  3872. var imgElementLoadEvent = 'load';
  3873. var isPlus = isString && force.slice(-1) == '+';
  3874. if(isString) {
  3875. if (force.indexOf(_strAuto) === 0) {
  3876. attrsChanged = meaningfulAttrsChanged();
  3877. contentSizeC = updateAutoContentSizeChanged();
  3878. if (attrsChanged || contentSizeC || isPlus)
  3879. update(false, contentSizeC, false, isPlus);
  3880. }
  3881. else if (force === 'zoom')
  3882. update(true, true);
  3883. }
  3884. else {
  3885. force = _isSleeping || force;
  3886. _isSleeping = false;
  3887. update(false, false, force, true);
  3888. }
  3889. if(!_isTextarea) {
  3890. _contentElement.find(imgElementSelector).each(function(i, el) {
  3891. var index = COMPATIBILITY.inA(el, _imgs);
  3892. if (index === -1)
  3893. FRAMEWORK(el).off(imgElementLoadEvent, imgOnLoad).on(imgElementLoadEvent, imgOnLoad);
  3894. });
  3895. }
  3896. };
  3897. /**
  3898. Gets or sets the current options. The update method will be called automatically if new options were set.
  3899. * @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.
  3900. * @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.
  3901. * @returns {*}
  3902. */
  3903. _base.options = function (newOptions, value) {
  3904. //return current options if newOptions are undefined or empty
  3905. if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) {
  3906. if (type(newOptions) == TYPES.s) {
  3907. if (arguments.length > 1) {
  3908. var option = { };
  3909. setObjectPropVal(option, newOptions, value);
  3910. setOptions(option);
  3911. update();
  3912. return;
  3913. }
  3914. else
  3915. return getObjectPropVal(_currentOptions, newOptions);
  3916. }
  3917. else
  3918. return _currentOptions;
  3919. }
  3920. setOptions(newOptions);
  3921. var isSleepingTmp = _isSleeping || false;
  3922. _isSleeping = false;
  3923. update();
  3924. _isSleeping = isSleepingTmp;
  3925. };
  3926. /**
  3927. * Restore the DOM, disconnects all observers, remove all resize observers and destroy all methods.
  3928. */
  3929. _base.destroy = function () {
  3930. _destroyed = true;
  3931. //remove this instance from auto update loop
  3932. autoUpdateLoop.remove(_base);
  3933. //disconnect all mutation observers
  3934. disconnectMutationObservers();
  3935. //remove all resize observers
  3936. removeResizeObserver(_sizeObserverElement);
  3937. if (_sizeAutoObserverAdded)
  3938. removeResizeObserver(_sizeAutoObserverElement);
  3939. //remove all extensions
  3940. for(var extName in _extensions)
  3941. _base.removeExt(extName);
  3942. //remove all events from host element
  3943. setupHostMouseTouchEvents(true);
  3944. //remove all events from structure
  3945. setupStructureEvents(true);
  3946. //remove all helper / detection elements
  3947. if (_contentGlueElement)
  3948. remove(_contentGlueElement);
  3949. if (_contentArrangeElement)
  3950. remove(_contentArrangeElement);
  3951. if (_sizeAutoObserverAdded)
  3952. remove(_sizeAutoObserverElement);
  3953. //remove all generated DOM
  3954. setupScrollbarsDOM(true);
  3955. setupScrollbarCornerDOM(true);
  3956. setupStructureDOM(true);
  3957. //remove all generated image load events
  3958. for(var i = 0; i < _imgs[LEXICON.l]; i++)
  3959. FRAMEWORK(_imgs[i]).off('load', imgOnLoad);
  3960. _imgs = undefined;
  3961. //remove this instance from the instances list
  3962. INSTANCES(pluginTargetElement, 0);
  3963. dispatchCallback("onDestroyed");
  3964. //remove all properties and methods
  3965. for (var property in _base)
  3966. delete _base[property];
  3967. _base = undefined;
  3968. };
  3969. /**
  3970. * Scrolls to a given position or element.
  3971. * @param coordinates
  3972. * 1. Can be "coordinates" which looks like:
  3973. * { x : ?, y : ? } OR Object with x and y properties
  3974. * { left : ?, top : ? } OR Object with left and top properties
  3975. * { l : ?, t : ? } OR Object with l and t properties
  3976. * [ ?, ? ] OR Array where the first two element are the coordinates (first is x, second is y)
  3977. * ? A single value which stays for both axis
  3978. * A value can be a number, a string or a calculation.
  3979. *
  3980. * Operators:
  3981. * [NONE] The current scroll will be overwritten by the value.
  3982. * '+=' The value will be added to the current scroll offset
  3983. * '-=' The value will be subtracted from the current scroll offset
  3984. * '*=' The current scroll wil be multiplicated by the value.
  3985. * '/=' The current scroll wil be divided by the value.
  3986. *
  3987. * Units:
  3988. * [NONE] The value is the final scroll amount. final = (value * 1)
  3989. * 'px' Same as none
  3990. * '%' The value is dependent on the current scroll value. final = ((currentScrollValue / 100) * value)
  3991. * 'vw' The value is multiplicated by the viewport width. final = (value * viewportWidth)
  3992. * 'vh' The value is multiplicated by the viewport height. final = (value * viewportHeight)
  3993. *
  3994. * example final values:
  3995. * 200, '200px', '50%', '1vw', '1vh', '+=200', '/=1vw', '*=2px', '-=5vh', '+=33%', '+= 50% - 2px', '-= 1vw - 50%'
  3996. *
  3997. * 2. Can be a HTML or jQuery element:
  3998. * The final scroll offset is the offset (without margin) of the given HTML / jQuery element.
  3999. *
  4000. * 3. Can be a object with a HTML or jQuery element with additional settings:
  4001. * {
  4002. * el : [HTMLElement, jQuery element], MUST be specified, else this object isn't valid.
  4003. * scroll : [string, array, object], Default value is 'always'.
  4004. * block : [string, array, object], Default value is 'begin'.
  4005. * margin : [number, boolean, array, object] Default value is false.
  4006. * }
  4007. *
  4008. * Possible scroll settings are:
  4009. * 'always' Scrolls always.
  4010. * 'ifneeded' Scrolls only if the element isnt fully in view.
  4011. * 'never' Scrolls never.
  4012. *
  4013. * Possible block settings are:
  4014. * 'begin' Both axis shall be docked to the "begin" edge. - The element will be docked to the top and left edge of the viewport.
  4015. * '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.)
  4016. * 'center' Both axis shall be docked to "center". - The element will be centered in the viewport.
  4017. * 'nearest' The element will be docked to the nearest edge(s).
  4018. *
  4019. * Possible margin settings are: -- The actual margin of the element wont be affect, this option affects only the final scroll offset.
  4020. * [BOOLEAN] If true the css margin of the element will be used, if false no margin will be used.
  4021. * [NUMBER] The margin will be used for all edges.
  4022. *
  4023. * @param duration The duration of the scroll animation, OR a jQuery animation configuration object.
  4024. * @param easing The animation easing.
  4025. * @param complete The animation complete callback.
  4026. * @returns {{
  4027. * position: {x: number, y: number},
  4028. * ratio: {x: number, y: number},
  4029. * max: {x: number, y: number},
  4030. * handleOffset: {x: number, y: number},
  4031. * handleLength: {x: number, y: number},
  4032. * handleLengthRatio: {x: number, y: number}, t
  4033. * rackLength: {x: number, y: number},
  4034. * isRTL: boolean,
  4035. * isRTLNormalized: boolean
  4036. * }}
  4037. */
  4038. _base.scroll = function (coordinates, duration, easing, complete) {
  4039. if (arguments.length === 0 || coordinates === undefined) {
  4040. var infoX = _scrollHorizontalInfo;
  4041. var infoY = _scrollVerticalInfo;
  4042. var normalizeInvert = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.i;
  4043. var normalizeNegate = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.n;
  4044. var scrollX = infoX._currentScroll;
  4045. var scrollXRatio = infoX._currentScrollRatio;
  4046. var maxScrollX = infoX._maxScroll;
  4047. scrollXRatio = normalizeInvert ? 1 - scrollXRatio : scrollXRatio;
  4048. scrollX = normalizeInvert ? maxScrollX - scrollX : scrollX;
  4049. scrollX *= normalizeNegate ? -1 : 1;
  4050. maxScrollX *= normalizeNegate ? -1 : 1;
  4051. return {
  4052. position : {
  4053. x : scrollX,
  4054. y : infoY._currentScroll
  4055. },
  4056. ratio : {
  4057. x : scrollXRatio,
  4058. y : infoY._currentScrollRatio
  4059. },
  4060. max : {
  4061. x : maxScrollX,
  4062. y : infoY._maxScroll
  4063. },
  4064. handleOffset : {
  4065. x : infoX._handleOffset,
  4066. y : infoY._handleOffset
  4067. },
  4068. handleLength : {
  4069. x : infoX._handleLength,
  4070. y : infoY._handleLength
  4071. },
  4072. handleLengthRatio : {
  4073. x : infoX._handleLengthRatio,
  4074. y : infoY._handleLengthRatio
  4075. },
  4076. trackLength : {
  4077. x : infoX._trackLength,
  4078. y : infoY._trackLength
  4079. },
  4080. snappedHandleOffset : {
  4081. x : infoX._snappedHandleOffset,
  4082. y : infoY._snappedHandleOffset
  4083. },
  4084. isRTL: _isRTL,
  4085. isRTLNormalized: _normalizeRTLCache
  4086. };
  4087. }
  4088. var normalizeRTL = _normalizeRTLCache;
  4089. var coordinatesXAxisProps = [_strX, _strLeft, 'l'];
  4090. var coordinatesYAxisProps = [_strY, _strTop, 't'];
  4091. var coordinatesOperators = ['+=', '-=', '*=', '/='];
  4092. var durationIsObject = type(duration) == TYPES.o;
  4093. var completeCallback = durationIsObject ? duration.complete : complete;
  4094. var i;
  4095. var finalScroll = { };
  4096. var specialEasing = {};
  4097. var doScrollLeft;
  4098. var doScrollTop;
  4099. var animationOptions;
  4100. var strEnd = 'end';
  4101. var strBegin = 'begin';
  4102. var strCenter = 'center';
  4103. var strNearest = 'nearest';
  4104. var strAlways = 'always';
  4105. var strNever = 'never';
  4106. var strIfNeeded = 'ifneeded';
  4107. var strLength = LEXICON.l;
  4108. var settingsAxis;
  4109. var settingsScroll;
  4110. var settingsBlock;
  4111. var settingsMargin;
  4112. var finalElement;
  4113. var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx'];
  4114. var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest];
  4115. var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded];
  4116. var coordinatesIsElementObj = coordinates.hasOwnProperty('el');
  4117. var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates;
  4118. var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false;
  4119. var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement);
  4120. var proxyCompleteCallback = type(completeCallback) != TYPES.f ? undefined : function() {
  4121. if(doScrollLeft)
  4122. refreshScrollbarHandleOffset(true);
  4123. if(doScrollTop)
  4124. refreshScrollbarHandleOffset(false);
  4125. completeCallback();
  4126. };
  4127. var checkSettingsStringValue = function (currValue, allowedValues) {
  4128. for (i = 0; i < allowedValues[strLength]; i++) {
  4129. if (currValue === allowedValues[i])
  4130. return true;
  4131. }
  4132. return false;
  4133. };
  4134. var getRawScroll = function (isX, coordinates) {
  4135. var coordinateProps = isX ? coordinatesXAxisProps : coordinatesYAxisProps;
  4136. coordinates = type(coordinates) == TYPES.s || type(coordinates) == TYPES.n ? [ coordinates, coordinates ] : coordinates;
  4137. if (type(coordinates) == TYPES.a)
  4138. return isX ? coordinates[0] : coordinates[1];
  4139. else if (type(coordinates) == TYPES.o) {
  4140. //decides RTL normalization "hack" with .n
  4141. //normalizeRTL = type(coordinates.n) == TYPES.b ? coordinates.n : normalizeRTL;
  4142. for (i = 0; i < coordinateProps[strLength]; i++)
  4143. if (coordinateProps[i] in coordinates)
  4144. return coordinates[coordinateProps[i]];
  4145. }
  4146. };
  4147. var getFinalScroll = function (isX, rawScroll) {
  4148. var isString = type(rawScroll) == TYPES.s;
  4149. if(isString)
  4150. _base.update(_strAuto + '+');
  4151. var operator;
  4152. var amount;
  4153. var scrollInfo = isX ? _scrollHorizontalInfo : _scrollVerticalInfo;
  4154. var currScroll = scrollInfo._currentScroll;
  4155. var maxScroll = scrollInfo._maxScroll;
  4156. var mult = ' * ';
  4157. var finalValue;
  4158. var isRTLisX = _isRTL && isX;
  4159. var normalizeShortcuts = isRTLisX && _rtlScrollBehavior.n && !normalizeRTL;
  4160. var strReplace = 'replace';
  4161. var evalFunc = eval;
  4162. var possibleOperator;
  4163. if (isString) {
  4164. //check operator
  4165. if (rawScroll[strLength] > 2) {
  4166. possibleOperator = rawScroll.substr(0, 2);
  4167. if(FRAMEWORK.inArray(possibleOperator, coordinatesOperators) > -1)
  4168. operator = possibleOperator;
  4169. }
  4170. //calculate units and shortcuts
  4171. rawScroll = operator ? rawScroll.substr(2) : rawScroll;
  4172. rawScroll = rawScroll
  4173. [strReplace](/min/g, 0) //'min' = 0%
  4174. [strReplace](/</g, 0) //'<' = 0%
  4175. [strReplace](/max/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'max' = 100%
  4176. [strReplace](/>/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'>' = 100%
  4177. [strReplace](/px/g, _strEmpty)
  4178. [strReplace](/%/g, mult + (maxScroll * (isRTLisX && _rtlScrollBehavior.n ? -1 : 1) / 100.0))
  4179. [strReplace](/vw/g, mult + _viewportSize.w)
  4180. [strReplace](/vh/g, mult + _viewportSize.h);
  4181. amount = parseToZeroOrNumber(isNaN(rawScroll) ? parseToZeroOrNumber(evalFunc(rawScroll), true).toFixed() : rawScroll);
  4182. }
  4183. else {
  4184. amount = rawScroll;
  4185. }
  4186. if (amount !== undefined && !isNaN(amount) && type(amount) == TYPES.n) {
  4187. var normalizeIsRTLisX = normalizeRTL && isRTLisX;
  4188. var operatorCurrScroll = currScroll * (normalizeIsRTLisX && _rtlScrollBehavior.n ? -1 : 1);
  4189. var invert = normalizeIsRTLisX && _rtlScrollBehavior.i;
  4190. var negate = normalizeIsRTLisX && _rtlScrollBehavior.n;
  4191. operatorCurrScroll = invert ? (maxScroll - operatorCurrScroll) : operatorCurrScroll;
  4192. switch (operator) {
  4193. case '+=':
  4194. finalValue = operatorCurrScroll + amount;
  4195. break;
  4196. case '-=':
  4197. finalValue = operatorCurrScroll - amount;
  4198. break;
  4199. case '*=':
  4200. finalValue = operatorCurrScroll * amount;
  4201. break;
  4202. case '/=':
  4203. finalValue = operatorCurrScroll / amount;
  4204. break;
  4205. default:
  4206. finalValue = amount;
  4207. break;
  4208. }
  4209. finalValue = invert ? maxScroll - finalValue : finalValue;
  4210. finalValue *= negate ? -1 : 1;
  4211. finalValue = isRTLisX && _rtlScrollBehavior.n ? MATH.min(0, MATH.max(maxScroll, finalValue)) : MATH.max(0, MATH.min(maxScroll, finalValue));
  4212. }
  4213. return finalValue === currScroll ? undefined : finalValue;
  4214. };
  4215. var getPerAxisValue = function (value, valueInternalType, defaultValue, allowedValues) {
  4216. var resultDefault = [ defaultValue, defaultValue ];
  4217. var valueType = type(value);
  4218. var valueArrLength;
  4219. var valueArrItem;
  4220. //value can be [ string, or array of two strings ]
  4221. if (valueType == valueInternalType) {
  4222. value = [value, value];
  4223. }
  4224. else if (valueType == TYPES.a) {
  4225. valueArrLength = value[strLength];
  4226. if (valueArrLength > 2 || valueArrLength < 1)
  4227. value = resultDefault;
  4228. else {
  4229. if (valueArrLength === 1)
  4230. value[1] = defaultValue;
  4231. for (i = 0; i < valueArrLength; i++) {
  4232. valueArrItem = value[i];
  4233. if (type(valueArrItem) != valueInternalType || !checkSettingsStringValue(valueArrItem, allowedValues)) {
  4234. value = resultDefault;
  4235. break;
  4236. }
  4237. }
  4238. }
  4239. }
  4240. else if (valueType == TYPES.o)
  4241. value = [ value[_strX]|| defaultValue, value[_strY] || defaultValue];
  4242. else
  4243. value = resultDefault;
  4244. return { x : value[0], y : value[1] };
  4245. };
  4246. var generateMargin = function (marginTopRightBottomLeftArray) {
  4247. var result = [ ];
  4248. var currValue;
  4249. var currValueType;
  4250. var valueDirections = [ _strTop, _strRight, _strBottom, _strLeft ];
  4251. for(i = 0; i < marginTopRightBottomLeftArray[strLength]; i++) {
  4252. if(i === valueDirections[strLength])
  4253. break;
  4254. currValue = marginTopRightBottomLeftArray[i];
  4255. currValueType = type(currValue);
  4256. if(currValueType == TYPES.b)
  4257. result.push(currValue ? parseToZeroOrNumber(finalElement.css(_strMarginMinus + valueDirections[i])) : 0);
  4258. else
  4259. result.push(currValueType == TYPES.n ? currValue : 0);
  4260. }
  4261. return result;
  4262. };
  4263. if (possibleElementIsJQuery || possibleElementIsHTMLElement) {
  4264. //get settings
  4265. var margin = coordinatesIsElementObj ? coordinates.margin : 0;
  4266. var axis = coordinatesIsElementObj ? coordinates.axis : 0;
  4267. var scroll = coordinatesIsElementObj ? coordinates.scroll : 0;
  4268. var block = coordinatesIsElementObj ? coordinates.block : 0;
  4269. var marginDefault = [ 0, 0, 0, 0 ];
  4270. var marginType = type(margin);
  4271. var marginLength;
  4272. finalElement = possibleElementIsJQuery ? possibleElement : FRAMEWORK(possibleElement);
  4273. if (finalElement[strLength] === 0)
  4274. return;
  4275. _base.update(_strAuto + '+');
  4276. //margin can be [ boolean, number, array of 2, array of 4, object ]
  4277. if (marginType == TYPES.n || marginType == TYPES.b)
  4278. margin = generateMargin([margin, margin, margin, margin]);
  4279. else if (marginType == TYPES.a) {
  4280. marginLength = margin[strLength];
  4281. if(marginLength === 2)
  4282. margin = generateMargin([margin[0], margin[1], margin[0], margin[1]]);
  4283. else if(marginLength >= 4)
  4284. margin = generateMargin(margin);
  4285. else
  4286. margin = marginDefault;
  4287. }
  4288. else if (marginType == TYPES.o)
  4289. margin = generateMargin([margin[_strTop], margin[_strRight], margin[_strBottom], margin[_strLeft]]);
  4290. else
  4291. margin = marginDefault;
  4292. //block = type(block) === TYPES.b ? block ? [ strNearest, strBegin ] : [ strNearest, strEnd ] : block;
  4293. settingsAxis = checkSettingsStringValue(axis, elementObjSettingsAxisValues) ? axis : 'xy';
  4294. settingsScroll = getPerAxisValue(scroll, TYPES.s, strAlways, elementObjSettingsScrollValues);
  4295. settingsBlock = getPerAxisValue(block, TYPES.s, strBegin, elementObjSettingsBlockValues);
  4296. settingsMargin = margin;
  4297. var viewportScroll = {
  4298. l: _scrollHorizontalInfo._currentScroll,
  4299. t: _scrollVerticalInfo._currentScroll
  4300. };
  4301. // use padding element instead of viewport element because padding element has never padding, margin or position applied.
  4302. var viewportOffset = _paddingElement.offset();
  4303. //get coordinates
  4304. var elementOffset = finalElement.offset();
  4305. var doNotScroll = {
  4306. x : settingsScroll.x == strNever || settingsAxis == _strY,
  4307. y : settingsScroll.y == strNever || settingsAxis == _strX
  4308. };
  4309. elementOffset[_strTop] -= settingsMargin[0];
  4310. elementOffset[_strLeft] -= settingsMargin[3];
  4311. var elementScrollCoordinates = {
  4312. x: MATH.round(elementOffset[_strLeft] - viewportOffset[_strLeft] + viewportScroll.l),
  4313. y: MATH.round(elementOffset[_strTop] - viewportOffset[_strTop] + viewportScroll.t)
  4314. };
  4315. if (_isRTL) {
  4316. if (!_rtlScrollBehavior.n && !_rtlScrollBehavior.i)
  4317. elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + viewportScroll.l);
  4318. if (_rtlScrollBehavior.n && normalizeRTL)
  4319. elementScrollCoordinates.x *= -1;
  4320. if (_rtlScrollBehavior.i && normalizeRTL)
  4321. elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + (_scrollHorizontalInfo._maxScroll - viewportScroll.l));
  4322. }
  4323. //measuring is required
  4324. if (settingsBlock.x != strBegin || settingsBlock.y != strBegin || settingsScroll.x == strIfNeeded || settingsScroll.y == strIfNeeded || _isRTL) {
  4325. var measuringElm = finalElement[0];
  4326. var rawElementSize = _supportTransform ? measuringElm.getBoundingClientRect() : {
  4327. width : measuringElm[LEXICON.oW],
  4328. height : measuringElm[LEXICON.oH]
  4329. };
  4330. var elementSize = {
  4331. w: rawElementSize[_strWidth] + settingsMargin[3] + settingsMargin[1],
  4332. h: rawElementSize[_strHeight] + settingsMargin[0] + settingsMargin[2]
  4333. };
  4334. var finalizeBlock = function(isX) {
  4335. var vars = getScrollbarVars(isX);
  4336. var wh = vars._w_h;
  4337. var lt = vars._left_top;
  4338. var xy = vars._x_y;
  4339. var blockIsEnd = settingsBlock[xy] == (isX ? _isRTL ? strBegin : strEnd : strEnd);
  4340. var blockIsCenter = settingsBlock[xy] == strCenter;
  4341. var blockIsNearest = settingsBlock[xy] == strNearest;
  4342. var scrollNever = settingsScroll[xy] == strNever;
  4343. var scrollIfNeeded = settingsScroll[xy] == strIfNeeded;
  4344. var vpSize = _viewportSize[wh];
  4345. var vpOffset = viewportOffset[lt];
  4346. var elSize = elementSize[wh];
  4347. var elOffset = elementOffset[lt];
  4348. var divide = blockIsCenter ? 2 : 1;
  4349. var elementCenterOffset = elOffset + (elSize / 2);
  4350. var viewportCenterOffset = vpOffset + (vpSize / 2);
  4351. var isInView =
  4352. elSize <= vpSize
  4353. && elOffset >= vpOffset
  4354. && elOffset + elSize <= vpOffset + vpSize;
  4355. if(scrollNever)
  4356. doNotScroll[xy] = true;
  4357. else if(!doNotScroll[xy]) {
  4358. if (blockIsNearest || scrollIfNeeded) {
  4359. doNotScroll[xy] = scrollIfNeeded ? isInView : false;
  4360. blockIsEnd = elSize < vpSize ? elementCenterOffset > viewportCenterOffset : elementCenterOffset < viewportCenterOffset;
  4361. }
  4362. elementScrollCoordinates[xy] -= blockIsEnd || blockIsCenter ? ((vpSize / divide) - (elSize / divide)) * (isX && _isRTL && normalizeRTL ? -1 : 1) : 0;
  4363. }
  4364. };
  4365. finalizeBlock(true);
  4366. finalizeBlock(false);
  4367. }
  4368. if (doNotScroll.y)
  4369. delete elementScrollCoordinates.y;
  4370. if (doNotScroll.x)
  4371. delete elementScrollCoordinates.x;
  4372. coordinates = elementScrollCoordinates;
  4373. }
  4374. finalScroll[_strScrollLeft] = getFinalScroll(true, getRawScroll(true, coordinates));
  4375. finalScroll[_strScrollTop] = getFinalScroll(false, getRawScroll(false, coordinates));
  4376. doScrollLeft = finalScroll[_strScrollLeft] !== undefined;
  4377. doScrollTop = finalScroll[_strScrollTop] !== undefined;
  4378. if ((doScrollLeft || doScrollTop) && (duration > 0 || durationIsObject)) {
  4379. if (durationIsObject) {
  4380. duration.complete = proxyCompleteCallback;
  4381. _viewportElement.animate(finalScroll, duration);
  4382. }
  4383. else {
  4384. animationOptions = {
  4385. duration: duration,
  4386. complete: proxyCompleteCallback
  4387. };
  4388. if (type(easing) == TYPES.a || FRAMEWORK.isPlainObject(easing)) {
  4389. specialEasing[_strScrollLeft] = easing[0] || easing.x;
  4390. specialEasing[_strScrollTop] = easing[1] || easing.y;
  4391. animationOptions.specialEasing = specialEasing;
  4392. }
  4393. else {
  4394. animationOptions.easing = easing;
  4395. }
  4396. _viewportElement.animate(finalScroll, animationOptions);
  4397. }
  4398. }
  4399. else {
  4400. if (doScrollLeft)
  4401. _viewportElement[_strScrollLeft](finalScroll[_strScrollLeft]);
  4402. if (doScrollTop)
  4403. _viewportElement[_strScrollTop](finalScroll[_strScrollTop]);
  4404. }
  4405. };
  4406. /**
  4407. * Stops all scroll animations.
  4408. * @returns {*} The current OverlayScrollbars instance (for chaining).
  4409. */
  4410. _base.scrollStop = function (param1, param2, param3) {
  4411. _viewportElement.stop(param1, param2, param3);
  4412. return _base;
  4413. };
  4414. /**
  4415. * Returns all relevant elements.
  4416. * @param elementName The name of the element which shall be returned.
  4417. * @returns {{target: *, host: *, padding: *, viewport: *, content: *, scrollbarHorizontal: {scrollbar: *, track: *, handle: *}, scrollbarVertical: {scrollbar: *, track: *, handle: *}, scrollbarCorner: *} | *}
  4418. */
  4419. _base.getElements = function (elementName) {
  4420. var obj = {
  4421. target: _targetElementNative,
  4422. host: _hostElementNative,
  4423. padding: _paddingElementNative,
  4424. viewport: _viewportElementNative,
  4425. content: _contentElementNative,
  4426. scrollbarHorizontal: {
  4427. scrollbar: _scrollbarHorizontalElement[0],
  4428. track: _scrollbarHorizontalTrackElement[0],
  4429. handle: _scrollbarHorizontalHandleElement[0]
  4430. },
  4431. scrollbarVertical: {
  4432. scrollbar: _scrollbarVerticalElement[0],
  4433. track: _scrollbarVerticalTrackElement[0],
  4434. handle: _scrollbarVerticalHandleElement[0]
  4435. },
  4436. scrollbarCorner: _scrollbarCornerElement[0]
  4437. };
  4438. return type(elementName) == TYPES.s ? getObjectPropVal(obj, elementName) : obj;
  4439. };
  4440. /**
  4441. * Returns a object which describes the current state of this instance.
  4442. * @param stateProperty A specific property from the state object which shall be returned.
  4443. * @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *}
  4444. */
  4445. _base.getState = function (stateProperty) {
  4446. var prepare = function (obj) {
  4447. if (!FRAMEWORK.isPlainObject(obj))
  4448. return obj;
  4449. var extended = extendDeep({}, obj);
  4450. var changePropertyName = function (from, to) {
  4451. if (extended.hasOwnProperty(from)) {
  4452. extended[to] = extended[from];
  4453. delete extended[from];
  4454. }
  4455. };
  4456. changePropertyName('w', _strWidth); //change w to width
  4457. changePropertyName('h', _strHeight); //change h to height
  4458. delete extended.c; //delete c (the 'changed' prop)
  4459. return extended;
  4460. };
  4461. var obj = {
  4462. sleeping: prepare(_isSleeping) || false,
  4463. autoUpdate: prepare(!_mutationObserversConnected),
  4464. widthAuto: prepare(_widthAutoCache),
  4465. heightAuto: prepare(_heightAutoCache),
  4466. padding: prepare(_cssPaddingCache),
  4467. overflowAmount: prepare(_overflowAmountCache),
  4468. hideOverflow: prepare(_hideOverflowCache),
  4469. hasOverflow: prepare(_hasOverflowCache),
  4470. contentScrollSize: prepare(_contentScrollSizeCache),
  4471. viewportSize: prepare(_viewportSize),
  4472. hostSize: prepare(_hostSizeCache),
  4473. documentMixed : prepare(_documentMixed)
  4474. };
  4475. return type(stateProperty) == TYPES.s ? getObjectPropVal(obj, stateProperty) : obj;
  4476. };
  4477. /**
  4478. * Gets all or specific extension instance.
  4479. * @param extName The name of the extension from which the instance shall be got.
  4480. * @returns {{}} The instance of the extension with the given name or undefined if the instance couldn't be found.
  4481. */
  4482. _base.ext = function(extName) {
  4483. var result;
  4484. var privateMethods = _extensionsPrivateMethods.split(' ');
  4485. var i = 0;
  4486. if(type(extName) == TYPES.s) {
  4487. if(_extensions.hasOwnProperty(extName)) {
  4488. result = extendDeep({}, _extensions[extName]);
  4489. for (; i < privateMethods.length; i++)
  4490. delete result[privateMethods[i]];
  4491. }
  4492. }
  4493. else {
  4494. result = { };
  4495. for(i in _extensions)
  4496. result[i] = extendDeep({ }, _base.ext(i));
  4497. }
  4498. return result;
  4499. };
  4500. /**
  4501. * Adds a extension to this instance.
  4502. * @param extName The name of the extension which shall be added.
  4503. * @param extensionOptions The extension options which shall be used.
  4504. * @returns {{}} The instance of the added extension or undefined if the extension couldn't be added properly.
  4505. */
  4506. _base.addExt = function(extName, extensionOptions) {
  4507. var registeredExtensionObj = window[PLUGINNAME].extension(extName);
  4508. var instance;
  4509. var instanceAdded;
  4510. var instanceContract;
  4511. var contractResult;
  4512. var contractFulfilled = true;
  4513. if(registeredExtensionObj) {
  4514. if(!_extensions.hasOwnProperty(extName)) {
  4515. instance = registeredExtensionObj.extensionFactory.call(_base,
  4516. extendDeep({ }, registeredExtensionObj.defaultOptions),
  4517. FRAMEWORK,
  4518. COMPATIBILITY);
  4519. if (instance) {
  4520. instanceContract = instance.contract;
  4521. if (type(instanceContract) == TYPES.f) {
  4522. contractResult = instanceContract(window);
  4523. contractFulfilled = type(contractResult) == TYPES.b ? contractResult : contractFulfilled;
  4524. }
  4525. if(contractFulfilled) {
  4526. _extensions[extName] = instance;
  4527. instanceAdded = instance.added;
  4528. if(type(instanceAdded) == TYPES.f)
  4529. instanceAdded(extensionOptions);
  4530. return _base.ext(extName);
  4531. }
  4532. }
  4533. }
  4534. else
  4535. return _base.ext(extName);
  4536. }
  4537. else
  4538. console.warn("A extension with the name \"" + extName + "\" isn't registered.");
  4539. };
  4540. /**
  4541. * Removes a extension from this instance.
  4542. * @param extName The name of the extension which shall be removed.
  4543. * @returns {boolean} True if the extension was removed, false otherwise e.g. if the extension wasn't added before.
  4544. */
  4545. _base.removeExt = function(extName) {
  4546. var instance = _extensions[extName];
  4547. var instanceRemoved;
  4548. if(instance) {
  4549. delete _extensions[extName];
  4550. instanceRemoved = instance.removed;
  4551. if(type(instanceRemoved) == TYPES.f)
  4552. instanceRemoved();
  4553. return true;
  4554. }
  4555. return false;
  4556. };
  4557. /**
  4558. * Constructs the plugin.
  4559. * @param targetElement The element to which the plugin shall be applied.
  4560. * @param options The initial options of the plugin.
  4561. * @param extensions The extension(s) which shall be added right after the initialization.
  4562. * @returns {boolean} True if the plugin was successfully initialized, false otherwise.
  4563. */
  4564. function construct(targetElement, options, extensions) {
  4565. _defaultOptions = globals.defaultOptions;
  4566. _nativeScrollbarStyling = globals.nativeScrollbarStyling;
  4567. _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
  4568. _nativeScrollbarIsOverlaid = extendDeep({}, globals.nativeScrollbarIsOverlaid);
  4569. _overlayScrollbarDummySize = extendDeep({}, globals.overlayScrollbarDummySize);
  4570. _rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior);
  4571. //parse & set options but don't update
  4572. setOptions(extendDeep({ }, _defaultOptions, _pluginsOptions._validate(options, _pluginsOptions._template, true)));
  4573. //check if the plugin hasn't to be initialized
  4574. if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.x && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) {
  4575. dispatchCallback("onInitializationWithdrawn");
  4576. return false;
  4577. }
  4578. _cssCalc = globals.cssCalc;
  4579. _msieVersion = globals.msie;
  4580. _autoUpdateRecommended = globals.autoUpdateRecommended;
  4581. _supportTransition = globals.supportTransition;
  4582. _supportTransform = globals.supportTransform;
  4583. _supportPassiveEvents = globals.supportPassiveEvents;
  4584. _supportResizeObserver = globals.supportResizeObserver;
  4585. _supportMutationObserver = globals.supportMutationObserver;
  4586. _restrictedMeasuring = globals.restrictedMeasuring;
  4587. _documentElement = FRAMEWORK(targetElement.ownerDocument);
  4588. _documentElementNative = _documentElement[0];
  4589. _windowElement = FRAMEWORK(_documentElementNative.defaultView || _documentElementNative.parentWindow);
  4590. _windowElementNative = _windowElement[0];
  4591. _htmlElement = findFirst(_documentElement, 'html');
  4592. _bodyElement = findFirst(_htmlElement, 'body');
  4593. _targetElement = FRAMEWORK(targetElement);
  4594. _targetElementNative = _targetElement[0];
  4595. _isTextarea = _targetElement.is('textarea');
  4596. _isBody = _targetElement.is('body');
  4597. _documentMixed = _documentElementNative !== document;
  4598. var initBodyScroll;
  4599. if (_isBody) {
  4600. initBodyScroll = {};
  4601. initBodyScroll.l = MATH.max(_targetElement[_strScrollLeft](), _htmlElement[_strScrollLeft](), _windowElement[_strScrollLeft]());
  4602. initBodyScroll.t = MATH.max(_targetElement[_strScrollTop](), _htmlElement[_strScrollTop](), _windowElement[_strScrollTop]());
  4603. }
  4604. //build OverlayScrollbars DOM and Events
  4605. setupStructureDOM();
  4606. setupStructureEvents();
  4607. //build Scrollbars DOM and Events
  4608. setupScrollbarsDOM();
  4609. setupScrollbarEvents(true);
  4610. setupScrollbarEvents(false);
  4611. //build Scrollbar Corner DOM and Events
  4612. setupScrollbarCornerDOM();
  4613. setupScrollbarCornerEvents();
  4614. //create mutation observers
  4615. createMutationObservers();
  4616. if(_isBody) {
  4617. //apply the body scroll to handle it right in the update method
  4618. _viewportElement[_strScrollLeft](initBodyScroll.l)[_strScrollTop](initBodyScroll.t);
  4619. //set the focus on the viewport element so you dont have to click on the page to use keyboard keys (up / down / space) for scrolling
  4620. if(document.activeElement == targetElement && _viewportElementNative.focus) {
  4621. //set a tabindex to make the viewportElement focusable
  4622. _viewportElement.attr('tabindex', '-1');
  4623. _viewportElementNative.focus();
  4624. /* the tabindex has to be removed due to;
  4625. * 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
  4626. * https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
  4627. */
  4628. _viewportElement.one(_strMouseTouchDownEvent, function() {
  4629. _viewportElement.removeAttr('tabindex');
  4630. });
  4631. }
  4632. }
  4633. //build resize observer for the host element
  4634. addResizeObserver(_sizeObserverElement, hostOnResized);
  4635. //update for the first time
  4636. hostOnResized(); //initialize cache for host size
  4637. _base.update(_strAuto); //initialize cache for content
  4638. //the plugin is initialized now!
  4639. _initialized = true;
  4640. dispatchCallback("onInitialized");
  4641. //call all callbacks which would fire before the initialized was complete
  4642. FRAMEWORK.each(_callbacksInitQeueue, function(index, value) { dispatchCallback(value.n, value.a); });
  4643. _callbacksInitQeueue = [ ];
  4644. //add extensions
  4645. if(type(extensions) == TYPES.s)
  4646. extensions = [ extensions ];
  4647. if(COMPATIBILITY.isA(extensions))
  4648. FRAMEWORK.each(extensions, function (index, value) {_base.addExt(value); });
  4649. else if(FRAMEWORK.isPlainObject(extensions))
  4650. FRAMEWORK.each(extensions, function (key, value) { _base.addExt(key, value); });
  4651. //add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions)
  4652. setTimeout(function () {
  4653. if (_supportTransition && !_destroyed)
  4654. addClass(_hostElement, _classNameHostTransition);
  4655. }, 333);
  4656. return _initialized;
  4657. }
  4658. if (construct(pluginTargetElement, options, extensions)) {
  4659. INSTANCES(pluginTargetElement, _base);
  4660. return _base;
  4661. }
  4662. _base = undefined;
  4663. }
  4664. /**
  4665. * Initializes a new OverlayScrollbarsInstance object or changes options if already initialized or returns the current instance.
  4666. * @param pluginTargetElements The elements to which the Plugin shall be initialized.
  4667. * @param options The custom options with which the plugin shall be initialized.
  4668. * @param extensions The extension(s) which shall be added right after initialization.
  4669. * @returns {*}
  4670. */
  4671. window[PLUGINNAME] = function(pluginTargetElements, options, extensions) {
  4672. if(arguments[LEXICON.l] === 0)
  4673. return this;
  4674. var arr = [ ];
  4675. var optsIsPlainObj = FRAMEWORK.isPlainObject(options);
  4676. var inst;
  4677. var result;
  4678. //pluginTargetElements is null or undefined
  4679. if(!pluginTargetElements)
  4680. return optsIsPlainObj || !options ? result : arr;
  4681. /*
  4682. pluginTargetElements will be converted to:
  4683. 1. A jQueryElement Array
  4684. 2. A HTMLElement Array
  4685. 3. A Array with a single HTML Element
  4686. so pluginTargetElements is always a array.
  4687. */
  4688. pluginTargetElements = pluginTargetElements[LEXICON.l] != undefined ? pluginTargetElements : [ pluginTargetElements[0] || pluginTargetElements ];
  4689. initOverlayScrollbarsStatics();
  4690. if(pluginTargetElements[LEXICON.l] > 0) {
  4691. if(optsIsPlainObj) {
  4692. FRAMEWORK.each(pluginTargetElements, function (i, v) {
  4693. inst = v;
  4694. if(inst !== undefined)
  4695. arr.push(OverlayScrollbarsInstance(inst, options, extensions, _pluginsGlobals, _pluginsAutoUpdateLoop));
  4696. });
  4697. }
  4698. else {
  4699. FRAMEWORK.each(pluginTargetElements, function(i, v) {
  4700. inst = INSTANCES(v);
  4701. if((options === '!' && inst instanceof window[PLUGINNAME]) || (COMPATIBILITY.type(options) == TYPES.f && options(v, inst)))
  4702. arr.push(inst);
  4703. else if(options === undefined)
  4704. arr.push(inst);
  4705. });
  4706. }
  4707. result = arr[LEXICON.l] === 1 ? arr[0] : arr;
  4708. }
  4709. return result;
  4710. };
  4711. /**
  4712. * Returns a object which contains global information about the plugin and each instance of it.
  4713. * The returned object is just a copy, that means that changes to the returned object won't have any effect to the original object.
  4714. */
  4715. window[PLUGINNAME].globals = function () {
  4716. initOverlayScrollbarsStatics();
  4717. var globals = FRAMEWORK.extend(true, { }, _pluginsGlobals);
  4718. delete globals['msie'];
  4719. return globals;
  4720. };
  4721. /**
  4722. * Gets or Sets the default options for each new plugin initialization.
  4723. * @param newDefaultOptions The object with which the default options shall be extended.
  4724. */
  4725. window[PLUGINNAME].defaultOptions = function(newDefaultOptions) {
  4726. initOverlayScrollbarsStatics();
  4727. var currDefaultOptions = _pluginsGlobals.defaultOptions;
  4728. if(newDefaultOptions === undefined)
  4729. return FRAMEWORK.extend(true, { }, currDefaultOptions);
  4730. //set the new default options
  4731. _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, { }, currDefaultOptions , _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true));
  4732. };
  4733. /**
  4734. * Registers, Unregisters or returns a extension.
  4735. * Register: Pass the name and the extension. (defaultOptions is optional)
  4736. * Unregister: Pass the name and anything except a function as extension parameter.
  4737. * Get extension: Pass the name of the extension which shall be got.
  4738. * Get all extensions: Pass no arguments.
  4739. * @param extensionName The name of the extension which shall be registered, unregistered or returned.
  4740. * @param extension A function which generates the instance of the extension or anything other to remove a already registered extension.
  4741. * @param defaultOptions The default options which shall be used for the registered extension.
  4742. */
  4743. window[PLUGINNAME].extension = function(extensionName, extension, defaultOptions) {
  4744. var extNameTypeString = COMPATIBILITY.type(extensionName) == TYPES.s;
  4745. var argLen = arguments[LEXICON.l];
  4746. var i = 0;
  4747. if(argLen < 1 || !extNameTypeString) {
  4748. //return a copy of all extension objects
  4749. return FRAMEWORK.extend(true, { length : _pluginsExtensions[LEXICON.l] }, _pluginsExtensions);
  4750. }
  4751. else if(extNameTypeString) {
  4752. if(COMPATIBILITY.type(extension) == TYPES.f) {
  4753. //register extension
  4754. _pluginsExtensions.push({
  4755. name : extensionName,
  4756. extensionFactory : extension,
  4757. defaultOptions : defaultOptions
  4758. });
  4759. }
  4760. else {
  4761. for(; i < _pluginsExtensions[LEXICON.l]; i++) {
  4762. if (_pluginsExtensions[i].name === extensionName) {
  4763. if(argLen > 1)
  4764. _pluginsExtensions.splice(i, 1); //remove extension
  4765. else
  4766. return FRAMEWORK.extend(true, { }, _pluginsExtensions[i]); //return extension with the given name
  4767. }
  4768. }
  4769. }
  4770. }
  4771. };
  4772. return window[PLUGINNAME];
  4773. })();
  4774. if(JQUERY && JQUERY.fn) {
  4775. /**
  4776. * The jQuery initialization interface.
  4777. * @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.
  4778. * @param extensions The extension(s) which shall be added right after initialization.
  4779. * @returns {*} After initialization it returns the jQuery element array, else it returns the instance(s) of the elements which are selected.
  4780. */
  4781. JQUERY.fn.overlayScrollbars = function (options, extensions) {
  4782. var _elements = this;
  4783. if(JQUERY.isPlainObject(options)) {
  4784. JQUERY.each(_elements, function() { PLUGIN(this, options, extensions); });
  4785. return _elements;
  4786. }
  4787. else
  4788. return PLUGIN(_elements, options);
  4789. };
  4790. }
  4791. return PLUGIN;
  4792. }
  4793. ));