OverlayScrollbars.js 339 KB

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