OverlayScrollbars.js 338 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372
  1. /*!
  2. * OverlayScrollbars
  3. * https://github.com/KingSora/OverlayScrollbars
  4. *
  5. * Version: 1.7.1
  6. *
  7. * Copyright KingSora.
  8. * https://github.com/KingSora
  9. *
  10. * Released under the MIT license.
  11. * Date: 22.05.2019
  12. */
  13. (function (global, factory) {
  14. if (typeof define === 'function' && define.amd)
  15. define(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. })(),
  1515. overlayScrollbarDummySize : { x: 30, y: 30 },
  1516. msie : (function() {
  1517. var ua = window.navigator.userAgent;
  1518. var strIndexOf = 'indexOf';
  1519. var strSubString = 'substring';
  1520. var msie = ua[strIndexOf]('MSIE ');
  1521. var trident = ua[strIndexOf]('Trident/');
  1522. var edge = ua[strIndexOf]('Edge/');
  1523. var rv = ua[strIndexOf]('rv:');
  1524. var result;
  1525. var parseIntFunc = parseInt;
  1526. // IE 10 or older => return version number
  1527. if (msie > 0)
  1528. result = parseIntFunc(ua[strSubString](msie + 5, ua[strIndexOf]('.', msie)), 10);
  1529. // IE 11 => return version number
  1530. else if (trident > 0)
  1531. result = parseIntFunc(ua[strSubString](rv + 3, ua[strIndexOf]('.', rv)), 10);
  1532. // Edge (IE 12+) => return version number
  1533. else if (edge > 0)
  1534. result = parseIntFunc(ua[strSubString](edge + 5, ua[strIndexOf]('.', edge)), 10);
  1535. // other browser
  1536. return result;
  1537. })(),
  1538. cssCalc : (function() {
  1539. var dummyStyle = document.createElement('div')[LEXICON.s];
  1540. var strCalc = 'calc';
  1541. var i = -1;
  1542. var prop;
  1543. for(; i < VENDORS._cssPrefixes[LEXICON.l]; i++) {
  1544. prop = i < 0 ? strCalc : VENDORS._cssPrefixes[i] + strCalc;
  1545. dummyStyle.cssText = 'width:' + prop + '(1px);';
  1546. if (dummyStyle[LEXICON.l])
  1547. return prop;
  1548. }
  1549. return null;
  1550. })(),
  1551. restrictedMeasuring : (function() {
  1552. //https://bugzilla.mozilla.org/show_bug.cgi?id=1439305
  1553. scrollbarDummyElement.css(strOverflow, strHidden);
  1554. var scrollSize = {
  1555. w : scrollbarDummyElement0[LEXICON.sW],
  1556. h : scrollbarDummyElement0[LEXICON.sH]
  1557. };
  1558. scrollbarDummyElement.css(strOverflow, 'visible');
  1559. var scrollSize2 = {
  1560. w : scrollbarDummyElement0[LEXICON.sW],
  1561. h : scrollbarDummyElement0[LEXICON.sH]
  1562. };
  1563. return (scrollSize.w - scrollSize2.w) !== 0 || (scrollSize.h - scrollSize2.h) !== 0;
  1564. })(),
  1565. rtlScrollBehavior : (function() {
  1566. scrollbarDummyElement.css({ 'overflow-y' : strHidden, 'overflow-x' : strScroll, 'direction' : 'rtl' }).scrollLeft(0);
  1567. var dummyContainerOffset = scrollbarDummyElement.offset();
  1568. var dummyContainerChildOffset = dummyContainerChild.offset();
  1569. scrollbarDummyElement.scrollLeft(999);
  1570. var dummyContainerScrollOffsetAfterScroll = dummyContainerChild.offset();
  1571. return {
  1572. //origin direction = determines if the zero scroll position is on the left or right side
  1573. //'i' means 'invert' (i === true means that the axis must be inverted to be correct)
  1574. //true = on the left side
  1575. //false = on the right side
  1576. i : dummyContainerOffset.left === dummyContainerChildOffset.left,
  1577. //negative = determines if the maximum scroll is positive or negative
  1578. //'n' means 'negate' (n === true means that the axis must be negated to be correct)
  1579. //true = negative
  1580. //false = positive
  1581. n : dummyContainerChildOffset.left - dummyContainerScrollOffsetAfterScroll.left === 0
  1582. };
  1583. })(),
  1584. supportTransform : VENDORS._cssProperty('transform') !== null,
  1585. supportTransition : VENDORS._cssProperty('transition') !== null,
  1586. supportPassiveEvents : (function() {
  1587. var supportsPassive = false;
  1588. try {
  1589. window.addEventListener('test', null, Object.defineProperty({ }, 'passive', {
  1590. get: function() {
  1591. supportsPassive = true;
  1592. }
  1593. }));
  1594. } catch (e) { }
  1595. return supportsPassive;
  1596. })(),
  1597. supportResizeObserver : !!COMPATIBILITY.rO(),
  1598. supportMutationObserver : !!COMPATIBILITY.mO()
  1599. });
  1600. scrollbarDummyElement.removeAttr(LEXICON.s).remove();
  1601. //Catch zoom event:
  1602. (function () {
  1603. if(nativeScrollbarIsOverlaid.x && nativeScrollbarIsOverlaid.y)
  1604. return;
  1605. var abs = MATH.abs;
  1606. var windowWidth = COMPATIBILITY.wW();
  1607. var windowHeight = COMPATIBILITY.wH();
  1608. var windowDpr = getWindowDPR();
  1609. var onResize = function() {
  1610. if(INSTANCES().length > 0) {
  1611. var newW = COMPATIBILITY.wW();
  1612. var newH = COMPATIBILITY.wH();
  1613. var deltaW = newW - windowWidth;
  1614. var deltaH = newH - windowHeight;
  1615. if (deltaW === 0 && deltaH === 0)
  1616. return;
  1617. var deltaWRatio = MATH.round(newW / (windowWidth / 100.0));
  1618. var deltaHRatio = MATH.round(newH / (windowHeight / 100.0));
  1619. var absDeltaW = abs(deltaW);
  1620. var absDeltaH = abs(deltaH);
  1621. var absDeltaWRatio = abs(deltaWRatio);
  1622. var absDeltaHRatio = abs(deltaHRatio);
  1623. var newDPR = getWindowDPR();
  1624. var deltaIsBigger = absDeltaW > 2 && absDeltaH > 2;
  1625. var difference = !differenceIsBiggerThanOne(absDeltaWRatio, absDeltaHRatio);
  1626. var dprChanged = newDPR !== windowDpr && windowDpr > 0;
  1627. var isZoom = deltaIsBigger && difference && dprChanged;
  1628. var oldScrollbarSize = _base.nativeScrollbarSize;
  1629. var newScrollbarSize;
  1630. if (isZoom) {
  1631. bodyElement.append(scrollbarDummyElement);
  1632. newScrollbarSize = _base.nativeScrollbarSize = calcNativeScrollbarSize(scrollbarDummyElement[0]);
  1633. scrollbarDummyElement.remove();
  1634. if(oldScrollbarSize.x !== newScrollbarSize.x || oldScrollbarSize.y !== newScrollbarSize.y) {
  1635. FRAMEWORK.each(INSTANCES(), function () {
  1636. if(INSTANCES(this))
  1637. INSTANCES(this).update('zoom');
  1638. });
  1639. }
  1640. }
  1641. windowWidth = newW;
  1642. windowHeight = newH;
  1643. windowDpr = newDPR;
  1644. }
  1645. };
  1646. function differenceIsBiggerThanOne(valOne, valTwo) {
  1647. var absValOne = abs(valOne);
  1648. var absValTwo = abs(valTwo);
  1649. return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
  1650. }
  1651. function getWindowDPR() {
  1652. var dDPI = window.screen.deviceXDPI || 0;
  1653. var sDPI = window.screen.logicalXDPI || 1;
  1654. return window.devicePixelRatio || (dDPI / sDPI);
  1655. }
  1656. FRAMEWORK(window).on('resize', onResize);
  1657. })();
  1658. function calcNativeScrollbarSize(measureElement) {
  1659. return {
  1660. x: measureElement[LEXICON.oH] - measureElement[LEXICON.cH],
  1661. y: measureElement[LEXICON.oW] - measureElement[LEXICON.cW]
  1662. };
  1663. }
  1664. }
  1665. /**
  1666. * 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.
  1667. * @constructor
  1668. */
  1669. function OverlayScrollbarsAutoUpdateLoop(globals) {
  1670. var _base = this;
  1671. var _strAutoUpdate = 'autoUpdate';
  1672. var _strAutoUpdateInterval = _strAutoUpdate + 'Interval';
  1673. var _strLength = LEXICON.l;
  1674. var _loopingInstances = [ ];
  1675. var _loopingInstancesIntervalCache = [ ];
  1676. var _loopIsActive = false;
  1677. var _loopIntervalDefault = 33;
  1678. var _loopInterval = _loopIntervalDefault;
  1679. var _loopTimeOld = COMPATIBILITY.now();
  1680. var _loopID;
  1681. /**
  1682. * The auto update loop which will run every 50 milliseconds or less if the update interval of a instance is lower than 50 milliseconds.
  1683. */
  1684. var loop = function() {
  1685. if(_loopingInstances[_strLength] > 0 && _loopIsActive) {
  1686. _loopID = COMPATIBILITY.rAF()(function () {
  1687. loop();
  1688. });
  1689. var timeNew = COMPATIBILITY.now();
  1690. var timeDelta = timeNew - _loopTimeOld;
  1691. var lowestInterval;
  1692. var instance;
  1693. var instanceOptions;
  1694. var instanceAutoUpdateAllowed;
  1695. var instanceAutoUpdateInterval;
  1696. var now;
  1697. if (timeDelta > _loopInterval) {
  1698. _loopTimeOld = timeNew - (timeDelta % _loopInterval);
  1699. lowestInterval = _loopIntervalDefault;
  1700. for(var i = 0; i < _loopingInstances[_strLength]; i++) {
  1701. instance = _loopingInstances[i];
  1702. if (instance !== undefined) {
  1703. instanceOptions = instance.options();
  1704. instanceAutoUpdateAllowed = instanceOptions[_strAutoUpdate];
  1705. instanceAutoUpdateInterval = MATH.max(1, instanceOptions[_strAutoUpdateInterval]);
  1706. now = COMPATIBILITY.now();
  1707. if ((instanceAutoUpdateAllowed === true || instanceAutoUpdateAllowed === null) && (now - _loopingInstancesIntervalCache[i]) > instanceAutoUpdateInterval) {
  1708. instance.update('auto');
  1709. _loopingInstancesIntervalCache[i] = new Date(now += instanceAutoUpdateInterval);
  1710. }
  1711. lowestInterval = MATH.max(1, MATH.min(lowestInterval, instanceAutoUpdateInterval));
  1712. }
  1713. }
  1714. _loopInterval = lowestInterval;
  1715. }
  1716. } else {
  1717. _loopInterval = _loopIntervalDefault;
  1718. }
  1719. };
  1720. /**
  1721. * Add OverlayScrollbars instance to the auto update loop. Only successful if the instance isn't already added.
  1722. * @param instance The instance which shall be updated in a loop automatically.
  1723. */
  1724. _base.add = function(instance) {
  1725. if(FRAMEWORK.inArray(instance, _loopingInstances) === -1) {
  1726. _loopingInstances.push(instance);
  1727. _loopingInstancesIntervalCache.push(COMPATIBILITY.now());
  1728. if (_loopingInstances[_strLength] > 0 && !_loopIsActive) {
  1729. _loopIsActive = true;
  1730. globals.autoUpdateLoop = _loopIsActive;
  1731. loop();
  1732. }
  1733. }
  1734. };
  1735. /**
  1736. * Remove OverlayScrollbars instance from the auto update loop. Only successful if the instance was added before.
  1737. * @param instance The instance which shall be updated in a loop automatically.
  1738. */
  1739. _base.remove = function(instance) {
  1740. var index = FRAMEWORK.inArray(instance, _loopingInstances);
  1741. if(index > -1) {
  1742. //remove from loopingInstances list
  1743. _loopingInstancesIntervalCache.splice(index, 1);
  1744. _loopingInstances.splice(index, 1);
  1745. //correct update loop behavior
  1746. if (_loopingInstances[_strLength] === 0 && _loopIsActive) {
  1747. _loopIsActive = false;
  1748. globals.autoUpdateLoop = _loopIsActive;
  1749. if(_loopID !== undefined) {
  1750. COMPATIBILITY.cAF()(_loopID);
  1751. _loopID = -1;
  1752. }
  1753. }
  1754. }
  1755. };
  1756. }
  1757. /**
  1758. * A object which manages the scrollbars visibility of the target element.
  1759. * @param pluginTargetElement The element from which the scrollbars shall be hidden.
  1760. * @param options The custom options.
  1761. * @param extensions The custom extensions.
  1762. * @param globals
  1763. * @param autoUpdateLoop
  1764. * @returns {*}
  1765. * @constructor
  1766. */
  1767. function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) {
  1768. //if passed element is no HTML element: skip and return
  1769. if(!isHTMLElement(pluginTargetElement))
  1770. return;
  1771. //if passed element is already initialized: set passed options if there are any and return its instance
  1772. if(INSTANCES(pluginTargetElement)) {
  1773. var inst = INSTANCES(pluginTargetElement);
  1774. inst.options(options);
  1775. return inst;
  1776. }
  1777. //make correct instanceof
  1778. var _base = new window[PLUGINNAME]();
  1779. var _frameworkProto = FRAMEWORK[LEXICON.p];
  1780. //globals:
  1781. var _nativeScrollbarIsOverlaid;
  1782. var _overlayScrollbarDummySize;
  1783. var _rtlScrollBehavior;
  1784. var _autoUpdateRecommended;
  1785. var _msieVersion;
  1786. var _nativeScrollbarStyling;
  1787. var _cssCalc;
  1788. var _nativeScrollbarSize;
  1789. var _supportTransition;
  1790. var _supportTransform;
  1791. var _supportPassiveEvents;
  1792. var _supportResizeObserver;
  1793. var _supportMutationObserver;
  1794. var _restrictedMeasuring;
  1795. //general readonly:
  1796. var _initialized;
  1797. var _destroyed;
  1798. var _isTextarea;
  1799. var _isBody;
  1800. var _documentMixed;
  1801. var _isTextareaHostGenerated;
  1802. //general:
  1803. var _isBorderBox;
  1804. var _sizeAutoObserverAdded;
  1805. var _paddingX;
  1806. var _paddingY;
  1807. var _borderX;
  1808. var _borderY;
  1809. var _marginX;
  1810. var _marginY;
  1811. var _isRTL;
  1812. var _isSleeping;
  1813. var _contentBorderSize = { };
  1814. var _scrollHorizontalInfo = { };
  1815. var _scrollVerticalInfo = { };
  1816. var _viewportSize = { };
  1817. var _nativeScrollbarMinSize = { };
  1818. //naming:
  1819. var _strMinusHidden = '-hidden';
  1820. var _strMarginMinus = 'margin-';
  1821. var _strPaddingMinus = 'padding-';
  1822. var _strBorderMinus = 'border-';
  1823. var _strTop = 'top';
  1824. var _strRight = 'right';
  1825. var _strBottom = 'bottom';
  1826. var _strLeft = 'left';
  1827. var _strMinMinus = 'min-';
  1828. var _strMaxMinus = 'max-';
  1829. var _strWidth = 'width';
  1830. var _strHeight = 'height';
  1831. var _strFloat = 'float';
  1832. var _strEmpty = '';
  1833. var _strAuto = 'auto';
  1834. var _strScroll = 'scroll';
  1835. var _strHundredPercent = '100%';
  1836. var _strX = 'x';
  1837. var _strY = 'y';
  1838. var _strDot = '.';
  1839. var _strSpace = ' ';
  1840. var _strScrollbar = 'scrollbar';
  1841. var _strMinusHorizontal = '-horizontal';
  1842. var _strMinusVertical = '-vertical';
  1843. var _strScrollLeft = _strScroll + 'Left';
  1844. var _strScrollTop = _strScroll + 'Top';
  1845. var _strMouseTouchDownEvent = 'mousedown touchstart';
  1846. var _strMouseTouchUpEvent = 'mouseup touchend touchcancel';
  1847. var _strMouseTouchMoveEvent = 'mousemove touchmove';
  1848. var _strMouseTouchEnter = 'mouseenter';
  1849. var _strMouseTouchLeave = 'mouseleave';
  1850. var _strKeyDownEvent = 'keydown';
  1851. var _strKeyUpEvent = 'keyup';
  1852. var _strSelectStartEvent = 'selectstart';
  1853. var _strTransitionEndEvent = 'transitionend webkitTransitionEnd oTransitionEnd';
  1854. var _strResizeObserverProperty = '__overlayScrollbarsRO__';
  1855. //class names:
  1856. var _cassNamesPrefix = 'os-';
  1857. var _classNameHTMLElement = _cassNamesPrefix + 'html';
  1858. var _classNameHostElement = _cassNamesPrefix + 'host';
  1859. var _classNameHostTextareaElement = _classNameHostElement + '-textarea';
  1860. var _classNameHostScrollbarHorizontalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusHorizontal + _strMinusHidden;
  1861. var _classNameHostScrollbarVerticalHidden = _classNameHostElement + '-' + _strScrollbar + _strMinusVertical + _strMinusHidden;
  1862. var _classNameHostTransition = _classNameHostElement + '-transition';
  1863. var _classNameHostRTL = _classNameHostElement + '-rtl';
  1864. var _classNameHostResizeDisabled = _classNameHostElement + '-resize-disabled';
  1865. var _classNameHostScrolling = _classNameHostElement + '-scrolling';
  1866. var _classNameHostOverflow = _classNameHostElement + '-overflow';
  1867. var _classNameHostOverflowX = _classNameHostOverflow + '-x';
  1868. var _classNameHostOverflowY = _classNameHostOverflow + '-y';
  1869. var _classNameTextareaElement = _cassNamesPrefix + 'textarea';
  1870. var _classNameTextareaCoverElement = _classNameTextareaElement + '-cover';
  1871. var _classNamePaddingElement = _cassNamesPrefix + 'padding';
  1872. var _classNameViewportElement = _cassNamesPrefix + 'viewport';
  1873. var _classNameViewportNativeScrollbarsInvisible = _classNameViewportElement + '-native-scrollbars-invisible';
  1874. var _classNameViewportNativeScrollbarsOverlaid = _classNameViewportElement + '-native-scrollbars-overlaid';
  1875. var _classNameContentElement = _cassNamesPrefix + 'content';
  1876. var _classNameContentArrangeElement = _cassNamesPrefix + 'content-arrange';
  1877. var _classNameContentGlueElement = _cassNamesPrefix + 'content-glue';
  1878. var _classNameSizeAutoObserverElement = _cassNamesPrefix + 'size-auto-observer';
  1879. var _classNameResizeObserverElement = _cassNamesPrefix + 'resize-observer';
  1880. var _classNameResizeObserverItemElement = _cassNamesPrefix + 'resize-observer-item';
  1881. var _classNameResizeObserverItemFinalElement = _classNameResizeObserverItemElement + '-final';
  1882. var _classNameTextInherit = _cassNamesPrefix + 'text-inherit';
  1883. var _classNameScrollbar = _cassNamesPrefix + _strScrollbar;
  1884. var _classNameScrollbarTrack = _classNameScrollbar + '-track';
  1885. var _classNameScrollbarTrackOff = _classNameScrollbarTrack + '-off';
  1886. var _classNameScrollbarHandle = _classNameScrollbar + '-handle';
  1887. var _classNameScrollbarHandleOff = _classNameScrollbarHandle + '-off';
  1888. var _classNameScrollbarUnusable = _classNameScrollbar + '-unusable';
  1889. var _classNameScrollbarAutoHidden = _classNameScrollbar + '-' + _strAuto + _strMinusHidden;
  1890. var _classNameScrollbarCorner = _classNameScrollbar + '-corner';
  1891. var _classNameScrollbarCornerResize = _classNameScrollbarCorner + '-resize';
  1892. var _classNameScrollbarCornerResizeB = _classNameScrollbarCornerResize + '-both';
  1893. var _classNameScrollbarCornerResizeH = _classNameScrollbarCornerResize + _strMinusHorizontal;
  1894. var _classNameScrollbarCornerResizeV = _classNameScrollbarCornerResize + _strMinusVertical;
  1895. var _classNameScrollbarHorizontal = _classNameScrollbar + _strMinusHorizontal;
  1896. var _classNameScrollbarVertical = _classNameScrollbar + _strMinusVertical;
  1897. var _classNameDragging = _cassNamesPrefix + 'dragging';
  1898. var _classNameThemeNone = _cassNamesPrefix + 'theme-none';
  1899. //callbacks:
  1900. var _callbacksInitQeueue = [ ];
  1901. //options:
  1902. var _defaultOptions;
  1903. var _currentOptions;
  1904. var _currentPreparedOptions;
  1905. //extensions:
  1906. var _extensions = { };
  1907. var _extensionsPrivateMethods = "added removed on contract";
  1908. //update
  1909. var _lastUpdateTime;
  1910. var _swallowedUpdateParams = { };
  1911. var _swallowedUpdateTimeout;
  1912. var _swallowUpdateLag = 42;
  1913. var _imgs = [ ];
  1914. //DOM elements:
  1915. var _windowElement;
  1916. var _documentElement;
  1917. var _htmlElement;
  1918. var _bodyElement;
  1919. var _targetElement; //the target element of this OverlayScrollbars object
  1920. var _hostElement; //the host element of this OverlayScrollbars object -> may be the same as targetElement
  1921. var _sizeAutoObserverElement; //observes size auto changes
  1922. var _sizeObserverElement; //observes size and padding changes
  1923. var _paddingElement; //manages the padding
  1924. var _viewportElement; //is the viewport of our scrollbar model
  1925. var _contentElement; //the element which holds the content
  1926. var _contentArrangeElement; //is needed for correct sizing of the content element (only if native scrollbars are overlays)
  1927. var _contentGlueElement; //has always the size of the content element
  1928. var _textareaCoverElement; //only applied if target is a textarea element. Used for correct size calculation and for prevention of uncontrolled scrolling
  1929. var _scrollbarCornerElement;
  1930. var _scrollbarHorizontalElement;
  1931. var _scrollbarHorizontalTrackElement;
  1932. var _scrollbarHorizontalHandleElement;
  1933. var _scrollbarVerticalElement;
  1934. var _scrollbarVerticalTrackElement;
  1935. var _scrollbarVerticalHandleElement;
  1936. var _windowElementNative;
  1937. var _documentElementNative;
  1938. var _targetElementNative;
  1939. var _hostElementNative;
  1940. var _sizeAutoObserverElementNative;
  1941. var _sizeObserverElementNative;
  1942. var _paddingElementNative;
  1943. var _viewportElementNative;
  1944. var _contentElementNative;
  1945. //Cache:
  1946. var _hostSizeCache;
  1947. var _contentScrollSizeCache;
  1948. var _arrangeContentSizeCache;
  1949. var _hasOverflowCache;
  1950. var _hideOverflowCache;
  1951. var _widthAutoCache;
  1952. var _heightAutoCache;
  1953. var _cssMaxValueCache;
  1954. var _cssBoxSizingCache;
  1955. var _cssPaddingCache;
  1956. var _cssBorderCache;
  1957. var _cssMarginCache;
  1958. var _cssDirectionCache;
  1959. var _cssDirectionDetectedCache;
  1960. var _paddingAbsoluteCache;
  1961. var _clipAlwaysCache;
  1962. var _contentGlueSizeCache;
  1963. var _overflowBehaviorCache;
  1964. var _overflowAmountCache;
  1965. var _ignoreOverlayScrollbarHidingCache;
  1966. var _autoUpdateCache;
  1967. var _sizeAutoCapableCache;
  1968. var _textareaAutoWrappingCache;
  1969. var _textareaInfoCache;
  1970. var _updateAutoHostElementIdCache;
  1971. var _updateAutoHostElementClassCache;
  1972. var _updateAutoHostElementStyleCache;
  1973. var _updateAutoHostElementVisibleCache;
  1974. var _updateAutoTargetElementRowsCache;
  1975. var _updateAutoTargetElementColsCache;
  1976. var _updateAutoTargetElementWrapCache;
  1977. var _contentElementScrollSizeChangeDetectedCache;
  1978. var _hostElementSizeChangeDetectedCache;
  1979. var _scrollbarsVisibilityCache;
  1980. var _scrollbarsAutoHideCache;
  1981. var _scrollbarsClickScrollingCache;
  1982. var _scrollbarsDragScrollingCache;
  1983. var _resizeCache;
  1984. var _normalizeRTLCache;
  1985. var _classNameCache;
  1986. var _oldClassName;
  1987. var _textareaDynHeightCache;
  1988. var _textareaDynWidthCache;
  1989. var _bodyMinSizeCache;
  1990. var _viewportScrollSizeCache;
  1991. var _displayIsHiddenCache;
  1992. //MutationObserver:
  1993. var _mutationObserverHost;
  1994. var _mutationObserverContent;
  1995. var _mutationObserversConnected;
  1996. //textarea:
  1997. var _textareaEvents;
  1998. var _textareaHasFocus;
  1999. //scrollbars:
  2000. var _scrollbarsAutoHideTimeoutId;
  2001. var _scrollbarsAutoHideMoveTimeoutId;
  2002. var _scrollbarsAutoHideDelay;
  2003. var _scrollbarsAutoHideNever;
  2004. var _scrollbarsAutoHideScroll;
  2005. var _scrollbarsAutoHideMove;
  2006. var _scrollbarsAutoHideLeave;
  2007. var _scrollbarsHandleHovered;
  2008. var _scrollbarsHandleAsync;
  2009. //resize
  2010. var _resizeReconnectMutationObserver;
  2011. var _resizeNone;
  2012. var _resizeBoth;
  2013. var _resizeHorizontal;
  2014. var _resizeVertical;
  2015. var _resizeOnMouseTouchDown;
  2016. //==== Passive Event Listener ====//
  2017. /**
  2018. * Adds a passive event listener to the given element.
  2019. * @param element The element to which the event listener shall be applied.
  2020. * @param eventNames The name(s) of the event listener.
  2021. * @param listener The listener method which shall be called.
  2022. */
  2023. function addPassiveEventListener(element, eventNames, listener) {
  2024. var events = eventNames.split(_strSpace);
  2025. for (var i = 0; i < events.length; i++)
  2026. element[0].addEventListener(events[i], listener, {passive: true});
  2027. }
  2028. /**
  2029. * Removes a passive event listener to the given element.
  2030. * @param element The element from which the event listener shall be removed.
  2031. * @param eventNames The name(s) of the event listener.
  2032. * @param listener The listener method which shall be removed.
  2033. */
  2034. function removePassiveEventListener(element, eventNames, listener) {
  2035. var events = eventNames.split(_strSpace);
  2036. for (var i = 0; i < events.length; i++)
  2037. element[0].removeEventListener(events[i], listener, {passive: true});
  2038. }
  2039. //==== Resize Observer ====//
  2040. /**
  2041. * Adds a resize observer to the given element.
  2042. * @param targetElement The element to which the resize observer shall be applied.
  2043. * @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change.
  2044. */
  2045. function addResizeObserver(targetElement, onElementResizedCallback) {
  2046. var constMaximum = 3333333;
  2047. var resizeObserver = COMPATIBILITY.rO();
  2048. var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart';
  2049. var strChildNodes = 'childNodes';
  2050. var callback = function () {
  2051. targetElement[_strScrollTop](constMaximum)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum : constMaximum);
  2052. onElementResizedCallback();
  2053. };
  2054. if (_supportResizeObserver) {
  2055. var element = targetElement.append(generateDiv(_classNameResizeObserverElement + ' observed')).contents()[0];
  2056. var observer = element[_strResizeObserverProperty] = new resizeObserver(callback);
  2057. observer.observe(element);
  2058. }
  2059. else {
  2060. if (_msieVersion > 9 || !_autoUpdateRecommended) {
  2061. targetElement.prepend(
  2062. generateDiv(_classNameResizeObserverElement,
  2063. generateDiv({ className : _classNameResizeObserverItemElement, dir : "ltr" },
  2064. generateDiv(_classNameResizeObserverItemElement,
  2065. generateDiv(_classNameResizeObserverItemFinalElement)
  2066. ) +
  2067. generateDiv(_classNameResizeObserverItemElement,
  2068. generateDiv({ className : _classNameResizeObserverItemFinalElement, style : 'width: 200%; height: 200%' })
  2069. )
  2070. )
  2071. )
  2072. );
  2073. var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0];
  2074. var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]);
  2075. var expandElement = FRAMEWORK(observerElement[strChildNodes][0]);
  2076. var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]);
  2077. var widthCache = observerElement[LEXICON.oW];
  2078. var heightCache = observerElement[LEXICON.oH];
  2079. var isDirty;
  2080. var rAFId;
  2081. var currWidth;
  2082. var currHeight;
  2083. var factor = 2;
  2084. var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!!
  2085. var reset = function () {
  2086. /*
  2087. var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
  2088. var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y;
  2089. var expandChildCSS = {};
  2090. expandChildCSS[_strWidth] = sizeResetWidth;
  2091. expandChildCSS[_strHeight] = sizeResetHeight;
  2092. expandElementChild.css(expandChildCSS);
  2093. expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
  2094. shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight);
  2095. */
  2096. expandElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum);
  2097. shrinkElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum);
  2098. };
  2099. var onResized = function () {
  2100. rAFId = 0;
  2101. if (!isDirty)
  2102. return;
  2103. widthCache = currWidth;
  2104. heightCache = currHeight;
  2105. callback();
  2106. };
  2107. var onScroll = function (event) {
  2108. currWidth = observerElement[LEXICON.oW];
  2109. currHeight = observerElement[LEXICON.oH];
  2110. isDirty = currWidth != widthCache || currHeight != heightCache;
  2111. if (event && isDirty && !rAFId) {
  2112. COMPATIBILITY.cAF()(rAFId);
  2113. rAFId = COMPATIBILITY.rAF()(onResized);
  2114. }
  2115. else if(!event)
  2116. onResized();
  2117. reset();
  2118. if (event) {
  2119. COMPATIBILITY.prvD(event);
  2120. COMPATIBILITY.stpP(event);
  2121. }
  2122. return false;
  2123. };
  2124. var expandChildCSS = {};
  2125. var observerElementCSS = {};
  2126. setTopRightBottomLeft(observerElementCSS, _strEmpty, [
  2127. -((nativeScrollbarSize.y + 1) * factor),
  2128. nativeScrollbarSize.x * -factor,
  2129. nativeScrollbarSize.y * -factor,
  2130. -((nativeScrollbarSize.x + 1) * factor)
  2131. ]);
  2132. FRAMEWORK(observerElement).css(observerElementCSS);
  2133. expandElement.on(_strScroll, onScroll);
  2134. shrinkElement.on(_strScroll, onScroll);
  2135. targetElement.on(strAnimationStartEvent, function () {
  2136. onScroll(false);
  2137. });
  2138. //lets assume that the divs will never be that large and a constant value is enough
  2139. expandChildCSS[_strWidth] = constMaximum;
  2140. expandChildCSS[_strHeight] = constMaximum;
  2141. expandElementChild.css(expandChildCSS);
  2142. reset();
  2143. }
  2144. else {
  2145. var attachEvent = _documentElementNative.attachEvent;
  2146. var isIE = _msieVersion !== undefined;
  2147. if (attachEvent) {
  2148. targetElement.prepend(generateDiv(_classNameResizeObserverElement));
  2149. findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback);
  2150. }
  2151. else {
  2152. var obj = _documentElementNative.createElement(TYPES.o);
  2153. obj.setAttribute('tabindex', '-1');
  2154. obj.setAttribute(LEXICON.c, _classNameResizeObserverElement);
  2155. obj.onload = function () {
  2156. var wnd = this.contentDocument.defaultView;
  2157. wnd.addEventListener('resize', callback);
  2158. wnd.document.documentElement.style.display = 'none';
  2159. };
  2160. obj.type = 'text/html';
  2161. if (isIE)
  2162. targetElement.prepend(obj);
  2163. obj.data = 'about:blank';
  2164. if (!isIE)
  2165. targetElement.prepend(obj);
  2166. targetElement.on(strAnimationStartEvent, callback);
  2167. }
  2168. }
  2169. }
  2170. //direction change detection:
  2171. if (targetElement[0] === _sizeObserverElementNative) {
  2172. var directionChanged = function () {
  2173. var dir = _hostElement.css('direction');
  2174. var css = {};
  2175. var scrollLeftValue = 0;
  2176. var result = false;
  2177. if (dir !== _cssDirectionDetectedCache) {
  2178. if (dir === 'ltr') {
  2179. css[_strLeft] = 0;
  2180. css[_strRight] = _strAuto;
  2181. scrollLeftValue = constMaximum;
  2182. }
  2183. else {
  2184. css[_strLeft] = _strAuto;
  2185. css[_strRight] = 0;
  2186. scrollLeftValue = _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum;
  2187. }
  2188. _sizeObserverElement.children().eq(0).css(css);
  2189. targetElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constMaximum);
  2190. _cssDirectionDetectedCache = dir;
  2191. result = true;
  2192. }
  2193. return result;
  2194. };
  2195. directionChanged();
  2196. targetElement.on(_strScroll, function (event) {
  2197. if (directionChanged())
  2198. update();
  2199. COMPATIBILITY.prvD(event);
  2200. COMPATIBILITY.stpP(event);
  2201. return false;
  2202. });
  2203. }
  2204. }
  2205. /**
  2206. * Removes a resize observer from the given element.
  2207. * @param targetElement The element to which the target resize observer is applied.
  2208. */
  2209. function removeResizeObserver(targetElement) {
  2210. if (_supportResizeObserver) {
  2211. var element = targetElement.contents()[0];
  2212. element[_strResizeObserverProperty].disconnect();
  2213. delete element[_strResizeObserverProperty];
  2214. }
  2215. else {
  2216. remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0));
  2217. }
  2218. }
  2219. /**
  2220. * Freezes the given resize observer.
  2221. * @param targetElement The element to which the target resize observer is applied.
  2222. */
  2223. function freezeResizeObserver(targetElement) {
  2224. if (targetElement !== undefined) {
  2225. /*
  2226. if (_supportResizeObserver) {
  2227. var element = targetElement.contents()[0];
  2228. element[_strResizeObserverProperty].unobserve(element);
  2229. }
  2230. else {
  2231. targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0);
  2232. var w = targetElement.css(_strWidth);
  2233. var h = targetElement.css(_strHeight);
  2234. var css = {};
  2235. css[_strWidth] = w;
  2236. css[_strHeight] = h;
  2237. targetElement.css(css);
  2238. }
  2239. */
  2240. }
  2241. }
  2242. /**
  2243. * Unfreezes the given resize observer.
  2244. * @param targetElement The element to which the target resize observer is applied.
  2245. */
  2246. function unfreezeResizeObserver(targetElement) {
  2247. if (targetElement !== undefined) {
  2248. /*
  2249. if (_supportResizeObserver) {
  2250. var element = targetElement.contents()[0];
  2251. element[_strResizeObserverProperty].observe(element);
  2252. }
  2253. else {
  2254. var css = { };
  2255. css[_strHeight] = _strEmpty;
  2256. css[_strWidth] = _strEmpty;
  2257. targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css);
  2258. }
  2259. */
  2260. }
  2261. }
  2262. //==== Mutation Observers ====//
  2263. /**
  2264. * Creates MutationObservers for the host and content Element if they are supported.
  2265. */
  2266. function createMutationObservers() {
  2267. if (_supportMutationObserver) {
  2268. var mutationObserverContentLag = 11;
  2269. var mutationObserver = COMPATIBILITY.mO();
  2270. var contentLastUpdate = COMPATIBILITY.now();
  2271. var mutationTarget;
  2272. var mutationAttrName;
  2273. var contentTimeout;
  2274. var now;
  2275. var sizeAuto;
  2276. var action;
  2277. _mutationObserverHost = new mutationObserver(function (mutations) {
  2278. if (!_initialized || _isSleeping)
  2279. return;
  2280. var doUpdate = false;
  2281. var mutation;
  2282. FRAMEWORK.each(mutations, function () {
  2283. mutation = this;
  2284. mutationTarget = mutation.target;
  2285. mutationAttrName = mutation.attributeName;
  2286. if (mutationAttrName === LEXICON.c)
  2287. doUpdate = hostClassNamesChanged(mutation.oldValue, mutationTarget.className);
  2288. else if (mutationAttrName === LEXICON.s)
  2289. doUpdate = mutation.oldValue !== mutationTarget[LEXICON.s].cssText;
  2290. else
  2291. doUpdate = true;
  2292. if (doUpdate)
  2293. return false;
  2294. });
  2295. if (doUpdate)
  2296. _base.update(_strAuto);
  2297. });
  2298. _mutationObserverContent = new mutationObserver(function (mutations) {
  2299. if (!_initialized || _isSleeping)
  2300. return;
  2301. var doUpdate = false;
  2302. var mutation;
  2303. FRAMEWORK.each(mutations, function () {
  2304. mutation = this;
  2305. doUpdate = isUnknownMutation(mutation);
  2306. return !doUpdate;
  2307. });
  2308. if (doUpdate) {
  2309. now = COMPATIBILITY.now();
  2310. sizeAuto = (_heightAutoCache || _widthAutoCache);
  2311. action = function () {
  2312. if(!_destroyed) {
  2313. contentLastUpdate = now;
  2314. //if cols, rows or wrap attr was changed
  2315. if (_isTextarea)
  2316. textareaUpdate();
  2317. if (sizeAuto)
  2318. update();
  2319. else
  2320. _base.update(_strAuto);
  2321. }
  2322. };
  2323. clearTimeout(contentTimeout);
  2324. if (mutationObserverContentLag <= 0 || now - contentLastUpdate > mutationObserverContentLag || !sizeAuto)
  2325. action();
  2326. else
  2327. contentTimeout = setTimeout(action, mutationObserverContentLag);
  2328. }
  2329. });
  2330. }
  2331. }
  2332. /**
  2333. * Connects the MutationObservers if they are supported.
  2334. */
  2335. function connectMutationObservers() {
  2336. if (_supportMutationObserver && !_mutationObserversConnected) {
  2337. _mutationObserverHost.observe(_hostElementNative, {
  2338. attributes: true,
  2339. attributeOldValue: true,
  2340. attributeFilter: [LEXICON.i, LEXICON.c, LEXICON.s]
  2341. });
  2342. _mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, {
  2343. attributes: true,
  2344. attributeOldValue: true,
  2345. subtree: !_isTextarea,
  2346. childList: !_isTextarea,
  2347. characterData: !_isTextarea,
  2348. attributeFilter: _isTextarea ? ['wrap', 'cols', 'rows'] : [LEXICON.i, LEXICON.c, LEXICON.s]
  2349. });
  2350. _mutationObserversConnected = true;
  2351. }
  2352. }
  2353. /**
  2354. * Disconnects the MutationObservers if they are supported.
  2355. */
  2356. function disconnectMutationObservers() {
  2357. if (_supportMutationObserver && _mutationObserversConnected) {
  2358. _mutationObserverHost.disconnect();
  2359. _mutationObserverContent.disconnect();
  2360. _mutationObserversConnected = false;
  2361. }
  2362. }
  2363. //==== Events of elements ====//
  2364. /**
  2365. * This method gets called every time the host element gets resized. IMPORTANT: Padding changes are detected too!!
  2366. * It refreshes the hostResizedEventArgs and the hostSizeResizeCache.
  2367. * If there are any size changes, the update method gets called.
  2368. */
  2369. function hostOnResized() {
  2370. if (_isSleeping)
  2371. return;
  2372. var changed;
  2373. var hostSize = {
  2374. w: _sizeObserverElementNative[LEXICON.sW],
  2375. h: _sizeObserverElementNative[LEXICON.sH]
  2376. };
  2377. if (_initialized) {
  2378. changed = checkCacheDouble(hostSize, _hostElementSizeChangeDetectedCache);
  2379. _hostElementSizeChangeDetectedCache = hostSize;
  2380. if (changed)
  2381. update(true, false);
  2382. }
  2383. else {
  2384. _hostElementSizeChangeDetectedCache = hostSize;
  2385. }
  2386. }
  2387. /**
  2388. * The mouse enter event of the host element. This event is only needed for the autoHide feature.
  2389. */
  2390. function hostOnMouseEnter() {
  2391. if (_scrollbarsAutoHideLeave)
  2392. refreshScrollbarsAutoHide(true);
  2393. }
  2394. /**
  2395. * The mouse leave event of the host element. This event is only needed for the autoHide feature.
  2396. */
  2397. function hostOnMouseLeave() {
  2398. if (_scrollbarsAutoHideLeave && !_bodyElement.hasClass(_classNameDragging))
  2399. refreshScrollbarsAutoHide(false);
  2400. }
  2401. /**
  2402. * The mouse move event of the host element. This event is only needed for the autoHide "move" feature.
  2403. */
  2404. function hostOnMouseMove() {
  2405. if (_scrollbarsAutoHideMove) {
  2406. refreshScrollbarsAutoHide(true);
  2407. clearTimeout(_scrollbarsAutoHideMoveTimeoutId);
  2408. _scrollbarsAutoHideMoveTimeoutId = setTimeout(function () {
  2409. if (_scrollbarsAutoHideMove && !_destroyed)
  2410. refreshScrollbarsAutoHide(false);
  2411. }, 100);
  2412. }
  2413. }
  2414. /**
  2415. * Adds or removes mouse & touch events of the host element. (for handling auto-hiding of the scrollbars)
  2416. * @param destroy Indicates whether the events shall be added or removed.
  2417. */
  2418. function setupHostMouseTouchEvents(destroy) {
  2419. var passiveEvent = destroy ? removePassiveEventListener : addPassiveEventListener;
  2420. var strOnOff = destroy ? 'off' : 'on';
  2421. var setupEvent = function(target, name, listener) {
  2422. if(_supportPassiveEvents)
  2423. passiveEvent(target, name, listener);
  2424. else
  2425. target[strOnOff](name, listener);
  2426. };
  2427. if(_scrollbarsAutoHideMove && !destroy)
  2428. setupEvent(_hostElement, _strMouseTouchMoveEvent, hostOnMouseMove);
  2429. else {
  2430. if(destroy)
  2431. setupEvent(_hostElement, _strMouseTouchMoveEvent, hostOnMouseMove);
  2432. setupEvent(_hostElement, _strMouseTouchEnter, hostOnMouseEnter);
  2433. setupEvent(_hostElement, _strMouseTouchLeave, hostOnMouseLeave);
  2434. }
  2435. //if the plugin is initialized and the mouse is over the host element, make the scrollbars visible
  2436. if(!_initialized && !destroy)
  2437. _hostElement.one("mouseover", hostOnMouseEnter);
  2438. }
  2439. /**
  2440. * Prevents text from deselection if attached to the document element on the mousedown event of a DOM element.
  2441. * @param event The select start event.
  2442. */
  2443. function documentOnSelectStart(event) {
  2444. COMPATIBILITY.prvD(event);
  2445. return false;
  2446. }
  2447. /**
  2448. * A callback which will be called after a img element has downloaded its src asynchronous.
  2449. */
  2450. function imgOnLoad() {
  2451. update(false, true);
  2452. }
  2453. //==== Update Detection ====//
  2454. /**
  2455. * Measures the min width and min height of the body element and refreshes the related cache.
  2456. * @returns {boolean} True if the min width or min height has changed, false otherwise.
  2457. */
  2458. function bodyMinSizeChanged() {
  2459. var bodyMinSize = {};
  2460. if (_isBody && _contentArrangeElement) {
  2461. bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth));
  2462. bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight));
  2463. bodyMinSize.c = checkCacheDouble(bodyMinSize, _bodyMinSizeCache);
  2464. bodyMinSize.f = true; //flag for "measured at least once"
  2465. }
  2466. _bodyMinSizeCache = bodyMinSize;
  2467. return bodyMinSize.c || false;
  2468. }
  2469. /**
  2470. * Returns true if the class names really changed (new class without plugin host prefix)
  2471. * @param oldCassNames The old ClassName string.
  2472. * @param newClassNames The new ClassName string.
  2473. * @returns {boolean} True if the class names has really changed, false otherwise.
  2474. */
  2475. function hostClassNamesChanged(oldCassNames, newClassNames) {
  2476. var currClasses = (newClassNames !== undefined && newClassNames !== null) ? newClassNames.split(_strSpace) : _strEmpty;
  2477. var oldClasses = (oldCassNames !== undefined && oldCassNames !== null) ? oldCassNames.split(_strSpace) : _strEmpty;
  2478. if (currClasses === _strEmpty && oldClasses === _strEmpty)
  2479. return false;
  2480. var diff = getArrayDifferences(oldClasses, currClasses);
  2481. var changed = false;
  2482. var oldClassNames = _oldClassName !== undefined && _oldClassName !== null ? _oldClassName.split(_strSpace) : [_strEmpty];
  2483. var currClassNames = _classNameCache !== undefined && _classNameCache !== null ? _classNameCache.split(_strSpace) : [_strEmpty];
  2484. //remove none theme from diff list to prevent update
  2485. var idx = FRAMEWORK.inArray(_classNameThemeNone, diff);
  2486. var curr;
  2487. var i;
  2488. var v;
  2489. var o;
  2490. var c;
  2491. if (idx > -1)
  2492. diff.splice(idx, 1);
  2493. for (i = 0; i < diff.length; i++) {
  2494. curr = diff[i];
  2495. if (curr.indexOf(_classNameHostElement) !== 0) {
  2496. o = true;
  2497. c = true;
  2498. for (v = 0; v < oldClassNames.length; v++) {
  2499. if (curr === oldClassNames[v]) {
  2500. o = false;
  2501. break;
  2502. }
  2503. }
  2504. for (v = 0; v < currClassNames.length; v++) {
  2505. if (curr === currClassNames[v]) {
  2506. c = false;
  2507. break;
  2508. }
  2509. }
  2510. if (o && c) {
  2511. changed = true;
  2512. break;
  2513. }
  2514. }
  2515. }
  2516. return changed;
  2517. }
  2518. /**
  2519. * 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.
  2520. * @param mutation The mutation which shall be checked.
  2521. * @returns {boolean} True if the mutation is from a unknown element, false otherwise.
  2522. */
  2523. function isUnknownMutation(mutation) {
  2524. var attributeName = mutation.attributeName;
  2525. var mutationTarget = mutation.target;
  2526. var mutationType = mutation.type;
  2527. var strClosest = 'closest';
  2528. if (mutationTarget === _contentElementNative)
  2529. return attributeName === null;
  2530. if (mutationType === 'attributes' && (attributeName === LEXICON.c || attributeName === LEXICON.s) && !_isTextarea) {
  2531. //ignore className changes by the plugin
  2532. if (attributeName === LEXICON.c && FRAMEWORK(mutationTarget).hasClass(_classNameHostElement))
  2533. return hostClassNamesChanged(mutation.oldValue, mutationTarget.getAttribute(LEXICON.c));
  2534. //only do it of browser support it natively
  2535. if (typeof mutationTarget[strClosest] != TYPES.f)
  2536. return true;
  2537. if (mutationTarget[strClosest](_strDot + _classNameResizeObserverElement) !== null ||
  2538. mutationTarget[strClosest](_strDot + _classNameScrollbar) !== null ||
  2539. mutationTarget[strClosest](_strDot + _classNameScrollbarCorner) !== null)
  2540. return false;
  2541. }
  2542. return true;
  2543. }
  2544. /**
  2545. * Returns true if the content size was changed since the last time this method was called.
  2546. * @returns {boolean} True if the content size was changed, false otherwise.
  2547. */
  2548. function updateAutoContentSizeChanged() {
  2549. if (_isSleeping)
  2550. return false;
  2551. var float;
  2552. var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0;
  2553. var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea;
  2554. var viewportScrollSize = { };
  2555. var css = { };
  2556. var bodyMinSizeC;
  2557. var changed;
  2558. var viewportScrollSizeChanged;
  2559. //fix for https://bugzilla.mozilla.org/show_bug.cgi?id=1439305, it only works with "clipAlways : true"
  2560. //it can work with "clipAlways : false" too, but we had to set the overflow of the viewportElement to hidden every time before measuring
  2561. if(_restrictedMeasuring) {
  2562. viewportScrollSize = {
  2563. x : _viewportElementNative[LEXICON.sW],
  2564. y : _viewportElementNative[LEXICON.sH]
  2565. }
  2566. }
  2567. if (setCSS) {
  2568. float = _contentElement.css(_strFloat);
  2569. css[_strFloat] = _isRTL ? _strRight : _strLeft;
  2570. css[_strWidth] = _strAuto;
  2571. _contentElement.css(css);
  2572. }
  2573. var contentElementScrollSize = {
  2574. w: getContentMeasureElement()[LEXICON.sW] + textareaValueLength,
  2575. h: getContentMeasureElement()[LEXICON.sH] + textareaValueLength
  2576. };
  2577. if (setCSS) {
  2578. css[_strFloat] = float;
  2579. css[_strWidth] = _strHundredPercent;
  2580. _contentElement.css(css);
  2581. }
  2582. bodyMinSizeC = bodyMinSizeChanged();
  2583. changed = checkCacheDouble(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache);
  2584. viewportScrollSizeChanged = checkCacheDouble(viewportScrollSize, _viewportScrollSizeCache, _strX, _strY);
  2585. _contentElementScrollSizeChangeDetectedCache = contentElementScrollSize;
  2586. _viewportScrollSizeCache = viewportScrollSize;
  2587. return changed || bodyMinSizeC || viewportScrollSizeChanged;
  2588. }
  2589. /**
  2590. * Returns true if the host element attributes (id, class, style) was changed since the last time this method was called.
  2591. * @returns {boolean}
  2592. */
  2593. function meaningfulAttrsChanged() {
  2594. if (_isSleeping || _mutationObserversConnected)
  2595. return false;
  2596. var hostElementId = _hostElement.attr(LEXICON.i) || _strEmpty;
  2597. var hostElementIdChanged = checkCacheSingle(hostElementId, _updateAutoHostElementIdCache);
  2598. var hostElementClass = _hostElement.attr(LEXICON.c) || _strEmpty;
  2599. var hostElementClassChanged = checkCacheSingle(hostElementClass, _updateAutoHostElementClassCache);
  2600. var hostElementStyle = _hostElement.attr(LEXICON.s) || _strEmpty;
  2601. var hostElementStyleChanged = checkCacheSingle(hostElementStyle, _updateAutoHostElementStyleCache);
  2602. var hostElementVisible = _hostElement.is(':visible') || _strEmpty;
  2603. var hostElementVisibleChanged = checkCacheSingle(hostElementVisible, _updateAutoHostElementVisibleCache);
  2604. var targetElementRows = _isTextarea ? (_targetElement.attr('rows') || _strEmpty) : _strEmpty;
  2605. var targetElementRowsChanged = checkCacheSingle(targetElementRows, _updateAutoTargetElementRowsCache);
  2606. var targetElementCols = _isTextarea ? (_targetElement.attr('cols') || _strEmpty) : _strEmpty;
  2607. var targetElementColsChanged = checkCacheSingle(targetElementCols, _updateAutoTargetElementColsCache);
  2608. var targetElementWrap = _isTextarea ? (_targetElement.attr('wrap') || _strEmpty) : _strEmpty;
  2609. var targetElementWrapChanged = checkCacheSingle(targetElementWrap, _updateAutoTargetElementWrapCache);
  2610. _updateAutoHostElementIdCache = hostElementId;
  2611. if (hostElementClassChanged)
  2612. hostElementClassChanged = hostClassNamesChanged(_updateAutoHostElementClassCache, hostElementClass);
  2613. _updateAutoHostElementClassCache = hostElementClass;
  2614. _updateAutoHostElementStyleCache = hostElementStyle;
  2615. _updateAutoHostElementVisibleCache = hostElementVisible;
  2616. _updateAutoTargetElementRowsCache = targetElementRows;
  2617. _updateAutoTargetElementColsCache = targetElementCols;
  2618. _updateAutoTargetElementWrapCache = targetElementWrap;
  2619. return hostElementIdChanged || hostElementClassChanged || hostElementStyleChanged || hostElementVisibleChanged || targetElementRowsChanged || targetElementColsChanged || targetElementWrapChanged;
  2620. }
  2621. /**
  2622. * Checks is a CSS Property of a child element is affecting the scroll size of the content.
  2623. * @param propertyName The CSS property name.
  2624. * @returns {boolean} True if the property is affecting the content scroll size, false otherwise.
  2625. */
  2626. function isSizeAffectingCSSProperty(propertyName) {
  2627. if (!_initialized)
  2628. return true;
  2629. var flexGrow = 'flex-grow';
  2630. var flexShrink = 'flex-shrink';
  2631. var flexBasis = 'flex-basis';
  2632. var affectingPropsX = [
  2633. _strWidth,
  2634. _strMinMinus + _strWidth,
  2635. _strMaxMinus + _strWidth,
  2636. _strMarginMinus + _strLeft,
  2637. _strMarginMinus + _strRight,
  2638. _strLeft,
  2639. _strRight,
  2640. 'font-weight',
  2641. 'word-spacing',
  2642. flexGrow,
  2643. flexShrink,
  2644. flexBasis
  2645. ];
  2646. var affectingPropsXContentBox = [
  2647. _strPaddingMinus + _strLeft,
  2648. _strPaddingMinus + _strRight,
  2649. _strBorderMinus + _strLeft + _strWidth,
  2650. _strBorderMinus + _strRight + _strWidth
  2651. ];
  2652. var affectingPropsY = [
  2653. _strHeight,
  2654. _strMinMinus + _strHeight,
  2655. _strMaxMinus + _strHeight,
  2656. _strMarginMinus + _strTop,
  2657. _strMarginMinus + _strBottom,
  2658. _strTop,
  2659. _strBottom,
  2660. 'line-height',
  2661. flexGrow,
  2662. flexShrink,
  2663. flexBasis
  2664. ];
  2665. var affectingPropsYContentBox = [
  2666. _strPaddingMinus + _strTop,
  2667. _strPaddingMinus + _strBottom,
  2668. _strBorderMinus + _strTop + _strWidth,
  2669. _strBorderMinus + _strBottom + _strWidth
  2670. ];
  2671. var _strS = 's';
  2672. var _strVS = 'v-s';
  2673. var checkX = _overflowBehaviorCache.x === _strS || _overflowBehaviorCache.x === _strVS;
  2674. var checkY = _overflowBehaviorCache.y === _strS || _overflowBehaviorCache.y === _strVS;
  2675. var sizeIsAffected = false;
  2676. var checkPropertyName = function (arr, name) {
  2677. for (var i = 0; i < arr[LEXICON.l]; i++) {
  2678. if (arr[i] === name)
  2679. return true;
  2680. }
  2681. return false;
  2682. };
  2683. if (checkY) {
  2684. sizeIsAffected = checkPropertyName(affectingPropsY, propertyName);
  2685. if (!sizeIsAffected && !_isBorderBox)
  2686. sizeIsAffected = checkPropertyName(affectingPropsYContentBox, propertyName);
  2687. }
  2688. if (checkX && !sizeIsAffected) {
  2689. sizeIsAffected = checkPropertyName(affectingPropsX, propertyName);
  2690. if (!sizeIsAffected && !_isBorderBox)
  2691. sizeIsAffected = checkPropertyName(affectingPropsXContentBox, propertyName);
  2692. }
  2693. return sizeIsAffected;
  2694. }
  2695. //==== Update ====//
  2696. /**
  2697. * Updates the variables and size of the textarea element, and manages the scroll on new line or new character.
  2698. */
  2699. function textareaUpdate() {
  2700. if (_isSleeping)
  2701. return;
  2702. var wrapAttrOff = !_textareaAutoWrappingCache;
  2703. var minWidth = _viewportSize.w /* - (!_isBorderBox && !_paddingAbsoluteCache && _widthAutoCache ? _paddingY + _borderY : 0) */;
  2704. var minHeight = _viewportSize.h /* - (!_isBorderBox && !_paddingAbsoluteCache && _heightAutoCache ? _paddingY + _borderY : 0) */;
  2705. var css = { };
  2706. var doMeasure = _widthAutoCache || wrapAttrOff;
  2707. var origWidth;
  2708. var width;
  2709. var origHeight;
  2710. var height;
  2711. //reset min size
  2712. css[_strMinMinus + _strWidth] = _strEmpty;
  2713. css[_strMinMinus + _strHeight] = _strEmpty;
  2714. //set width auto
  2715. css[_strWidth] = _strAuto;
  2716. _targetElement.css(css);
  2717. //measure width
  2718. origWidth = _targetElementNative[LEXICON.oW];
  2719. width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1;
  2720. /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/
  2721. //set measured width
  2722. css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent;
  2723. css[_strMinMinus + _strWidth] = _strHundredPercent;
  2724. //set height auto
  2725. css[_strHeight] = _strAuto;
  2726. _targetElement.css(css);
  2727. //measure height
  2728. origHeight = _targetElementNative[LEXICON.oH];
  2729. height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1);
  2730. //append correct size values
  2731. css[_strWidth] = width;
  2732. css[_strHeight] = height;
  2733. _textareaCoverElement.css(css);
  2734. //apply min width / min height to prevent textarea collapsing
  2735. css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/;
  2736. css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/;
  2737. _targetElement.css(css);
  2738. return {
  2739. _originalWidth: origWidth,
  2740. _originalHeight: origHeight,
  2741. _dynamicWidth: width,
  2742. _dynamicHeight: height
  2743. };
  2744. }
  2745. /**
  2746. * Updates the plugin and DOM to the current options.
  2747. * This method should only be called if a update is 100% required.
  2748. * @param hostSizeChanged True if this method was called due to a host size change.
  2749. * @param contentSizeChanged True if this method was called due to a content size change.
  2750. * @param force True if every property shall be updated and the cache shall be ignored.
  2751. * @param preventSwallowing True if this method shall be executed event if it could be swallowed.
  2752. */
  2753. function update(hostSizeChanged, contentSizeChanged, force, preventSwallowing) {
  2754. var now = COMPATIBILITY.now();
  2755. var swallow = _swallowUpdateLag > 0 && _initialized && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache) && !preventSwallowing;
  2756. var displayIsHidden = _hostElement.is(':hidden');
  2757. var displayIsHiddenChanged = checkCacheSingle(displayIsHidden, _displayIsHiddenCache, force);
  2758. _displayIsHiddenCache = displayIsHidden;
  2759. clearTimeout(_swallowedUpdateTimeout);
  2760. if (swallow) {
  2761. _swallowedUpdateParams.h = _swallowedUpdateParams.h || hostSizeChanged;
  2762. _swallowedUpdateParams.c = _swallowedUpdateParams.c || contentSizeChanged;
  2763. _swallowedUpdateParams.f = _swallowedUpdateParams.f || force;
  2764. _swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag);
  2765. }
  2766. //abort update due to:
  2767. //destroyed
  2768. //swallowing
  2769. //sleeping
  2770. //host is hidden or has false display
  2771. if (_destroyed || swallow || _isSleeping || (_initialized && !force && displayIsHidden) || _hostElement.css('display') === 'inline')
  2772. return;
  2773. _lastUpdateTime = now;
  2774. hostSizeChanged = hostSizeChanged || _swallowedUpdateParams.h;
  2775. contentSizeChanged = contentSizeChanged || _swallowedUpdateParams.c;
  2776. force = force || _swallowedUpdateParams.f;
  2777. _swallowedUpdateParams = {};
  2778. hostSizeChanged = hostSizeChanged === undefined ? false : hostSizeChanged;
  2779. contentSizeChanged = contentSizeChanged === undefined ? false : contentSizeChanged;
  2780. force = force === undefined ? false : force;
  2781. //if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely.
  2782. if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
  2783. //native scrollbars are hidden, so change the values to zero
  2784. _nativeScrollbarSize.x = 0;
  2785. _nativeScrollbarSize.y = 0;
  2786. }
  2787. else {
  2788. //refresh native scrollbar size (in case of zoom)
  2789. _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
  2790. }
  2791. // Scrollbar padding is needed for firefox, because firefox hides scrollbar automatically if the size of the div is too small.
  2792. // The calculation: [scrollbar size +3 *3]
  2793. // (+3 because of possible decoration e.g. borders, margins etc., but only if native scrollbar is NOT a overlaid scrollbar)
  2794. // (*3 because (1)increase / (2)decrease -button and (3)resize handle)
  2795. _nativeScrollbarMinSize = {
  2796. x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3,
  2797. y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 3
  2798. };
  2799. freezeResizeObserver(_sizeObserverElement);
  2800. freezeResizeObserver(_sizeAutoObserverElement);
  2801. //save current scroll offset
  2802. var currScroll = {
  2803. x: _viewportElement[_strScrollLeft](),
  2804. y: _viewportElement[_strScrollTop]()
  2805. };
  2806. var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars;
  2807. var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea;
  2808. //scrollbars visibility:
  2809. var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility;
  2810. var scrollbarsVisibilityChanged = checkCacheSingle(scrollbarsVisibility, _scrollbarsVisibilityCache, force);
  2811. //scrollbars autoHide:
  2812. var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide;
  2813. var scrollbarsAutoHideChanged = checkCacheSingle(scrollbarsAutoHide, _scrollbarsAutoHideCache, force);
  2814. //scrollbars click scrolling
  2815. var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling;
  2816. var scrollbarsClickScrollingChanged = checkCacheSingle(scrollbarsClickScrolling, _scrollbarsClickScrollingCache, force);
  2817. //scrollbars drag scrolling
  2818. var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling;
  2819. var scrollbarsDragScrollingChanged = checkCacheSingle(scrollbarsDragScrolling, _scrollbarsDragScrollingCache, force);
  2820. //className
  2821. var className = _currentPreparedOptions.className;
  2822. var classNameChanged = checkCacheSingle(className, _classNameCache, force);
  2823. //resize
  2824. var resize = _currentPreparedOptions.resize;
  2825. var resizeChanged = checkCacheSingle(resize, _resizeCache, force) && !_isBody; //body can't be resized since the window itself acts as resize possibility.
  2826. //textarea AutoWrapping
  2827. var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false;
  2828. var textareaAutoWrappingChanged = checkCacheSingle(textareaAutoWrapping, _textareaAutoWrappingCache, force);
  2829. //paddingAbsolute
  2830. var paddingAbsolute = _currentPreparedOptions.paddingAbsolute;
  2831. var paddingAbsoluteChanged = checkCacheSingle(paddingAbsolute, _paddingAbsoluteCache, force);
  2832. //clipAlways
  2833. var clipAlways = _currentPreparedOptions.clipAlways;
  2834. var clipAlwaysChanged = checkCacheSingle(clipAlways, _clipAlwaysCache, force);
  2835. //sizeAutoCapable
  2836. var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport.
  2837. var sizeAutoCapableChanged = checkCacheSingle(sizeAutoCapable, _sizeAutoCapableCache, force);
  2838. //showNativeScrollbars
  2839. var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars;
  2840. var ignoreOverlayScrollbarHidingChanged = checkCacheSingle(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache);
  2841. //autoUpdate
  2842. var autoUpdate = _currentPreparedOptions.autoUpdate;
  2843. var autoUpdateChanged = checkCacheSingle(autoUpdate, _autoUpdateCache);
  2844. //overflowBehavior
  2845. var overflowBehavior = _currentPreparedOptions.overflowBehavior;
  2846. var overflowBehaviorChanged = checkCacheDouble(overflowBehavior, _overflowBehaviorCache, _strX, _strY, force);
  2847. //dynWidth:
  2848. var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth;
  2849. var textareaDynWidthChanged = checkCacheSingle(_textareaDynWidthCache, textareaDynWidth);
  2850. //dynHeight:
  2851. var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight;
  2852. var textareaDynHeightChanged = checkCacheSingle(_textareaDynHeightCache, textareaDynHeight);
  2853. //scrollbars visibility
  2854. _scrollbarsAutoHideNever = scrollbarsAutoHide === 'n';
  2855. _scrollbarsAutoHideScroll = scrollbarsAutoHide === 's';
  2856. _scrollbarsAutoHideMove = scrollbarsAutoHide === 'm';
  2857. _scrollbarsAutoHideLeave = scrollbarsAutoHide === 'l';
  2858. //scrollbars autoHideDelay
  2859. _scrollbarsAutoHideDelay = currentPreparedOptionsScrollbars.autoHideDelay;
  2860. //old className
  2861. _oldClassName = _classNameCache;
  2862. //resize
  2863. _resizeNone = resize === 'n';
  2864. _resizeBoth = resize === 'b';
  2865. _resizeHorizontal = resize === 'h';
  2866. _resizeVertical = resize === 'v';
  2867. //normalizeRTL
  2868. _normalizeRTLCache = _currentPreparedOptions.normalizeRTL;
  2869. //ignore overlay scrollbar hiding
  2870. ignoreOverlayScrollbarHiding = ignoreOverlayScrollbarHiding && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y);
  2871. //refresh options cache
  2872. _scrollbarsVisibilityCache = scrollbarsVisibility;
  2873. _scrollbarsAutoHideCache = scrollbarsAutoHide;
  2874. _scrollbarsClickScrollingCache = scrollbarsClickScrolling;
  2875. _scrollbarsDragScrollingCache = scrollbarsDragScrolling;
  2876. _classNameCache = className;
  2877. _resizeCache = resize;
  2878. _textareaAutoWrappingCache = textareaAutoWrapping;
  2879. _paddingAbsoluteCache = paddingAbsolute;
  2880. _clipAlwaysCache = clipAlways;
  2881. _sizeAutoCapableCache = sizeAutoCapable;
  2882. _ignoreOverlayScrollbarHidingCache = ignoreOverlayScrollbarHiding;
  2883. _autoUpdateCache = autoUpdate;
  2884. _overflowBehaviorCache = extendDeep({}, overflowBehavior);
  2885. _textareaDynWidthCache = textareaDynWidth;
  2886. _textareaDynHeightCache = textareaDynHeight;
  2887. _hasOverflowCache = _hasOverflowCache || { x: false, y: false };
  2888. //set correct class name to the host element
  2889. if (classNameChanged) {
  2890. removeClass(_hostElement, _oldClassName + _strSpace + _classNameThemeNone);
  2891. addClass(_hostElement, className !== undefined && className !== null && className.length > 0 ? className : _classNameThemeNone);
  2892. }
  2893. //set correct auto Update
  2894. if (autoUpdateChanged) {
  2895. if (autoUpdate === true) {
  2896. disconnectMutationObservers();
  2897. autoUpdateLoop.add(_base);
  2898. }
  2899. else if (autoUpdate === null) {
  2900. if (_autoUpdateRecommended) {
  2901. disconnectMutationObservers();
  2902. autoUpdateLoop.add(_base);
  2903. }
  2904. else {
  2905. autoUpdateLoop.remove(_base);
  2906. connectMutationObservers();
  2907. }
  2908. }
  2909. else {
  2910. autoUpdateLoop.remove(_base);
  2911. connectMutationObservers();
  2912. }
  2913. }
  2914. //activate or deactivate size auto capability
  2915. if (sizeAutoCapableChanged) {
  2916. if (sizeAutoCapable) {
  2917. if (!_contentGlueElement) {
  2918. _contentGlueElement = FRAMEWORK(generateDiv(_classNameContentGlueElement));
  2919. _paddingElement.before(_contentGlueElement);
  2920. }
  2921. else {
  2922. _contentGlueElement.show();
  2923. }
  2924. if (_sizeAutoObserverAdded) {
  2925. _sizeAutoObserverElement.show();
  2926. }
  2927. else {
  2928. _sizeAutoObserverElement = FRAMEWORK(generateDiv(_classNameSizeAutoObserverElement));
  2929. _sizeAutoObserverElementNative = _sizeAutoObserverElement[0];
  2930. _contentGlueElement.before(_sizeAutoObserverElement);
  2931. var oldSize = {w: -1, h: -1};
  2932. addResizeObserver(_sizeAutoObserverElement, function () {
  2933. var newSize = {
  2934. w: _sizeAutoObserverElementNative[LEXICON.oW],
  2935. h: _sizeAutoObserverElementNative[LEXICON.oH]
  2936. };
  2937. if (checkCacheDouble(newSize, oldSize)) {
  2938. if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) {
  2939. update();
  2940. }
  2941. else if (_initialized && (!_heightAutoCache && newSize.h === 0) || (!_widthAutoCache && newSize.w === 0)) {
  2942. update();
  2943. }
  2944. }
  2945. oldSize = newSize;
  2946. });
  2947. _sizeAutoObserverAdded = true;
  2948. //fix heightAuto detector bug if height is fixed but contentHeight is 0.
  2949. //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.
  2950. if (_cssCalc !== null)
  2951. _sizeAutoObserverElement.css(_strHeight, _cssCalc + '(100% + 1px)');
  2952. }
  2953. }
  2954. else {
  2955. if (_sizeAutoObserverAdded)
  2956. _sizeAutoObserverElement.hide();
  2957. if (_contentGlueElement)
  2958. _contentGlueElement.hide();
  2959. }
  2960. }
  2961. //if force, update all resizeObservers too
  2962. if (force) {
  2963. _sizeObserverElement.find('*').trigger(_strScroll);
  2964. if (_sizeAutoObserverAdded)
  2965. _sizeAutoObserverElement.find('*').trigger(_strScroll);
  2966. }
  2967. //detect direction:
  2968. var cssDirection = _hostElement.css('direction');
  2969. var cssDirectionChanged = checkCacheSingle(cssDirection, _cssDirectionCache, force);
  2970. //detect box-sizing:
  2971. var boxSizing = _hostElement.css('box-sizing');
  2972. var boxSizingChanged = checkCacheSingle(boxSizing, _cssBoxSizingCache, force);
  2973. //detect padding:
  2974. var padding = {
  2975. c: force,
  2976. t: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strTop)),
  2977. r: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strRight)),
  2978. b: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strBottom)),
  2979. l: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strLeft))
  2980. };
  2981. //width + height auto detecting var:
  2982. var sizeAutoObserverElementBCRect;
  2983. //exception occurs in IE8 sometimes (unknown exception)
  2984. try {
  2985. sizeAutoObserverElementBCRect = _sizeAutoObserverAdded ? _sizeAutoObserverElementNative.getBoundingClientRect() : null;
  2986. } catch (ex) {
  2987. return;
  2988. }
  2989. _isRTL = cssDirection === 'rtl';
  2990. _isBorderBox = (boxSizing === 'border-box');
  2991. var isRTLLeft = _isRTL ? _strLeft : _strRight;
  2992. var isRTLRight = _isRTL ? _strRight : _strLeft;
  2993. //detect width auto:
  2994. var widthAutoResizeDetection = false;
  2995. var widthAutoObserverDetection = (_sizeAutoObserverAdded && (_hostElement.css(_strFloat) !== 'none' /*|| _isTextarea */)) ? (MATH.round(sizeAutoObserverElementBCRect.right - sizeAutoObserverElementBCRect.left) === 0) && (!paddingAbsolute ? (_hostElementNative[LEXICON.cW] - _paddingX) > 0 : true) : false;
  2996. if (sizeAutoCapable && !widthAutoObserverDetection) {
  2997. var tmpCurrHostWidth = _hostElementNative[LEXICON.oW];
  2998. var tmpCurrContentGlueWidth = _contentGlueElement.css(_strWidth);
  2999. _contentGlueElement.css(_strWidth, _strAuto);
  3000. var tmpNewHostWidth = _hostElementNative[LEXICON.oW];
  3001. _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
  3002. widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
  3003. if (!widthAutoResizeDetection) {
  3004. _contentGlueElement.css(_strWidth, tmpCurrHostWidth + 1);
  3005. tmpNewHostWidth = _hostElementNative[LEXICON.oW];
  3006. _contentGlueElement.css(_strWidth, tmpCurrContentGlueWidth);
  3007. widthAutoResizeDetection = tmpCurrHostWidth !== tmpNewHostWidth;
  3008. }
  3009. }
  3010. var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden;
  3011. var widthAutoChanged = checkCacheSingle(widthAuto, _widthAutoCache, force);
  3012. var wasWidthAuto = !widthAuto && _widthAutoCache;
  3013. //detect height auto:
  3014. var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false;
  3015. var heightAutoChanged = checkCacheSingle(heightAuto, _heightAutoCache, force);
  3016. var wasHeightAuto = !heightAuto && _heightAutoCache;
  3017. //detect border:
  3018. //we need the border only if border box and auto size
  3019. var strMinusWidth = '-' + _strWidth;
  3020. var updateBorderX = (widthAuto && _isBorderBox) || !_isBorderBox;
  3021. var updateBorderY = (heightAuto && _isBorderBox) || !_isBorderBox;
  3022. var border = {
  3023. c: force,
  3024. t: updateBorderY ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strTop + strMinusWidth), true) : 0,
  3025. r: updateBorderX ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strRight + strMinusWidth), true) : 0,
  3026. b: updateBorderY ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strBottom + strMinusWidth), true) : 0,
  3027. l: updateBorderX ? parseToZeroOrNumber(_hostElement.css(_strBorderMinus + _strLeft + strMinusWidth), true) : 0
  3028. };
  3029. //detect margin:
  3030. var margin = {
  3031. c: force,
  3032. t: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strTop)),
  3033. r: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strRight)),
  3034. b: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strBottom)),
  3035. l: parseToZeroOrNumber(_hostElement.css(_strMarginMinus + _strLeft))
  3036. };
  3037. //detect css max width & height:
  3038. var cssMaxValue = {
  3039. h: String(_hostElement.css(_strMaxMinus + _strHeight)),
  3040. w: String(_hostElement.css(_strMaxMinus + _strWidth))
  3041. };
  3042. //vars to apply correct css
  3043. var contentElementCSS = { };
  3044. var contentGlueElementCSS = { };
  3045. //funcs
  3046. var getHostSize = function() {
  3047. //has to be clientSize because offsetSize respect borders
  3048. return {
  3049. w: _hostElementNative[LEXICON.cW],
  3050. h: _hostElementNative[LEXICON.cH]
  3051. };
  3052. };
  3053. var getViewportSize = function() {
  3054. //viewport size is padding container because it never has padding, margin and a border
  3055. //determine zoom rounding error -> sometimes scrollWidth/Height is smaller than clientWidth/Height
  3056. //if this happens add the difference to the viewportSize to compensate the rounding error
  3057. return {
  3058. w: _paddingElementNative[LEXICON.oW] + MATH.max(0, _contentElementNative[LEXICON.cW] - _contentElementNative[LEXICON.sW]),
  3059. h: _paddingElementNative[LEXICON.oH] + MATH.max(0, _contentElementNative[LEXICON.cH] - _contentElementNative[LEXICON.sH])
  3060. };
  3061. };
  3062. //set info for padding
  3063. var paddingAbsoluteX = _paddingX = padding.l + padding.r;
  3064. var paddingAbsoluteY = _paddingY = padding.t + padding.b;
  3065. paddingAbsoluteX *=
  3066. paddingAbsoluteY *= paddingAbsolute ? 1 : 0;
  3067. padding.c = checkCacheTRBL(padding, _cssPaddingCache);
  3068. //set info for border
  3069. _borderX = border.l + border.r;
  3070. _borderY = border.t + border.b;
  3071. border.c = checkCacheTRBL(border, _cssBorderCache);
  3072. //set info for margin
  3073. _marginX = margin.l + margin.r;
  3074. _marginY = margin.t + margin.b;
  3075. margin.c = checkCacheTRBL(margin, _cssMarginCache);
  3076. //set info for css max value
  3077. cssMaxValue.ih = parseToZeroOrNumber(cssMaxValue.h); //ih = integer height
  3078. cssMaxValue.iw = parseToZeroOrNumber(cssMaxValue.w); //iw = integer width
  3079. cssMaxValue.ch = cssMaxValue.h.indexOf('px') > -1; //ch = correct height
  3080. cssMaxValue.cw = cssMaxValue.w.indexOf('px') > -1; //cw = correct width
  3081. cssMaxValue.c = checkCacheDouble(cssMaxValue, _cssMaxValueCache, force);
  3082. //refresh cache
  3083. _cssDirectionCache = cssDirection;
  3084. _cssBoxSizingCache = boxSizing;
  3085. _widthAutoCache = widthAuto;
  3086. _heightAutoCache = heightAuto;
  3087. _cssPaddingCache = padding;
  3088. _cssBorderCache = border;
  3089. _cssMarginCache = margin;
  3090. _cssMaxValueCache = cssMaxValue;
  3091. //IEFix direction changed
  3092. if (cssDirectionChanged && _sizeAutoObserverAdded)
  3093. _sizeAutoObserverElement.css(_strFloat, isRTLRight);
  3094. //apply padding:
  3095. if (padding.c || cssDirectionChanged || paddingAbsoluteChanged || widthAutoChanged || heightAutoChanged || boxSizingChanged || sizeAutoCapableChanged) {
  3096. var paddingElementCSS = {};
  3097. var textareaCSS = {};
  3098. setTopRightBottomLeft(contentGlueElementCSS, _strMarginMinus, [-padding.t, -padding.r, -padding.b, -padding.l]);
  3099. if (paddingAbsolute) {
  3100. setTopRightBottomLeft(paddingElementCSS, _strEmpty, [padding.t, padding.r, padding.b, padding.l]);
  3101. if (_isTextarea)
  3102. setTopRightBottomLeft(textareaCSS, _strPaddingMinus);
  3103. else
  3104. setTopRightBottomLeft(contentElementCSS, _strPaddingMinus);
  3105. }
  3106. else {
  3107. setTopRightBottomLeft(paddingElementCSS, _strEmpty);
  3108. if (_isTextarea)
  3109. setTopRightBottomLeft(textareaCSS, _strPaddingMinus, [padding.t, padding.r, padding.b, padding.l]);
  3110. else
  3111. setTopRightBottomLeft(contentElementCSS, _strPaddingMinus, [padding.t, padding.r, padding.b, padding.l]);
  3112. }
  3113. _paddingElement.css(paddingElementCSS);
  3114. _targetElement.css(textareaCSS);
  3115. }
  3116. //viewport size is padding container because it never has padding, margin and a border.
  3117. _viewportSize = getViewportSize();
  3118. //update Textarea
  3119. var textareaSize = _isTextarea ? textareaUpdate() : false;
  3120. //fix height auto / width auto in cooperation with current padding & boxSizing behavior:
  3121. if (heightAuto && (heightAutoChanged || paddingAbsoluteChanged || boxSizingChanged || cssMaxValue.c || padding.c || border.c)) {
  3122. //if (cssMaxValue.ch)
  3123. contentElementCSS[_strMaxMinus + _strHeight] =
  3124. (cssMaxValue.ch ? (cssMaxValue.ih - paddingAbsoluteY + (_isBorderBox ? -_borderY : _paddingY))
  3125. : _strEmpty);
  3126. contentElementCSS[_strHeight] = _strAuto;
  3127. }
  3128. else if (heightAutoChanged || paddingAbsoluteChanged) {
  3129. contentElementCSS[_strMaxMinus + _strHeight] = _strEmpty;
  3130. contentElementCSS[_strHeight] = _strHundredPercent;
  3131. }
  3132. if (widthAuto && (widthAutoChanged || paddingAbsoluteChanged || boxSizingChanged || cssMaxValue.c || padding.c || border.c || cssDirectionChanged)) {
  3133. //if (cssMaxValue.cw)
  3134. contentElementCSS[_strMaxMinus + _strWidth] =
  3135. (cssMaxValue.cw ? (cssMaxValue.iw - paddingAbsoluteX + (_isBorderBox ? -_borderX : _paddingX)) +
  3136. (_nativeScrollbarIsOverlaid.y /*&& _hasOverflowCache.y && widthAuto */ ? _overlayScrollbarDummySize.y : 0)
  3137. : _strEmpty);
  3138. contentElementCSS[_strWidth] = _strAuto;
  3139. contentGlueElementCSS[_strMaxMinus + _strWidth] = _strHundredPercent; //IE Fix
  3140. }
  3141. else if (widthAutoChanged || paddingAbsoluteChanged) {
  3142. contentElementCSS[_strMaxMinus + _strWidth] = _strEmpty;
  3143. contentElementCSS[_strWidth] = _strHundredPercent;
  3144. contentElementCSS[_strFloat] = _strEmpty;
  3145. contentGlueElementCSS[_strMaxMinus + _strWidth] = _strEmpty; //IE Fix
  3146. }
  3147. if (widthAuto) {
  3148. if (!cssMaxValue.cw)
  3149. contentElementCSS[_strMaxMinus + _strWidth] = _strEmpty;
  3150. contentGlueElementCSS[_strWidth] = _isTextarea && textareaDynWidth ? textareaSize._dynamicWidth : _strAuto;
  3151. contentElementCSS[_strWidth] = _strAuto;
  3152. contentElementCSS[_strFloat] = isRTLRight;
  3153. }
  3154. else {
  3155. contentGlueElementCSS[_strWidth] = _strEmpty;
  3156. }
  3157. if (heightAuto) {
  3158. if (!cssMaxValue.ch)
  3159. contentElementCSS[_strMaxMinus + _strHeight] = _strEmpty;
  3160. //fix dyn height collapse bug: (doesn't works for width!)
  3161. //contentGlueElementCSS[_strHeight] = _isTextarea && textareaDynHeight ? textareaSize._dynamicHeight : _strAuto;
  3162. contentGlueElementCSS[_strHeight] = _isTextarea ? textareaDynHeight ? textareaSize._dynamicHeight : _strAuto : _contentElementNative[LEXICON.cH];
  3163. }
  3164. else {
  3165. contentGlueElementCSS[_strHeight] = _strEmpty;
  3166. }
  3167. if (sizeAutoCapable)
  3168. _contentGlueElement.css(contentGlueElementCSS);
  3169. _contentElement.css(contentElementCSS);
  3170. //CHECKPOINT HERE ~
  3171. contentElementCSS = {};
  3172. contentGlueElementCSS = {};
  3173. //if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true
  3174. if (hostSizeChanged || contentSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || cssMaxValue.c || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged || force) {
  3175. var strOverflow = 'overflow';
  3176. var strOverflowX = strOverflow + '-x';
  3177. var strOverflowY = strOverflow + '-y';
  3178. var strHidden = 'hidden';
  3179. var strVisible = 'visible';
  3180. //decide whether the content overflow must get hidden for correct overflow measuring, it !MUST! be always hidden if the height is auto
  3181. var hideOverflow4CorrectMeasuring = _restrictedMeasuring ?
  3182. (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) || //it must be hidden if native scrollbars are overlaid
  3183. (_viewportSize.w < _nativeScrollbarMinSize.y || _viewportSize.h < _nativeScrollbarMinSize.x) || //it must be hidden if host-element is too small
  3184. heightAuto || displayIsHiddenChanged //it must be hidden if height is auto or display was change
  3185. : heightAuto; //if there is not the restricted Measuring bug, it must be hidden if the height is auto
  3186. //Reset the viewport (very important for natively overlaid scrollbars and zoom change
  3187. //don't change the overflow prop as it is very expensive and affects performance !A LOT!
  3188. var viewportElementResetCSS = { };
  3189. var resetXTmp = _hasOverflowCache.y && _hideOverflowCache.ys && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.y ? _viewportElement.css(isRTLLeft) : -_nativeScrollbarSize.y) : 0;
  3190. var resetBottomTmp = _hasOverflowCache.x && _hideOverflowCache.xs && !ignoreOverlayScrollbarHiding ? (_nativeScrollbarIsOverlaid.x ? _viewportElement.css(_strBottom) : -_nativeScrollbarSize.x) : 0;
  3191. setTopRightBottomLeft(viewportElementResetCSS, _strEmpty);
  3192. _viewportElement.css(viewportElementResetCSS);
  3193. if(hideOverflow4CorrectMeasuring)
  3194. _contentElement.css(strOverflow, strHidden);
  3195. //measure several sizes:
  3196. var contentMeasureElement = getContentMeasureElement();
  3197. //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
  3198. var contentMeasureElementGuaranty = _restrictedMeasuring && !hideOverflow4CorrectMeasuring ? _viewportElementNative : contentMeasureElement;
  3199. var contentSize = {
  3200. //use clientSize because natively overlaidScrollbars add borders
  3201. w: _isTextarea && textareaSize ? (textareaDynWidth ? textareaSize._dynamicWidth : textareaSize._originalWidth) : contentMeasureElement[LEXICON.cW],
  3202. h: _isTextarea && textareaSize ? (textareaDynHeight ? textareaSize._dynamicHeight : textareaSize._originalHeight) : contentMeasureElement[LEXICON.cH]
  3203. };
  3204. var scrollSize = {
  3205. w: MATH.max(contentMeasureElement[LEXICON.sW], contentMeasureElementGuaranty[LEXICON.sW]),
  3206. h: MATH.max(contentMeasureElement[LEXICON.sH], contentMeasureElementGuaranty[LEXICON.sH])
  3207. };
  3208. //apply the correct viewport style and measure viewport size
  3209. viewportElementResetCSS[_strBottom] = wasHeightAuto ? _strEmpty : resetBottomTmp;
  3210. viewportElementResetCSS[isRTLLeft] = wasWidthAuto ? _strEmpty : resetXTmp;
  3211. _viewportElement.css(viewportElementResetCSS);
  3212. _viewportSize = getViewportSize();
  3213. //measure and correct several sizes
  3214. var hostSize = getHostSize();
  3215. var contentGlueSize = {
  3216. //client/scrollSize + AbsolutePadding -> because padding is only applied to the paddingElement if its absolute, so you have to add it manually
  3217. //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
  3218. w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostSize.w),
  3219. h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostSize.h)
  3220. };
  3221. contentGlueSize.c = checkCacheDouble(contentGlueSize, _contentGlueSizeCache, force);
  3222. _contentGlueSizeCache = contentGlueSize;
  3223. //apply correct contentGlue size
  3224. if (sizeAutoCapable) {
  3225. //size contentGlue correctly to make sure the element has correct size if the sizing switches to auto
  3226. if (contentGlueSize.c || (heightAuto || widthAuto)) {
  3227. contentGlueElementCSS[_strWidth] = contentGlueSize.w;
  3228. contentGlueElementCSS[_strHeight] = contentGlueSize.h;
  3229. //textarea-sizes are already calculated correctly at this point
  3230. if(!_isTextarea) {
  3231. contentSize = {
  3232. //use clientSize because natively overlaidScrollbars add borders
  3233. w: contentMeasureElement[LEXICON.cW],
  3234. h: contentMeasureElement[LEXICON.cH]
  3235. };
  3236. }
  3237. }
  3238. var textareaCoverCSS = {};
  3239. var setContentGlueElementCSSfunction = function(horizontal) {
  3240. var scrollbarVars = getScrollbarVars(horizontal);
  3241. var wh = scrollbarVars._w_h;
  3242. var strWH = scrollbarVars._width_height;
  3243. var autoSize = horizontal ? widthAuto : heightAuto;
  3244. var borderSize = horizontal ? _borderX : _borderY;
  3245. var paddingSize = horizontal ? _paddingX : _paddingY;
  3246. var marginSize = horizontal ? _marginX : _marginY;
  3247. var maxSize = contentGlueElementCSS[strWH] + (_isBorderBox ? borderSize : -paddingSize);
  3248. //make contentGlue size -1 if element is not auto sized, to make sure that a resize event happens when the element shrinks
  3249. if (!autoSize || (!autoSize && border.c))
  3250. contentGlueElementCSS[strWH] = hostSize[wh] - (_isBorderBox ? 0 : paddingSize + borderSize) - 1 - marginSize;
  3251. //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
  3252. if (autoSize && cssMaxValue['c' + wh] && cssMaxValue['i' + wh] === maxSize)
  3253. contentGlueElementCSS[strWH] = maxSize + (_isBorderBox ? 0 : paddingSize) + 1;
  3254. //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)
  3255. if (autoSize && (contentSize[wh] < _viewportSize[wh]) && (horizontal ? (_isTextarea ? !textareaAutoWrapping : false) : true)) {
  3256. if (_isTextarea)
  3257. textareaCoverCSS[strWH] = parseToZeroOrNumber(_textareaCoverElement.css(strWH)) - 1;
  3258. contentGlueElementCSS[strWH] -= 1;
  3259. }
  3260. //make sure content glue size is at least 1
  3261. if (contentSize[wh] > 0)
  3262. contentGlueElementCSS[strWH] = MATH.max(1, contentGlueElementCSS[strWH]);
  3263. };
  3264. setContentGlueElementCSSfunction(true);
  3265. setContentGlueElementCSSfunction(false);
  3266. if (_isTextarea)
  3267. _textareaCoverElement.css(textareaCoverCSS);
  3268. _contentGlueElement.css(contentGlueElementCSS);
  3269. }
  3270. if (widthAuto)
  3271. contentElementCSS[_strWidth] = _strHundredPercent;
  3272. if (widthAuto && !_isBorderBox && !_mutationObserversConnected)
  3273. contentElementCSS[_strFloat] = 'none';
  3274. //apply and reset content style
  3275. _contentElement.css(contentElementCSS);
  3276. contentElementCSS = {};
  3277. //measure again, but this time all correct sizes:
  3278. var contentScrollSize = {
  3279. w: MATH.max(contentMeasureElement[LEXICON.sW], contentMeasureElementGuaranty[LEXICON.sW]),
  3280. h: MATH.max(contentMeasureElement[LEXICON.sH], contentMeasureElementGuaranty[LEXICON.sH])
  3281. };
  3282. contentScrollSize.c = contentSizeChanged = checkCacheDouble(contentScrollSize, _contentScrollSizeCache, force);
  3283. _contentScrollSizeCache = contentScrollSize;
  3284. //remove overflow hidden to restore overflow
  3285. if(hideOverflow4CorrectMeasuring)
  3286. _contentElement.css(strOverflow, _strEmpty);
  3287. //refresh viewport size after correct measuring
  3288. _viewportSize = getViewportSize();
  3289. hostSize = getHostSize();
  3290. hostSizeChanged = checkCacheDouble(hostSize, _hostSizeCache);
  3291. _hostSizeCache = hostSize;
  3292. var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0);
  3293. var previousOverflow = _overflowAmountCache;
  3294. var overflowBehaviorIsVS = { };
  3295. var overflowBehaviorIsVH = { };
  3296. var overflowBehaviorIsS = { };
  3297. var overflowAmount = { };
  3298. var hasOverflow = { };
  3299. var hideOverflow = { };
  3300. var canScroll = { };
  3301. var viewportRect = _paddingElementNative.getBoundingClientRect();
  3302. var setOverflowVariables = function(horizontal) {
  3303. var scrollbarVars = getScrollbarVars(horizontal);
  3304. var scrollbarVarsInverted = getScrollbarVars(!horizontal);
  3305. var xyI = scrollbarVarsInverted._x_y;
  3306. var xy = scrollbarVars._x_y;
  3307. var wh = scrollbarVars._w_h;
  3308. var widthHeight = scrollbarVars._width_height;
  3309. var scrollMax = _strScroll + scrollbarVars._Left_Top + 'Max';
  3310. var fractionalOverflowAmount = viewportRect[widthHeight] ? MATH.abs(viewportRect[widthHeight] - _viewportSize[wh]) : 0;
  3311. overflowBehaviorIsVS[xy] = overflowBehavior[xy] === 'v-s';
  3312. overflowBehaviorIsVH[xy] = overflowBehavior[xy] === 'v-h';
  3313. overflowBehaviorIsS[xy] = overflowBehavior[xy] === 's';
  3314. overflowAmount[xy] = MATH.max(0, MATH.round((contentScrollSize[wh] - _viewportSize[wh]) * 100) / 100);
  3315. overflowAmount[xy] *= (hideOverflowForceTextarea || (_viewportElementNative[scrollMax] === 0 && fractionalOverflowAmount > 0 && fractionalOverflowAmount < 1)) ? 0 : 1;
  3316. hasOverflow[xy] = overflowAmount[xy] > 0;
  3317. //hideOverflow:
  3318. //x || y : true === overflow is hidden by "overflow: scroll" OR "overflow: hidden"
  3319. //xs || ys : true === overflow is hidden by "overflow: scroll"
  3320. hideOverflow[xy] = overflowBehaviorIsVS[xy] || overflowBehaviorIsVH[xy] ? (hasOverflow[xyI] && !overflowBehaviorIsVS[xyI] && !overflowBehaviorIsVH[xyI]) : hasOverflow[xy];
  3321. hideOverflow[xy + 's'] = hideOverflow[xy] ? (overflowBehaviorIsS[xy] || overflowBehaviorIsVS[xy]) : false;
  3322. canScroll[xy] = hasOverflow[xy] && hideOverflow[xy + 's'];
  3323. };
  3324. setOverflowVariables(true);
  3325. setOverflowVariables(false);
  3326. overflowAmount.c = checkCacheDouble(overflowAmount, _overflowAmountCache, _strX, _strY, force);
  3327. _overflowAmountCache = overflowAmount;
  3328. hasOverflow.c = checkCacheDouble(hasOverflow, _hasOverflowCache, _strX, _strY, force);
  3329. _hasOverflowCache = hasOverflow;
  3330. hideOverflow.c = checkCacheDouble(hideOverflow, _hideOverflowCache, _strX, _strY, force);
  3331. _hideOverflowCache = hideOverflow;
  3332. //if native scrollbar is overlay at x OR y axis, prepare DOM
  3333. if (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) {
  3334. var borderDesign = 'px solid transparent';
  3335. var contentArrangeElementCSS = { };
  3336. var arrangeContent = { };
  3337. var arrangeChanged = force;
  3338. var setContentElementCSS;
  3339. if (hasOverflow.x || hasOverflow.y) {
  3340. arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty;
  3341. arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty;
  3342. arrangeChanged = checkCacheSingle(arrangeContent, _arrangeContentSizeCache, force);
  3343. _arrangeContentSizeCache = arrangeContent;
  3344. }
  3345. if (hasOverflow.c || hideOverflow.c || contentScrollSize.c || cssDirectionChanged || widthAutoChanged || heightAutoChanged || widthAuto || heightAuto || ignoreOverlayScrollbarHidingChanged) {
  3346. contentElementCSS[_strMarginMinus + isRTLRight] = contentElementCSS[_strBorderMinus + isRTLRight] = _strEmpty;
  3347. setContentElementCSS = function(horizontal) {
  3348. var scrollbarVars = getScrollbarVars(horizontal);
  3349. var scrollbarVarsInverted = getScrollbarVars(!horizontal);
  3350. var xy = scrollbarVars._x_y;
  3351. var strDirection = horizontal ? _strBottom : isRTLLeft;
  3352. var invertedAutoSize = horizontal ? heightAuto : widthAuto;
  3353. if (_nativeScrollbarIsOverlaid[xy] && hasOverflow[xy] && hideOverflow[xy + 's']) {
  3354. contentElementCSS[_strMarginMinus + strDirection] = invertedAutoSize ? (ignoreOverlayScrollbarHiding ? _strEmpty : _overlayScrollbarDummySize[xy]) : _strEmpty;
  3355. contentElementCSS[_strBorderMinus + strDirection] = ((horizontal ? !invertedAutoSize : true) && !ignoreOverlayScrollbarHiding) ? (_overlayScrollbarDummySize[xy] + borderDesign) : _strEmpty;
  3356. }
  3357. else {
  3358. arrangeContent[scrollbarVarsInverted._w_h] =
  3359. contentElementCSS[_strMarginMinus + strDirection] =
  3360. contentElementCSS[_strBorderMinus + strDirection] = _strEmpty;
  3361. arrangeChanged = true;
  3362. }
  3363. };
  3364. setContentElementCSS(true);
  3365. setContentElementCSS(false);
  3366. }
  3367. if (ignoreOverlayScrollbarHiding) {
  3368. arrangeContent.w = arrangeContent.h = _strEmpty;
  3369. arrangeChanged = true;
  3370. }
  3371. if (arrangeChanged) {
  3372. contentArrangeElementCSS[_strWidth] = hideOverflow.y ? arrangeContent.w : _strEmpty;
  3373. contentArrangeElementCSS[_strHeight] = hideOverflow.x ? arrangeContent.h : _strEmpty;
  3374. if (!_contentArrangeElement) {
  3375. _contentArrangeElement = FRAMEWORK(generateDiv(_classNameContentArrangeElement));
  3376. _viewportElement.prepend(_contentArrangeElement);
  3377. }
  3378. _contentArrangeElement.css(contentArrangeElementCSS);
  3379. }
  3380. _contentElement.css(contentElementCSS);
  3381. }
  3382. var viewportElementCSS = {};
  3383. var paddingElementCSS = {};
  3384. var setViewportCSS;
  3385. if (hostSizeChanged || hasOverflow.c || hideOverflow.c || contentScrollSize.c || overflowBehaviorChanged || boxSizingChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged || clipAlwaysChanged || heightAutoChanged) {
  3386. viewportElementCSS[isRTLRight] = _strEmpty;
  3387. setViewportCSS = function(horizontal) {
  3388. var scrollbarVars = getScrollbarVars(horizontal);
  3389. var scrollbarVarsInverted = getScrollbarVars(!horizontal);
  3390. var xy = scrollbarVars._x_y;
  3391. var XY = scrollbarVars._X_Y;
  3392. var strDirection = horizontal ? _strBottom : isRTLLeft;
  3393. var reset = function () {
  3394. viewportElementCSS[strDirection] = _strEmpty;
  3395. _contentBorderSize[scrollbarVarsInverted._w_h] = 0;
  3396. };
  3397. if (hasOverflow[xy] && hideOverflow[xy + 's']) {
  3398. viewportElementCSS[strOverflow + XY] = _strScroll;
  3399. if (!ignoreOverlayScrollbarHiding) {
  3400. viewportElementCSS[strDirection] = -(_nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[xy] : _nativeScrollbarSize[xy]);
  3401. _contentBorderSize[scrollbarVarsInverted._w_h] = _nativeScrollbarIsOverlaid[xy] ? _overlayScrollbarDummySize[scrollbarVarsInverted._x_y] : 0;
  3402. }
  3403. else
  3404. reset();
  3405. } else {
  3406. viewportElementCSS[strOverflow + XY] = _strEmpty;
  3407. reset();
  3408. }
  3409. };
  3410. setViewportCSS(true);
  3411. setViewportCSS(false);
  3412. // if the scroll container is too small and if there is any overflow with not overlay scrollbar, make viewport element greater in size (Firefox hide Scrollbars fix)
  3413. // because firefox starts hiding scrollbars on too small elements
  3414. // with this behavior the overflow calculation may be incorrect or the scrollbars would appear suddenly
  3415. // https://bugzilla.mozilla.org/show_bug.cgi?id=292284
  3416. if ((_viewportSize.h < _nativeScrollbarMinSize.x || _viewportSize.w < _nativeScrollbarMinSize.y)
  3417. && ((hasOverflow.x && hideOverflow.x && !_nativeScrollbarIsOverlaid.x) || (hasOverflow.y && hideOverflow.y && !_nativeScrollbarIsOverlaid.y))) {
  3418. viewportElementCSS[_strPaddingMinus + _strTop] = _nativeScrollbarMinSize.x;
  3419. viewportElementCSS[_strMarginMinus + _strTop] = -_nativeScrollbarMinSize.x;
  3420. viewportElementCSS[_strPaddingMinus + isRTLRight] = _nativeScrollbarMinSize.y;
  3421. viewportElementCSS[_strMarginMinus + isRTLRight] = -_nativeScrollbarMinSize.y;
  3422. }
  3423. else {
  3424. viewportElementCSS[_strPaddingMinus + _strTop] =
  3425. viewportElementCSS[_strMarginMinus + _strTop] =
  3426. viewportElementCSS[_strPaddingMinus + isRTLRight] =
  3427. viewportElementCSS[_strMarginMinus + isRTLRight] = _strEmpty;
  3428. }
  3429. viewportElementCSS[_strPaddingMinus + isRTLLeft] =
  3430. viewportElementCSS[_strMarginMinus + isRTLLeft] = _strEmpty;
  3431. //if there is any overflow (x OR y axis) and this overflow shall be hidden, make overflow hidden, else overflow visible
  3432. if ((hasOverflow.x && hideOverflow.x) || (hasOverflow.y && hideOverflow.y) || hideOverflowForceTextarea) {
  3433. //only hide if is Textarea
  3434. if (_isTextarea && hideOverflowForceTextarea) {
  3435. paddingElementCSS[strOverflowX] =
  3436. paddingElementCSS[strOverflowY] = strHidden;
  3437. }
  3438. }
  3439. else {
  3440. if (!clipAlways || (overflowBehaviorIsVH.x || overflowBehaviorIsVS.x || overflowBehaviorIsVH.y || overflowBehaviorIsVS.y)) {
  3441. //only un-hide if Textarea
  3442. if (_isTextarea) {
  3443. paddingElementCSS[strOverflowX] =
  3444. paddingElementCSS[strOverflowY] = _strEmpty;
  3445. }
  3446. viewportElementCSS[strOverflowX] =
  3447. viewportElementCSS[strOverflowY] = strVisible;
  3448. }
  3449. }
  3450. _paddingElement.css(paddingElementCSS);
  3451. _viewportElement.css(viewportElementCSS);
  3452. viewportElementCSS = { };
  3453. //force soft redraw in webkit because without the scrollbars will may appear because DOM wont be redrawn under special conditions
  3454. if ((hasOverflow.c || boxSizingChanged || widthAutoChanged || heightAutoChanged) && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) {
  3455. var elementStyle = _contentElementNative[LEXICON.s];
  3456. var dump;
  3457. elementStyle.webkitTransform = 'scale(1)';
  3458. elementStyle.display = 'run-in';
  3459. dump = _contentElementNative[LEXICON.oH];
  3460. elementStyle.display = _strEmpty; //|| dump; //use dump to prevent it from deletion if minify
  3461. elementStyle.webkitTransform = _strEmpty;
  3462. }
  3463. /*
  3464. //force hard redraw in webkit if native overlaid scrollbars shall appear
  3465. if (ignoreOverlayScrollbarHidingChanged && ignoreOverlayScrollbarHiding) {
  3466. _hostElement.hide();
  3467. var dump = _hostElementNative[LEXICON.oH];
  3468. _hostElement.show();
  3469. }
  3470. */
  3471. }
  3472. //change to direction RTL and width auto Bugfix in Webkit
  3473. //without this fix, the DOM still thinks the scrollbar is LTR and thus the content is shifted to the left
  3474. contentElementCSS = {};
  3475. if (cssDirectionChanged || widthAutoChanged || heightAutoChanged) {
  3476. if (_isRTL && widthAuto) {
  3477. var floatTmp = _contentElement.css(_strFloat);
  3478. var posLeftWithoutFloat = MATH.round(_contentElement.css(_strFloat, _strEmpty).css(_strLeft, _strEmpty).position().left);
  3479. _contentElement.css(_strFloat, floatTmp);
  3480. var posLeftWithFloat = MATH.round(_contentElement.position().left);
  3481. if (posLeftWithoutFloat !== posLeftWithFloat)
  3482. contentElementCSS[_strLeft] = posLeftWithoutFloat;
  3483. }
  3484. else {
  3485. contentElementCSS[_strLeft] = _strEmpty;
  3486. }
  3487. }
  3488. _contentElement.css(contentElementCSS);
  3489. //handle scroll position
  3490. if (_isTextarea && contentSizeChanged) {
  3491. var textareaInfo = getTextareaInfo();
  3492. if (textareaInfo) {
  3493. var textareaRowsChanged = _textareaInfoCache === undefined ? true : textareaInfo._rows !== _textareaInfoCache._rows;
  3494. var cursorRow = textareaInfo._cursorRow;
  3495. var cursorCol = textareaInfo._cursorColumn;
  3496. var widestRow = textareaInfo._widestRow;
  3497. var lastRow = textareaInfo._rows;
  3498. var lastCol = textareaInfo._columns;
  3499. var cursorPos = textareaInfo._cursorPosition;
  3500. var cursorMax = textareaInfo._cursorMax;
  3501. var cursorIsLastPosition = (cursorPos >= cursorMax && _textareaHasFocus);
  3502. var textareaScrollAmount = {
  3503. x: (!textareaAutoWrapping && (cursorCol === lastCol && cursorRow === widestRow)) ? _overflowAmountCache.x : -1,
  3504. y: (textareaAutoWrapping ? cursorIsLastPosition || textareaRowsChanged && (previousOverflow !== undefined ? (currScroll.y === previousOverflow.y) : false) : (cursorIsLastPosition || textareaRowsChanged) && cursorRow === lastRow) ? _overflowAmountCache.y : -1
  3505. };
  3506. 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.
  3507. currScroll.y = textareaScrollAmount.y > -1 ? textareaScrollAmount.y : currScroll.y;
  3508. }
  3509. _textareaInfoCache = textareaInfo;
  3510. }
  3511. if (_isRTL && _rtlScrollBehavior.i && _nativeScrollbarIsOverlaid.y && hasOverflow.x && _normalizeRTLCache)
  3512. currScroll.x += _contentBorderSize.w || 0;
  3513. if(widthAuto)
  3514. _hostElement[_strScrollLeft](0);
  3515. if(heightAuto)
  3516. _hostElement[_strScrollTop](0);
  3517. _viewportElement[_strScrollLeft](currScroll.x)[_strScrollTop](currScroll.y);
  3518. //scrollbars management:
  3519. var scrollbarsVisibilityVisible = scrollbarsVisibility === 'v';
  3520. var scrollbarsVisibilityHidden = scrollbarsVisibility === 'h';
  3521. var scrollbarsVisibilityAuto = scrollbarsVisibility === 'a';
  3522. var showScrollbarH = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, true, true, canScroll.x);
  3523. var showScrollbarV = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, false, true, canScroll.y);
  3524. var hideScrollbarH = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, true, false, canScroll.x);
  3525. var hideScrollbarV = COMPATIBILITY.bind(refreshScrollbarAppearance, 0, false, false, canScroll.y);
  3526. //manage class name which indicates scrollable overflow
  3527. if (hideOverflow.x || hideOverflow.y)
  3528. addClass(_hostElement, _classNameHostOverflow);
  3529. else
  3530. removeClass(_hostElement, _classNameHostOverflow);
  3531. if (hideOverflow.x)
  3532. addClass(_hostElement, _classNameHostOverflowX);
  3533. else
  3534. removeClass(_hostElement, _classNameHostOverflowX);
  3535. if (hideOverflow.y)
  3536. addClass(_hostElement, _classNameHostOverflowY);
  3537. else
  3538. removeClass(_hostElement, _classNameHostOverflowY);
  3539. //add or remove rtl class name for styling purposes
  3540. if (cssDirectionChanged) {
  3541. if (_isRTL)
  3542. addClass(_hostElement, _classNameHostRTL);
  3543. else
  3544. removeClass(_hostElement, _classNameHostRTL);
  3545. }
  3546. //manage the resize feature (CSS3 resize "polyfill" for this plugin)
  3547. if (_isBody)
  3548. addClass(_hostElement, _classNameHostResizeDisabled);
  3549. if (resizeChanged) {
  3550. var addCornerEvents = function () { _scrollbarCornerElement.on(_strMouseTouchDownEvent, _resizeOnMouseTouchDown); };
  3551. var removeCornerEvents = function () { _scrollbarCornerElement.off(_strMouseTouchDownEvent, _resizeOnMouseTouchDown); };
  3552. removeClass(_scrollbarCornerElement, [
  3553. _classNameHostResizeDisabled,
  3554. _classNameScrollbarCornerResize,
  3555. _classNameScrollbarCornerResizeB,
  3556. _classNameScrollbarCornerResizeH,
  3557. _classNameScrollbarCornerResizeV].join(_strSpace));
  3558. if (_resizeNone) {
  3559. addClass(_hostElement, _classNameHostResizeDisabled);
  3560. removeCornerEvents();
  3561. }
  3562. else {
  3563. addClass(_scrollbarCornerElement, _classNameScrollbarCornerResize);
  3564. if (_resizeBoth)
  3565. addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeB);
  3566. else if (_resizeHorizontal)
  3567. addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeH);
  3568. else if (_resizeVertical)
  3569. addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV);
  3570. removeCornerEvents();
  3571. addCornerEvents();
  3572. }
  3573. }
  3574. //manage the scrollbars general visibility + the scrollbar interactivity (unusable class name)
  3575. if (scrollbarsVisibilityChanged || overflowBehaviorChanged || hideOverflow.c || hasOverflow.c || ignoreOverlayScrollbarHidingChanged) {
  3576. if (ignoreOverlayScrollbarHiding) {
  3577. if (ignoreOverlayScrollbarHidingChanged) {
  3578. removeClass(_hostElement, _classNameHostScrolling);
  3579. if (ignoreOverlayScrollbarHiding) {
  3580. hideScrollbarH();
  3581. hideScrollbarV();
  3582. }
  3583. }
  3584. }
  3585. else if (scrollbarsVisibilityAuto) {
  3586. if (canScroll.x)
  3587. showScrollbarH();
  3588. else
  3589. hideScrollbarH();
  3590. if (canScroll.y)
  3591. showScrollbarV();
  3592. else
  3593. hideScrollbarV();
  3594. }
  3595. else if (scrollbarsVisibilityVisible) {
  3596. showScrollbarH();
  3597. showScrollbarV();
  3598. }
  3599. else if (scrollbarsVisibilityHidden) {
  3600. hideScrollbarH();
  3601. hideScrollbarV();
  3602. }
  3603. }
  3604. //manage the scrollbars auto hide feature (auto hide them after specific actions)
  3605. if (scrollbarsAutoHideChanged || ignoreOverlayScrollbarHidingChanged) {
  3606. if (_scrollbarsAutoHideLeave || _scrollbarsAutoHideMove) {
  3607. setupHostMouseTouchEvents(true);
  3608. setupHostMouseTouchEvents();
  3609. }
  3610. else {
  3611. setupHostMouseTouchEvents(true);
  3612. }
  3613. if (_scrollbarsAutoHideNever)
  3614. refreshScrollbarsAutoHide(true);
  3615. else
  3616. refreshScrollbarsAutoHide(false, true);
  3617. }
  3618. //manage scrollbars handle length & offset - don't remove!
  3619. if (hostSizeChanged || overflowAmount.c || heightAutoChanged || widthAutoChanged || resizeChanged || boxSizingChanged || paddingAbsoluteChanged || ignoreOverlayScrollbarHidingChanged || cssDirectionChanged) {
  3620. refreshScrollbarHandleLength(true);
  3621. refreshScrollbarHandleOffset(true);
  3622. refreshScrollbarHandleLength(false);
  3623. refreshScrollbarHandleOffset(false);
  3624. }
  3625. //manage interactivity
  3626. if (scrollbarsClickScrollingChanged)
  3627. refreshScrollbarsInteractive(true, scrollbarsClickScrolling);
  3628. if (scrollbarsDragScrollingChanged)
  3629. refreshScrollbarsInteractive(false, scrollbarsDragScrolling);
  3630. //callbacks:
  3631. if (cssDirectionChanged) {
  3632. dispatchCallback("onDirectionChanged", {
  3633. isRTL: _isRTL,
  3634. dir: cssDirection
  3635. });
  3636. }
  3637. if (hostSizeChanged) {
  3638. dispatchCallback("onHostSizeChanged", {
  3639. width: _hostSizeCache.w,
  3640. height: _hostSizeCache.h
  3641. });
  3642. }
  3643. if (contentSizeChanged) {
  3644. dispatchCallback("onContentSizeChanged", {
  3645. width: _contentScrollSizeCache.w,
  3646. height: _contentScrollSizeCache.h
  3647. });
  3648. }
  3649. if (hasOverflow.c || hideOverflow.c) {
  3650. dispatchCallback("onOverflowChanged", {
  3651. x: hasOverflow.x,
  3652. y: hasOverflow.y,
  3653. xScrollable: hideOverflow.xs,
  3654. yScrollable: hideOverflow.ys,
  3655. clipped: hideOverflow.x || hideOverflow.y
  3656. });
  3657. }
  3658. if (overflowAmount.c) {
  3659. dispatchCallback("onOverflowAmountChanged", {
  3660. x: overflowAmount.x,
  3661. y: overflowAmount.y
  3662. });
  3663. }
  3664. }
  3665. //fix body min size
  3666. if (_isBody && (_hasOverflowCache.c || _bodyMinSizeCache.c)) {
  3667. //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.
  3668. if (!_bodyMinSizeCache.f)
  3669. bodyMinSizeChanged();
  3670. if (_nativeScrollbarIsOverlaid.y && _hasOverflowCache.x)
  3671. _contentElement.css(_strMinMinus + _strWidth, _bodyMinSizeCache.w + _overlayScrollbarDummySize.y);
  3672. if (_nativeScrollbarIsOverlaid.x && _hasOverflowCache.y)
  3673. _contentElement.css(_strMinMinus + _strHeight, _bodyMinSizeCache.h + _overlayScrollbarDummySize.x);
  3674. _bodyMinSizeCache.c = false;
  3675. }
  3676. unfreezeResizeObserver(_sizeObserverElement);
  3677. unfreezeResizeObserver(_sizeAutoObserverElement);
  3678. dispatchCallback("onUpdated", { forced: force });
  3679. }
  3680. //==== Options ====//
  3681. /**
  3682. * Sets new options but doesn't call the update method.
  3683. * @param newOptions The object which contains the new options.
  3684. */
  3685. function setOptions(newOptions) {
  3686. _currentOptions = extendDeep({}, _currentOptions, _pluginsOptions._validate(newOptions, _pluginsOptions._template, true));
  3687. _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, _pluginsOptions._validate(newOptions, _pluginsOptions._template, false, true));
  3688. }
  3689. //==== Structure ====//
  3690. /**
  3691. * Builds or destroys the wrapper and helper DOM elements.
  3692. * @param destroy Indicates whether the DOM shall be build or destroyed.
  3693. */
  3694. function setupStructureDOM(destroy) {
  3695. var adoptAttrs = _currentPreparedOptions.textarea.inheritedAttrs;
  3696. var adoptAttrsMap = { };
  3697. var applyAdoptedAttrs = function() {
  3698. var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement;
  3699. FRAMEWORK.each(adoptAttrsMap, function(k, v) {
  3700. if(type(v) == TYPES.s) {
  3701. if(k == LEXICON.c)
  3702. applyAdoptedAttrsElm.addClass(v);
  3703. else
  3704. applyAdoptedAttrsElm.attr(k, v);
  3705. }
  3706. });
  3707. };
  3708. var hostElementClassNames = [
  3709. _classNameHostElement,
  3710. _classNameHostTextareaElement,
  3711. _classNameHostResizeDisabled,
  3712. _classNameHostRTL,
  3713. _classNameHostScrollbarHorizontalHidden,
  3714. _classNameHostScrollbarVerticalHidden,
  3715. _classNameHostTransition,
  3716. _classNameHostScrolling,
  3717. _classNameHostOverflow,
  3718. _classNameHostOverflowX,
  3719. _classNameHostOverflowY,
  3720. _classNameThemeNone,
  3721. _classNameTextareaElement,
  3722. _classNameTextInherit,
  3723. _classNameCache].join(_strSpace);
  3724. adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(' ') : adoptAttrs;
  3725. if(type(adoptAttrs) == TYPES.a) {
  3726. FRAMEWORK.each(adoptAttrs, function(i, v) {
  3727. if(type(v) == TYPES.s)
  3728. adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v);
  3729. });
  3730. }
  3731. if(!destroy) {
  3732. if (_isTextarea) {
  3733. var hostElementCSS = {};
  3734. var parent = _targetElement.parent();
  3735. _isTextareaHostGenerated = !(parent.hasClass(_classNameHostTextareaElement) && parent.children()[LEXICON.l] === 1);
  3736. if (!_currentPreparedOptions.sizeAutoCapable) {
  3737. hostElementCSS[_strWidth] = _targetElement.css(_strWidth);
  3738. hostElementCSS[_strHeight] = _targetElement.css(_strHeight);
  3739. }
  3740. if(_isTextareaHostGenerated)
  3741. _targetElement.wrap(generateDiv(_classNameHostTextareaElement));
  3742. _hostElement = _targetElement.parent();
  3743. _hostElement.css(hostElementCSS)
  3744. .wrapInner(generateDiv(_classNameContentElement + _strSpace + _classNameTextInherit))
  3745. .wrapInner(generateDiv(_classNameViewportElement + _strSpace + _classNameTextInherit))
  3746. .wrapInner(generateDiv(_classNamePaddingElement + _strSpace + _classNameTextInherit));
  3747. _contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);
  3748. _viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);
  3749. _paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);
  3750. _textareaCoverElement = FRAMEWORK(generateDiv(_classNameTextareaCoverElement));
  3751. _contentElement.prepend(_textareaCoverElement);
  3752. addClass(_targetElement, _classNameTextareaElement + _strSpace + _classNameTextInherit);
  3753. if(_isTextareaHostGenerated)
  3754. applyAdoptedAttrs();
  3755. }
  3756. else {
  3757. _hostElement = _targetElement;
  3758. _hostElement.wrapInner(generateDiv(_classNameContentElement))
  3759. .wrapInner(generateDiv(_classNameViewportElement))
  3760. .wrapInner(generateDiv(_classNamePaddingElement));
  3761. _contentElement = findFirst(_hostElement, _strDot + _classNameContentElement);
  3762. _viewportElement = findFirst(_hostElement, _strDot + _classNameViewportElement);
  3763. _paddingElement = findFirst(_hostElement, _strDot + _classNamePaddingElement);
  3764. addClass(_targetElement, _classNameHostElement);
  3765. }
  3766. if (_nativeScrollbarStyling)
  3767. addClass(_viewportElement, _nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y ? _classNameViewportNativeScrollbarsOverlaid : _classNameViewportNativeScrollbarsInvisible);
  3768. if (_isBody)
  3769. addClass(_htmlElement, _classNameHTMLElement);
  3770. _sizeObserverElement = FRAMEWORK(generateDiv('os-resize-observer-host'));
  3771. _hostElement.prepend(_sizeObserverElement);
  3772. _sizeObserverElementNative = _sizeObserverElement[0];
  3773. _hostElementNative = _hostElement[0];
  3774. _paddingElementNative = _paddingElement[0];
  3775. _viewportElementNative = _viewportElement[0];
  3776. _contentElementNative = _contentElement[0];
  3777. }
  3778. else {
  3779. _contentElement.contents()
  3780. .unwrap()
  3781. .unwrap()
  3782. .unwrap();
  3783. removeClass(_hostElement, hostElementClassNames);
  3784. if (_isTextarea) {
  3785. _targetElement.removeAttr(LEXICON.s);
  3786. if(_isTextareaHostGenerated)
  3787. applyAdoptedAttrs();
  3788. removeClass(_targetElement, hostElementClassNames);
  3789. remove(_textareaCoverElement);
  3790. if(_isTextareaHostGenerated) {
  3791. _targetElement.unwrap();
  3792. remove(_hostElement);
  3793. }
  3794. else {
  3795. addClass(_hostElement, _classNameHostTextareaElement);
  3796. }
  3797. }
  3798. else {
  3799. removeClass(_targetElement, _classNameHostElement);
  3800. }
  3801. if (_isBody)
  3802. removeClass(_htmlElement, _classNameHTMLElement);
  3803. remove(_sizeObserverElement);
  3804. }
  3805. }
  3806. /**
  3807. * Adds or removes all wrapper elements interactivity events.
  3808. * @param destroy Indicates whether the Events shall be added or removed.
  3809. */
  3810. function setupStructureEvents(destroy) {
  3811. var textareaKeyDownRestrictedKeyCodes = [
  3812. 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, //F1 to F12
  3813. 33, 34, //page up, page down
  3814. 37, 38, 39, 40, //left, up, right, down arrows
  3815. 16, 17, 18, 19, 20, 144 //Shift, Ctrl, Alt, Pause, CapsLock, NumLock
  3816. ];
  3817. var textareaKeyDownKeyCodesList = [ ];
  3818. var textareaUpdateIntervalID;
  3819. var scrollStopDelay = 175;
  3820. var scrollStopTimeoutId;
  3821. var strOnOff = destroy ? 'off' : 'on';
  3822. var updateTextarea;
  3823. var viewportOnScroll;
  3824. if(!destroy && _isTextarea) {
  3825. _textareaEvents = { };
  3826. updateTextarea = function(doClearInterval) {
  3827. textareaUpdate();
  3828. _base.update(_strAuto);
  3829. if(doClearInterval)
  3830. clearInterval(textareaUpdateIntervalID);
  3831. };
  3832. _textareaEvents[_strScroll] = function(event) {
  3833. _targetElement[_strScrollLeft](_rtlScrollBehavior.i && _normalizeRTLCache ? 9999999 : 0);
  3834. _targetElement[_strScrollTop](0);
  3835. COMPATIBILITY.prvD(event);
  3836. COMPATIBILITY.stpP(event);
  3837. return false;
  3838. };
  3839. _textareaEvents['drop'] = function() {
  3840. setTimeout(function () {
  3841. if(!_destroyed)
  3842. updateTextarea();
  3843. }, 50);
  3844. };
  3845. _textareaEvents['focus'] = function() {
  3846. _textareaHasFocus = true;
  3847. };
  3848. _textareaEvents['focusout'] = function() {
  3849. _textareaHasFocus = false;
  3850. textareaKeyDownKeyCodesList = [ ];
  3851. updateTextarea(true);
  3852. };
  3853. if (_msieVersion > 9 || !_autoUpdateRecommended) {
  3854. _textareaEvents['input'] = function textareaOnInput() {
  3855. updateTextarea();
  3856. }
  3857. }
  3858. else {
  3859. _textareaEvents[_strKeyDownEvent] = function textareaOnKeyDown(event) {
  3860. var keyCode = event.keyCode;
  3861. if (FRAMEWORK.inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1)
  3862. return;
  3863. if (!textareaKeyDownKeyCodesList.length) {
  3864. updateTextarea();
  3865. textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60);
  3866. }
  3867. if (FRAMEWORK.inArray(keyCode, textareaKeyDownKeyCodesList) === -1)
  3868. textareaKeyDownKeyCodesList.push(keyCode);
  3869. };
  3870. _textareaEvents[_strKeyUpEvent] = function(event) {
  3871. var keyCode = event.keyCode;
  3872. var index = FRAMEWORK.inArray(keyCode, textareaKeyDownKeyCodesList);
  3873. if (FRAMEWORK.inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1)
  3874. return;
  3875. if (index > -1)
  3876. textareaKeyDownKeyCodesList.splice(index, 1);
  3877. if (!textareaKeyDownKeyCodesList.length)
  3878. updateTextarea(true);
  3879. };
  3880. }
  3881. }
  3882. if (_isTextarea) {
  3883. FRAMEWORK.each(_textareaEvents, function(key, value) {
  3884. _targetElement[strOnOff](key, value);
  3885. });
  3886. }
  3887. else {
  3888. _contentElement[strOnOff](_strTransitionEndEvent, function (event) {
  3889. if (_autoUpdateCache === true)
  3890. return;
  3891. event = event.originalEvent || event;
  3892. if (isSizeAffectingCSSProperty(event.propertyName))
  3893. update(_strAuto);
  3894. });
  3895. }
  3896. if(!destroy) {
  3897. viewportOnScroll = function(event) {
  3898. if (_isSleeping)
  3899. return;
  3900. if (scrollStopTimeoutId !== undefined)
  3901. clearTimeout(scrollStopTimeoutId);
  3902. else {
  3903. if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
  3904. refreshScrollbarsAutoHide(true);
  3905. if (!nativeOverlayScrollbarsAreActive())
  3906. addClass(_hostElement, _classNameHostScrolling);
  3907. dispatchCallback("onScrollStart", event);
  3908. }
  3909. //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset
  3910. //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point
  3911. //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove
  3912. if(!_scrollbarsHandleAsync) {
  3913. refreshScrollbarHandleOffset(true);
  3914. refreshScrollbarHandleOffset(false);
  3915. }
  3916. dispatchCallback("onScroll", event);
  3917. scrollStopTimeoutId = setTimeout(function () {
  3918. if(!_destroyed) {
  3919. //OnScrollStop:
  3920. clearTimeout(scrollStopTimeoutId);
  3921. scrollStopTimeoutId = undefined;
  3922. if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
  3923. refreshScrollbarsAutoHide(false);
  3924. if (!nativeOverlayScrollbarsAreActive())
  3925. removeClass(_hostElement, _classNameHostScrolling);
  3926. dispatchCallback("onScrollStop", event);
  3927. }
  3928. }, scrollStopDelay);
  3929. };
  3930. if (_supportPassiveEvents)
  3931. addPassiveEventListener(_viewportElement, _strScroll, viewportOnScroll);
  3932. else
  3933. _viewportElement.on(_strScroll, viewportOnScroll);
  3934. }
  3935. }
  3936. //==== Scrollbars ====//
  3937. /**
  3938. * Builds or destroys all scrollbar DOM elements (scrollbar, track, handle)
  3939. * @param destroy Indicates whether the DOM shall be build or destroyed.
  3940. */
  3941. function setupScrollbarsDOM(destroy) {
  3942. if(!destroy) {
  3943. _scrollbarHorizontalElement = FRAMEWORK(generateDiv(_classNameScrollbar + _strSpace + _classNameScrollbarHorizontal));
  3944. _scrollbarHorizontalTrackElement = FRAMEWORK(generateDiv(_classNameScrollbarTrack));
  3945. _scrollbarHorizontalHandleElement = FRAMEWORK(generateDiv(_classNameScrollbarHandle));
  3946. _scrollbarVerticalElement = FRAMEWORK(generateDiv(_classNameScrollbar + _strSpace + _classNameScrollbarVertical));
  3947. _scrollbarVerticalTrackElement = FRAMEWORK(generateDiv(_classNameScrollbarTrack));
  3948. _scrollbarVerticalHandleElement = FRAMEWORK(generateDiv(_classNameScrollbarHandle));
  3949. _scrollbarHorizontalElement.append(_scrollbarHorizontalTrackElement);
  3950. _scrollbarHorizontalTrackElement.append(_scrollbarHorizontalHandleElement);
  3951. _scrollbarVerticalElement.append(_scrollbarVerticalTrackElement);
  3952. _scrollbarVerticalTrackElement.append(_scrollbarVerticalHandleElement);
  3953. _paddingElement.after(_scrollbarVerticalElement);
  3954. _paddingElement.after(_scrollbarHorizontalElement);
  3955. }
  3956. else {
  3957. remove(_scrollbarHorizontalElement);
  3958. remove(_scrollbarVerticalElement);
  3959. }
  3960. }
  3961. /**
  3962. * Initializes all scrollbar interactivity events. (track and handle dragging, clicking, scrolling)
  3963. * @param isHorizontal True if the target scrollbar is the horizontal scrollbar, false if the target scrollbar is the vertical scrollbar.
  3964. */
  3965. function setupScrollbarEvents(isHorizontal) {
  3966. var scrollbarVars = getScrollbarVars(isHorizontal);
  3967. var scrollbarVarsInfo = scrollbarVars._info;
  3968. var insideIFrame = _windowElementNative.top !== _windowElementNative;
  3969. var xy = scrollbarVars._x_y;
  3970. var XY = scrollbarVars._X_Y;
  3971. var scroll = _strScroll + scrollbarVars._Left_Top;
  3972. var strActive = 'active';
  3973. var strSnapHandle = 'snapHandle';
  3974. var scrollDurationFactor = 1;
  3975. var increaseDecreaseScrollAmountKeyCodes = [ 16, 17 ]; //shift, ctrl
  3976. var trackTimeout;
  3977. var mouseDownScroll;
  3978. var mouseDownOffset;
  3979. var mouseDownInvertedScale;
  3980. function getPointerPosition(event) {
  3981. return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames.
  3982. }
  3983. function getPreparedScrollbarsOption(name) {
  3984. return _currentPreparedOptions.scrollbars[name];
  3985. }
  3986. function increaseTrackScrollAmount() {
  3987. scrollDurationFactor = 0.5;
  3988. }
  3989. function decreaseTrackScrollAmount() {
  3990. scrollDurationFactor = 1;
  3991. }
  3992. function documentKeyDown(event) {
  3993. if (FRAMEWORK.inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
  3994. increaseTrackScrollAmount();
  3995. }
  3996. function documentKeyUp(event) {
  3997. if (FRAMEWORK.inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1)
  3998. decreaseTrackScrollAmount();
  3999. }
  4000. function onMouseTouchDownContinue(event) {
  4001. var originalEvent = event.originalEvent || event;
  4002. var isTouchEvent = originalEvent.touches !== undefined;
  4003. return _isSleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
  4004. }
  4005. function documentDragMove(event) {
  4006. if(onMouseTouchDownContinue(event)) {
  4007. var trackLength = scrollbarVarsInfo._trackLength;
  4008. var handleLength = scrollbarVarsInfo._handleLength;
  4009. var scrollRange = scrollbarVarsInfo._maxScroll;
  4010. var scrollRaw = (getPointerPosition(event) - mouseDownOffset) * mouseDownInvertedScale;
  4011. var scrollDeltaPercent = scrollRaw / (trackLength - handleLength);
  4012. var scrollDelta = (scrollRange * scrollDeltaPercent);
  4013. scrollDelta = isFinite(scrollDelta) ? scrollDelta : 0;
  4014. if (_isRTL && isHorizontal && !_rtlScrollBehavior.i)
  4015. scrollDelta *= -1;
  4016. _viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta));
  4017. if(_scrollbarsHandleAsync)
  4018. refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta);
  4019. if (!_supportPassiveEvents)
  4020. COMPATIBILITY.prvD(event);
  4021. }
  4022. else
  4023. documentMouseTouchUp(event);
  4024. }
  4025. function documentMouseTouchUp(event) {
  4026. event = event || event.originalEvent;
  4027. _documentElement.off(_strMouseTouchMoveEvent, documentDragMove)
  4028. .off(_strMouseTouchUpEvent, documentMouseTouchUp)
  4029. .off(_strKeyDownEvent, documentKeyDown)
  4030. .off(_strKeyUpEvent, documentKeyUp)
  4031. .off(_strSelectStartEvent, documentOnSelectStart);
  4032. if(_scrollbarsHandleAsync)
  4033. refreshScrollbarHandleOffset(isHorizontal, true);
  4034. _scrollbarsHandleAsync = false;
  4035. removeClass(_bodyElement, _classNameDragging);
  4036. removeClass(scrollbarVars._handle, strActive);
  4037. removeClass(scrollbarVars._track, strActive);
  4038. removeClass(scrollbarVars._scrollbar, strActive);
  4039. mouseDownScroll = undefined;
  4040. mouseDownOffset = undefined;
  4041. mouseDownInvertedScale = 1;
  4042. decreaseTrackScrollAmount();
  4043. if (trackTimeout !== undefined) {
  4044. _base.scrollStop();
  4045. clearTimeout(trackTimeout);
  4046. trackTimeout = undefined;
  4047. }
  4048. if(event) {
  4049. var rect = _hostElementNative.getBoundingClientRect();
  4050. var mouseInsideHost = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
  4051. //if mouse is outside host element
  4052. if (!mouseInsideHost)
  4053. hostOnMouseLeave();
  4054. if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
  4055. refreshScrollbarsAutoHide(false);
  4056. }
  4057. }
  4058. function onHandleMouseTouchDown(event) {
  4059. mouseDownScroll = _viewportElement[scroll]();
  4060. mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll;
  4061. if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL)
  4062. mouseDownScroll = mouseDownScroll < 0 ? 0 : mouseDownScroll;
  4063. mouseDownInvertedScale = getHostElementInvertedScale()[xy];
  4064. mouseDownOffset = getPointerPosition(event);
  4065. _scrollbarsHandleAsync = !getPreparedScrollbarsOption(strSnapHandle);
  4066. addClass(_bodyElement, _classNameDragging);
  4067. addClass(scrollbarVars._handle, strActive);
  4068. addClass(scrollbarVars._scrollbar, strActive);
  4069. _documentElement.on(_strMouseTouchMoveEvent, documentDragMove)
  4070. .on(_strMouseTouchUpEvent, documentMouseTouchUp)
  4071. .on(_strSelectStartEvent, documentOnSelectStart);
  4072. if(_msieVersion || !_documentMixed)
  4073. COMPATIBILITY.prvD(event);
  4074. COMPATIBILITY.stpP(event);
  4075. }
  4076. scrollbarVars._handle.on(_strMouseTouchDownEvent, function(event) {
  4077. if (onMouseTouchDownContinue(event))
  4078. onHandleMouseTouchDown(event);
  4079. });
  4080. scrollbarVars._track.on(_strMouseTouchDownEvent, function(event) {
  4081. if (onMouseTouchDownContinue(event)) {
  4082. var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h]);
  4083. var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top];
  4084. var ctrlKey = event.ctrlKey;
  4085. var instantScroll = event.shiftKey;
  4086. var instantScrollTransition = instantScroll && ctrlKey;
  4087. var isFirstIteration = true;
  4088. var easing = 'linear';
  4089. var decreaseScroll;
  4090. var finishedCondition;
  4091. var scrollActionFinsished = function(transition) {
  4092. if(_scrollbarsHandleAsync)
  4093. refreshScrollbarHandleOffset(isHorizontal, transition);
  4094. };
  4095. var scrollActionInstantFinished = function() {
  4096. scrollActionFinsished();
  4097. onHandleMouseTouchDown(event);
  4098. };
  4099. var scrollAction = function () {
  4100. if(!_destroyed) {
  4101. var mouseOffset = (mouseDownOffset - trackOffset) * mouseDownInvertedScale;
  4102. var handleOffset = scrollbarVarsInfo._handleOffset;
  4103. var trackLength = scrollbarVarsInfo._trackLength;
  4104. var handleLength = scrollbarVarsInfo._handleLength;
  4105. var scrollRange = scrollbarVarsInfo._maxScroll;
  4106. var currScroll = scrollbarVarsInfo._currentScroll;
  4107. var scrollDuration = 270 * scrollDurationFactor;
  4108. var timeoutDelay = isFirstIteration ? MATH.max(400, scrollDuration) : scrollDuration;
  4109. var instantScrollPosition = scrollRange * ((mouseOffset - (handleLength / 2)) / (trackLength - handleLength)); // 100% * positionPercent
  4110. var rtlIsNormal = _isRTL && isHorizontal && ((!_rtlScrollBehavior.i && !_rtlScrollBehavior.n) || _normalizeRTLCache);
  4111. var decreaseScrollCondition = rtlIsNormal ? handleOffset < mouseOffset : handleOffset > mouseOffset;
  4112. var scrollObj = { };
  4113. var animationObj = {
  4114. easing : easing,
  4115. step : function(now) {
  4116. if(_scrollbarsHandleAsync) {
  4117. _viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/4340
  4118. refreshScrollbarHandleOffset(isHorizontal, now);
  4119. }
  4120. }
  4121. };
  4122. instantScrollPosition = isFinite(instantScrollPosition) ? instantScrollPosition : 0;
  4123. instantScrollPosition = _isRTL && isHorizontal && !_rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
  4124. //_base.scrollStop();
  4125. if(instantScroll) {
  4126. _viewportElement[scroll](instantScrollPosition); //scroll instantly to new position
  4127. if(instantScrollTransition) {
  4128. //get the scroll position after instant scroll (in case CSS Snap Points are used) to get the correct snapped scroll position
  4129. //and the animation stops at the correct point
  4130. instantScrollPosition = _viewportElement[scroll]();
  4131. //scroll back to the position before instant scrolling so animation can be performed
  4132. _viewportElement[scroll](currScroll);
  4133. instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.i ? (scrollRange - instantScrollPosition) : instantScrollPosition;
  4134. instantScrollPosition = rtlIsNormal && _rtlScrollBehavior.n ? -instantScrollPosition : instantScrollPosition;
  4135. scrollObj[xy] = instantScrollPosition;
  4136. _base.scroll(scrollObj, extendDeep(animationObj, {
  4137. duration : 130,
  4138. complete : scrollActionInstantFinished
  4139. }));
  4140. }
  4141. else
  4142. scrollActionInstantFinished();
  4143. }
  4144. else {
  4145. decreaseScroll = isFirstIteration ? decreaseScrollCondition : decreaseScroll;
  4146. finishedCondition = rtlIsNormal
  4147. ? (decreaseScroll ? handleOffset + handleLength >= mouseOffset : handleOffset <= mouseOffset)
  4148. : (decreaseScroll ? handleOffset <= mouseOffset : handleOffset + handleLength >= mouseOffset);
  4149. if (finishedCondition) {
  4150. clearTimeout(trackTimeout);
  4151. _base.scrollStop();
  4152. trackTimeout = undefined;
  4153. scrollActionFinsished(true);
  4154. }
  4155. else {
  4156. trackTimeout = setTimeout(scrollAction, timeoutDelay);
  4157. scrollObj[xy] = (decreaseScroll ? '-=' : '+=') + scrollDistance;
  4158. _base.scroll(scrollObj, extendDeep(animationObj, {
  4159. duration: scrollDuration
  4160. }));
  4161. }
  4162. isFirstIteration = false;
  4163. }
  4164. }
  4165. };
  4166. if (ctrlKey)
  4167. increaseTrackScrollAmount();
  4168. mouseDownInvertedScale = getHostElementInvertedScale()[xy];
  4169. mouseDownOffset = COMPATIBILITY.page(event)[xy];
  4170. _scrollbarsHandleAsync = !getPreparedScrollbarsOption(strSnapHandle);
  4171. addClass(_bodyElement, _classNameDragging);
  4172. addClass(scrollbarVars._track, strActive);
  4173. addClass(scrollbarVars._scrollbar, strActive);
  4174. _documentElement.on(_strMouseTouchUpEvent, documentMouseTouchUp)
  4175. .on(_strKeyDownEvent, documentKeyDown)
  4176. .on(_strKeyUpEvent, documentKeyUp)
  4177. .on(_strSelectStartEvent, documentOnSelectStart);
  4178. scrollAction();
  4179. COMPATIBILITY.prvD(event);
  4180. COMPATIBILITY.stpP(event);
  4181. }
  4182. }).on(_strMouseTouchEnter, function() { //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move".
  4183. _scrollbarsHandleHovered = true;
  4184. if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
  4185. refreshScrollbarsAutoHide(true);
  4186. }).on(_strMouseTouchLeave, function() {
  4187. _scrollbarsHandleHovered = false;
  4188. if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove)
  4189. refreshScrollbarsAutoHide(false);
  4190. });
  4191. scrollbarVars._scrollbar.on(_strMouseTouchDownEvent, function(event) {
  4192. COMPATIBILITY.stpP(event);
  4193. });
  4194. if (_supportTransition) {
  4195. scrollbarVars._scrollbar.on(_strTransitionEndEvent, function(event) {
  4196. if (event.target !== scrollbarVars._scrollbar[0])
  4197. return;
  4198. refreshScrollbarHandleLength(isHorizontal);
  4199. refreshScrollbarHandleOffset(isHorizontal);
  4200. });
  4201. }
  4202. }
  4203. /**
  4204. * Shows or hides the given scrollbar and applied a class name which indicates if the scrollbar is scrollable or not.
  4205. * @param isHorizontal True if the horizontal scrollbar is the target, false if the vertical scrollbar is the target.
  4206. * @param shallBeVisible True if the scrollbar shall be shown, false if hidden.
  4207. * @param canScroll True if the scrollbar is scrollable, false otherwise.
  4208. */
  4209. function refreshScrollbarAppearance(isHorizontal, shallBeVisible, canScroll) {
  4210. var scrollbarClassName = isHorizontal ? _classNameHostScrollbarHorizontalHidden : _classNameHostScrollbarVerticalHidden;
  4211. var scrollbarElement = isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement;
  4212. if (shallBeVisible)
  4213. removeClass(_hostElement, scrollbarClassName);
  4214. else
  4215. addClass(_hostElement, scrollbarClassName);
  4216. if (canScroll)
  4217. removeClass(scrollbarElement, _classNameScrollbarUnusable);
  4218. else
  4219. addClass(scrollbarElement, _classNameScrollbarUnusable);
  4220. }
  4221. /**
  4222. * Autoshows / autohides both scrollbars with.
  4223. * @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.
  4224. * @param delayfree True if the scrollbars shall be hidden without a delay, false or undefined otherwise.
  4225. */
  4226. function refreshScrollbarsAutoHide(shallBeVisible, delayfree) {
  4227. clearTimeout(_scrollbarsAutoHideTimeoutId);
  4228. if (shallBeVisible) {
  4229. //if(_hasOverflowCache.x && _hideOverflowCache.xs)
  4230. removeClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
  4231. //if(_hasOverflowCache.y && _hideOverflowCache.ys)
  4232. removeClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
  4233. }
  4234. else {
  4235. var anyActive;
  4236. var strActive = 'active';
  4237. var hide = function () {
  4238. if (!_scrollbarsHandleHovered && !_destroyed) {
  4239. anyActive = _scrollbarHorizontalHandleElement.hasClass(strActive) || _scrollbarVerticalHandleElement.hasClass(strActive);
  4240. if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
  4241. addClass(_scrollbarHorizontalElement, _classNameScrollbarAutoHidden);
  4242. if (!anyActive && (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove || _scrollbarsAutoHideLeave))
  4243. addClass(_scrollbarVerticalElement, _classNameScrollbarAutoHidden);
  4244. }
  4245. };
  4246. if (_scrollbarsAutoHideDelay > 0 && delayfree !== true)
  4247. _scrollbarsAutoHideTimeoutId = setTimeout(hide, _scrollbarsAutoHideDelay);
  4248. else
  4249. hide();
  4250. }
  4251. }
  4252. /**
  4253. * Refreshes the handle length of the given scrollbar.
  4254. * @param isHorizontal True if the horizontal scrollbar handle shall be refreshed, false if the vertical one shall be refreshed.
  4255. */
  4256. function refreshScrollbarHandleLength(isHorizontal) {
  4257. var handleCSS = {};
  4258. var scrollbarVars = getScrollbarVars(isHorizontal);
  4259. var scrollbarVarsInfo = scrollbarVars._info;
  4260. var digit = 1000000;
  4261. //get and apply intended handle length
  4262. var handleRatio = MATH.min(1, (_hostSizeCache[scrollbarVars._w_h] - (_paddingAbsoluteCache ? (isHorizontal ? _paddingX : _paddingY) : 0)) / _contentScrollSizeCache[scrollbarVars._w_h]);
  4263. handleCSS[scrollbarVars._width_height] = (MATH.floor(handleRatio * 100 * digit) / digit) + "%"; //the last * digit / digit is for flooring to the 4th digit
  4264. if (!nativeOverlayScrollbarsAreActive())
  4265. scrollbarVars._handle.css(handleCSS);
  4266. //measure the handle length to respect min & max length
  4267. scrollbarVarsInfo._handleLength = scrollbarVars._handle[0]['offset' + scrollbarVars._Width_Height];
  4268. scrollbarVarsInfo._handleLengthRatio = handleRatio;
  4269. }
  4270. /**
  4271. * Refreshes the handle offset 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. * @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)
  4274. */
  4275. function refreshScrollbarHandleOffset(isHorizontal, scrollOrTransition) {
  4276. var transition = type(scrollOrTransition) == TYPES.b;
  4277. var transitionDuration = 250;
  4278. var isRTLisHorizontal = _isRTL && isHorizontal;
  4279. var scrollbarVars = getScrollbarVars(isHorizontal);
  4280. var scrollbarVarsInfo = scrollbarVars._info;
  4281. var strTranslateBrace = 'translate(';
  4282. var strTransform = VENDORS._cssProperty('transform');
  4283. var strTransition = VENDORS._cssProperty('transition');
  4284. var nativeScroll = isHorizontal ? _viewportElement[_strScrollLeft]() : _viewportElement[_strScrollTop]();
  4285. var currentScroll = scrollOrTransition === undefined || transition ? nativeScroll : scrollOrTransition;
  4286. //measure the handle length to respect min & max length
  4287. var handleLength = scrollbarVarsInfo._handleLength;
  4288. var trackLength = scrollbarVars._track[0]['offset' + scrollbarVars._Width_Height];
  4289. var handleTrackDiff = trackLength - handleLength;
  4290. var handleCSS = {};
  4291. var transformOffset;
  4292. var translateValue;
  4293. //DONT use the variable '_contentScrollSizeCache[scrollbarVars._w_h]' instead of '_viewportElement[0]['scroll' + scrollbarVars._Width_Height]'
  4294. // because its a bit behind during the small delay when content size updates
  4295. //(delay = mutationObserverContentLag, if its 0 then this var could be used)
  4296. var maxScroll = (_viewportElementNative[_strScroll + scrollbarVars._Width_Height] - _viewportElementNative['client' + scrollbarVars._Width_Height]) * (_rtlScrollBehavior.n && isRTLisHorizontal ? -1 : 1); //* -1 if rtl scroll max is negative
  4297. var getScrollRatio = function(base) {
  4298. return isNaN(base / maxScroll) ? 0 : MATH.max(0, MATH.min(1, base / maxScroll));
  4299. };
  4300. var getHandleOffset = function(scrollRatio) {
  4301. var offset = handleTrackDiff * scrollRatio;
  4302. offset = isNaN(offset) ? 0 : offset;
  4303. offset = (isRTLisHorizontal && !_rtlScrollBehavior.i) ? (trackLength - handleLength - offset) : offset;
  4304. offset = MATH.max(0, offset);
  4305. return offset;
  4306. };
  4307. var scrollRatio = getScrollRatio(nativeScroll);
  4308. var unsnappedScrollRatio = getScrollRatio(currentScroll);
  4309. var handleOffset = getHandleOffset(unsnappedScrollRatio);
  4310. var snappedHandleOffset = getHandleOffset(scrollRatio);
  4311. scrollbarVarsInfo._maxScroll = maxScroll;
  4312. scrollbarVarsInfo._currentScroll = nativeScroll;
  4313. scrollbarVarsInfo._currentScrollRatio = scrollRatio;
  4314. if (_supportTransform) {
  4315. transformOffset = isRTLisHorizontal ? -(trackLength - handleLength - handleOffset) : handleOffset; //in px
  4316. //transformOffset = (transformOffset / trackLength * 100) * (trackLength / handleLength); //in %
  4317. translateValue = isHorizontal ? strTranslateBrace + transformOffset + 'px, 0)' : strTranslateBrace + '0, ' + transformOffset + 'px)';
  4318. handleCSS[strTransform] = translateValue;
  4319. //apply or clear up transition
  4320. if(_supportTransition)
  4321. handleCSS[strTransition] = transition && MATH.abs(handleOffset - scrollbarVarsInfo._handleOffset) > 1 ? getCSSTransitionString(scrollbarVars._handle) + ', ' + (strTransform + _strSpace + transitionDuration + 'ms') : _strEmpty;
  4322. }
  4323. else
  4324. handleCSS[scrollbarVars._left_top] = handleOffset;
  4325. //only apply css if offset has changed and overflow exists.
  4326. if (!nativeOverlayScrollbarsAreActive()) {
  4327. scrollbarVars._handle.css(handleCSS);
  4328. //clear up transition
  4329. if(_supportTransform && _supportTransition && transition) {
  4330. scrollbarVars._handle.one(_strTransitionEndEvent, function() {
  4331. if(!_destroyed)
  4332. scrollbarVars._handle.css(strTransition, _strEmpty);
  4333. });
  4334. }
  4335. }
  4336. scrollbarVarsInfo._handleOffset = handleOffset;
  4337. scrollbarVarsInfo._snappedHandleOffset = snappedHandleOffset;
  4338. scrollbarVarsInfo._trackLength = trackLength;
  4339. }
  4340. /**
  4341. * Refreshes the interactivity of the given scrollbar element.
  4342. * @param isTrack True if the track element is the target, false if the handle element is the target.
  4343. * @param value True for interactivity false for no interactivity.
  4344. */
  4345. function refreshScrollbarsInteractive(isTrack, value) {
  4346. var action = value ? 'removeClass' : 'addClass';
  4347. var element1 = isTrack ? _scrollbarHorizontalTrackElement : _scrollbarHorizontalHandleElement;
  4348. var element2 = isTrack ? _scrollbarVerticalTrackElement : _scrollbarVerticalHandleElement;
  4349. var className = isTrack ? _classNameScrollbarTrackOff : _classNameScrollbarHandleOff;
  4350. element1[action](className);
  4351. element2[action](className);
  4352. }
  4353. /**
  4354. * Returns a object which is used for fast access for specific variables.
  4355. * @param isHorizontal True if the horizontal scrollbar vars shall be accessed, false if the vertical scrollbar vars shall be accessed.
  4356. * @returns {{wh: string, WH: string, lt: string, _wh: string, _lt: string, t: *, h: *, c: {}, s: *}}
  4357. */
  4358. function getScrollbarVars(isHorizontal) {
  4359. return {
  4360. _width_height: isHorizontal ? _strWidth : _strHeight,
  4361. _Width_Height: isHorizontal ? 'Width' : 'Height',
  4362. _left_top: isHorizontal ? _strLeft : _strTop,
  4363. _Left_Top: isHorizontal ? 'Left' : 'Top',
  4364. _x_y: isHorizontal ? _strX : _strY,
  4365. _X_Y: isHorizontal ? 'X' : 'Y',
  4366. _w_h: isHorizontal ? 'w' : 'h',
  4367. _l_t: isHorizontal ? 'l' : 't',
  4368. _track: isHorizontal ? _scrollbarHorizontalTrackElement : _scrollbarVerticalTrackElement,
  4369. _handle: isHorizontal ? _scrollbarHorizontalHandleElement : _scrollbarVerticalHandleElement,
  4370. _scrollbar: isHorizontal ? _scrollbarHorizontalElement : _scrollbarVerticalElement,
  4371. _info: isHorizontal ? _scrollHorizontalInfo : _scrollVerticalInfo
  4372. };
  4373. }
  4374. //==== Scrollbar Corner ====//
  4375. /**
  4376. * Builds or destroys the scrollbar corner DOM element.
  4377. * @param destroy Indicates whether the DOM shall be build or destroyed.
  4378. */
  4379. function setupScrollbarCornerDOM(destroy) {
  4380. if(!destroy) {
  4381. _scrollbarCornerElement = FRAMEWORK(generateDiv(_classNameScrollbarCorner));
  4382. _hostElement.append(_scrollbarCornerElement);
  4383. }
  4384. else {
  4385. remove(_scrollbarCornerElement);
  4386. }
  4387. }
  4388. /**
  4389. * Initializes all scrollbar corner interactivity events.
  4390. */
  4391. function setupScrollbarCornerEvents() {
  4392. var insideIFrame = _windowElementNative.top !== _windowElementNative;
  4393. var mouseDownPosition = { };
  4394. var mouseDownSize = { };
  4395. var mouseDownInvertedScale = { };
  4396. _resizeOnMouseTouchDown = function(event) {
  4397. if (onMouseTouchDownContinue(event)) {
  4398. if (_mutationObserversConnected) {
  4399. _resizeReconnectMutationObserver = true;
  4400. disconnectMutationObservers();
  4401. }
  4402. mouseDownPosition = getCoordinates(event);
  4403. mouseDownSize.w = _hostElementNative[LEXICON.oW] - (!_isBorderBox ? _paddingX : 0);
  4404. mouseDownSize.h = _hostElementNative[LEXICON.oH] - (!_isBorderBox ? _paddingY : 0);
  4405. mouseDownInvertedScale = getHostElementInvertedScale();
  4406. _documentElement.on(_strSelectStartEvent, documentOnSelectStart)
  4407. .on(_strMouseTouchMoveEvent, documentDragMove)
  4408. .on(_strMouseTouchUpEvent, documentMouseTouchUp);
  4409. addClass(_bodyElement, _classNameDragging);
  4410. if (_scrollbarCornerElement.setCapture)
  4411. _scrollbarCornerElement.setCapture();
  4412. COMPATIBILITY.prvD(event);
  4413. COMPATIBILITY.stpP(event);
  4414. }
  4415. };
  4416. function documentDragMove(event) {
  4417. if (onMouseTouchDownContinue(event)) {
  4418. var pageOffset = getCoordinates(event);
  4419. var hostElementCSS = { };
  4420. if (_resizeHorizontal || _resizeBoth)
  4421. hostElementCSS[_strWidth] = (mouseDownSize.w + (pageOffset.x - mouseDownPosition.x) * mouseDownInvertedScale.x);
  4422. if (_resizeVertical || _resizeBoth)
  4423. hostElementCSS[_strHeight] = (mouseDownSize.h + (pageOffset.y - mouseDownPosition.y) * mouseDownInvertedScale.y);
  4424. _hostElement.css(hostElementCSS);
  4425. COMPATIBILITY.stpP(event);
  4426. }
  4427. else {
  4428. documentMouseTouchUp(event);
  4429. }
  4430. }
  4431. function documentMouseTouchUp(event) {
  4432. var eventIsTrusted = event !== undefined;
  4433. _documentElement.off(_strSelectStartEvent, documentOnSelectStart)
  4434. .off(_strMouseTouchMoveEvent, documentDragMove)
  4435. .off(_strMouseTouchUpEvent, documentMouseTouchUp);
  4436. removeClass(_bodyElement, _classNameDragging);
  4437. if (_scrollbarCornerElement.releaseCapture)
  4438. _scrollbarCornerElement.releaseCapture();
  4439. if (eventIsTrusted) {
  4440. if (_resizeReconnectMutationObserver)
  4441. connectMutationObservers();
  4442. _base.update(_strAuto);
  4443. }
  4444. _resizeReconnectMutationObserver = false;
  4445. }
  4446. function onMouseTouchDownContinue(event) {
  4447. var originalEvent = event.originalEvent || event;
  4448. var isTouchEvent = originalEvent.touches !== undefined;
  4449. return _isSleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent;
  4450. }
  4451. function getCoordinates(event) {
  4452. return _msieVersion && insideIFrame ? { x : event.screenX , y : event.screenY } : COMPATIBILITY.page(event);
  4453. }
  4454. }
  4455. //==== Utils ====//
  4456. /**
  4457. * Calls the callback with the given name. The Context of this callback is always _base (this).
  4458. * @param name The name of the target which shall be called.
  4459. * @param args The args with which the callback shall be called.
  4460. */
  4461. function dispatchCallback(name, args) {
  4462. if(_initialized) {
  4463. var callback = _currentPreparedOptions.callbacks[name];
  4464. var extensionOnName = name;
  4465. var ext;
  4466. if(extensionOnName.substr(0, 2) === "on")
  4467. extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3);
  4468. if(type(callback) == TYPES.f)
  4469. callback.call(_base, args);
  4470. FRAMEWORK.each(_extensions, function() {
  4471. ext = this;
  4472. if(type(ext.on) == TYPES.f)
  4473. ext.on(extensionOnName, args);
  4474. });
  4475. }
  4476. else if(!_destroyed)
  4477. _callbacksInitQeueue.push({ n : name, a : args });
  4478. }
  4479. /**
  4480. * Sets the "top, right, bottom, left" properties, with a given prefix, of the given css object.
  4481. * @param targetCSSObject The css object to which the values shall be applied.
  4482. * @param prefix The prefix of the "top, right, bottom, left" css properties. (example: 'padding-' is a valid prefix)
  4483. * @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].
  4484. * If this argument is undefined the value '' (empty string) will be applied to all properties.
  4485. */
  4486. function setTopRightBottomLeft(targetCSSObject, prefix, values) {
  4487. if (values === undefined)
  4488. values = [_strEmpty, _strEmpty, _strEmpty, _strEmpty];
  4489. targetCSSObject[prefix + _strTop] = values[0];
  4490. targetCSSObject[prefix + _strRight] = values[1];
  4491. targetCSSObject[prefix + _strBottom] = values[2];
  4492. targetCSSObject[prefix + _strLeft] = values[3];
  4493. }
  4494. /**
  4495. * Returns the computed CSS transition string from the given element.
  4496. * @param element The element from which the transition string shall be returned.
  4497. * @returns {string} The CSS transition string from the given element.
  4498. */
  4499. function getCSSTransitionString(element) {
  4500. var transitionStr = VENDORS._cssProperty('transition');
  4501. var assembledValue = element.css(transitionStr);
  4502. if(assembledValue)
  4503. return assembledValue;
  4504. var regExpString = '\\s*(' + '([^,(]+(\\(.+?\\))?)+' + ')[\\s,]*';
  4505. var regExpMain = new RegExp(regExpString);
  4506. var regExpValidate = new RegExp('^(' + regExpString + ')+$');
  4507. var properties = 'property duration timing-function delay'.split(' ');
  4508. var result = [ ];
  4509. var strResult;
  4510. var valueArray;
  4511. var i = 0;
  4512. var j;
  4513. var splitCssStyleByComma = function(str) {
  4514. strResult = [ ];
  4515. if (!str.match(regExpValidate))
  4516. return str;
  4517. while (str.match(regExpMain)) {
  4518. strResult.push(RegExp.$1);
  4519. str = str.replace(regExpMain, _strEmpty);
  4520. }
  4521. return strResult;
  4522. };
  4523. for (; i < properties[LEXICON.l]; i++) {
  4524. valueArray = splitCssStyleByComma(element.css(transitionStr + '-' + properties[i]));
  4525. for (j = 0; j < valueArray[LEXICON.l]; j++)
  4526. result[j] = (result[j] ? result[j] + _strSpace : _strEmpty) + valueArray[j];
  4527. }
  4528. return result.join(', ');
  4529. }
  4530. /**
  4531. * Calculates the host-elements inverted scale. (invertedScale = 1 / scale)
  4532. * @returns {{x: number, y: number}} The scale of the host-element.
  4533. */
  4534. function getHostElementInvertedScale() {
  4535. var rect = _paddingElementNative.getBoundingClientRect();
  4536. return {
  4537. x : _supportTransform ? 1 / (MATH.round(rect.width) / _paddingElementNative[LEXICON.oW]) : 1,
  4538. y : _supportTransform ? 1 / (MATH.round(rect.height) / _paddingElementNative[LEXICON.oH]) : 1
  4539. };
  4540. }
  4541. /**
  4542. * Checks whether the given object is a HTMLElement.
  4543. * @param o The object which shall be checked.
  4544. * @returns {boolean} True the given object is a HTMLElement, false otherwise.
  4545. */
  4546. function isHTMLElement(o) {
  4547. var strOwnerDocument = 'ownerDocument';
  4548. var strHTMLElement = 'HTMLElement';
  4549. var wnd = o && o[strOwnerDocument] ? (o[strOwnerDocument].parentWindow || window) : window;
  4550. return (
  4551. typeof wnd[strHTMLElement] == TYPES.o ? o instanceof wnd[strHTMLElement] : //DOM2
  4552. o && typeof o == TYPES.o && o !== null && o.nodeType === 1 && typeof o.nodeName == TYPES.s
  4553. );
  4554. }
  4555. /**
  4556. * Compares 2 arrays and returns the differences between them as a array.
  4557. * @param a1 The first array which shall be compared.
  4558. * @param a2 The second array which shall be compared.
  4559. * @returns {Array} The differences between the two arrays.
  4560. */
  4561. function getArrayDifferences(a1, a2) {
  4562. var a = [ ];
  4563. var diff = [ ];
  4564. var i;
  4565. var k;
  4566. for (i = 0; i < a1.length; i++)
  4567. a[a1[i]] = true;
  4568. for (i = 0; i < a2.length; i++) {
  4569. if (a[a2[i]])
  4570. delete a[a2[i]];
  4571. else
  4572. a[a2[i]] = true;
  4573. }
  4574. for (k in a)
  4575. diff.push(k);
  4576. return diff;
  4577. }
  4578. /**
  4579. * Returns Zero or the number to which the value can be parsed.
  4580. * @param value The value which shall be parsed.
  4581. * @param toFloat Indicates whether the number shall be parsed to a float.
  4582. */
  4583. function parseToZeroOrNumber(value, toFloat) {
  4584. var num = toFloat ? parseFloat(value) : parseInt(value, 10);
  4585. return isNaN(num) ? 0 : num;
  4586. }
  4587. /**
  4588. * Gets several information of the textarea and returns them as a object or undefined if the browser doesn't support it.
  4589. * @returns {{cursorRow: Number, cursorCol, rows: Number, cols: number, wRow: number, pos: number, max : number}} or undefined if not supported.
  4590. */
  4591. function getTextareaInfo() {
  4592. //read needed values
  4593. var textareaCursorPosition = _targetElementNative.selectionStart;
  4594. if (textareaCursorPosition === undefined)
  4595. return;
  4596. var strLength = 'length';
  4597. var textareaValue = _targetElement.val();
  4598. var textareaLength = textareaValue[strLength];
  4599. var textareaRowSplit = textareaValue.split("\n");
  4600. var textareaLastRow = textareaRowSplit[strLength];
  4601. var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split("\n");
  4602. var widestRow = 0;
  4603. var textareaLastCol = 0;
  4604. var cursorRow = textareaCurrentCursorRowSplit[strLength];
  4605. var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[strLength] - 1][strLength];
  4606. var rowCols;
  4607. var i;
  4608. //get widest Row and the last column of the textarea
  4609. for (i = 0; i < textareaRowSplit[strLength]; i++) {
  4610. rowCols = textareaRowSplit[i][strLength];
  4611. if (rowCols > textareaLastCol) {
  4612. widestRow = i + 1;
  4613. textareaLastCol = rowCols;
  4614. }
  4615. }
  4616. return {
  4617. _cursorRow: cursorRow, //cursorRow
  4618. _cursorColumn: cursorCol, //cursorCol
  4619. _rows: textareaLastRow, //rows
  4620. _columns: textareaLastCol, //cols
  4621. _widestRow: widestRow, //wRow
  4622. _cursorPosition: textareaCursorPosition, //pos
  4623. _cursorMax: textareaLength //max
  4624. };
  4625. }
  4626. /**
  4627. * Determines whether native overlay scrollbars are active.
  4628. * @returns {boolean} True if native overlay scrollbars are active, false otherwise.
  4629. */
  4630. function nativeOverlayScrollbarsAreActive() {
  4631. return (_ignoreOverlayScrollbarHidingCache && (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y));
  4632. }
  4633. /**
  4634. * Gets the element which is used to measure the content size.
  4635. * @returns {*} TextareaCover if target element is textarea else the ContentElement.
  4636. */
  4637. function getContentMeasureElement() {
  4638. return _isTextarea ? _textareaCoverElement[0] : _contentElementNative;
  4639. }
  4640. /**
  4641. * Generates a string which represents a HTML div with the given classes or attributes.
  4642. * @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".)
  4643. * @param content The content of the div as string.
  4644. * @returns {string} The concated string which represents a HTML div and its content.
  4645. */
  4646. function generateDiv(classesOrAttrs, content) {
  4647. return '<div ' + (classesOrAttrs ? type(classesOrAttrs) == TYPES.s ?
  4648. 'class="' + classesOrAttrs + '"' :
  4649. (function() {
  4650. var key;
  4651. var attrs = '';
  4652. if(FRAMEWORK.isPlainObject(classesOrAttrs)) {
  4653. for (key in classesOrAttrs)
  4654. attrs += (key === 'className' ? 'class' : key) + '="' + classesOrAttrs[key] + '" ';
  4655. }
  4656. return attrs;
  4657. })() :
  4658. _strEmpty) +
  4659. '>' +
  4660. (content ? content : _strEmpty) +
  4661. '</div>';
  4662. }
  4663. /**
  4664. * Gets the value of the given property from the given object.
  4665. * @param obj The object from which the property value shall be got.
  4666. * @param path The property of which the value shall be got.
  4667. * @returns {*} Returns the value of the searched property or undefined of the property wasn't found.
  4668. */
  4669. function getObjectPropVal(obj, path) {
  4670. var splits = path.split(_strDot);
  4671. var i = 0;
  4672. var val;
  4673. for(; i < splits.length; i++) {
  4674. if(!obj.hasOwnProperty(splits[i]))
  4675. return;
  4676. val = obj[splits[i]];
  4677. if(i < splits.length && type(val) == TYPES.o)
  4678. obj = val;
  4679. }
  4680. return val;
  4681. }
  4682. /**
  4683. * Sets the value of the given property from the given object.
  4684. * @param obj The object from which the property value shall be set.
  4685. * @param path The property of which the value shall be set.
  4686. * @param val The value of the property which shall be set.
  4687. */
  4688. function setObjectPropVal(obj, path, val) {
  4689. var splits = path.split(_strDot);
  4690. var splitsLength = splits.length;
  4691. var i = 0;
  4692. var extendObj = { };
  4693. var extendObjRoot = extendObj;
  4694. for(; i < splitsLength; i++)
  4695. extendObj = extendObj[splits[i]] = i + 1 < splitsLength ? { } : val;
  4696. FRAMEWORK.extend(obj, extendObjRoot, true);
  4697. }
  4698. //==== Utils Cache ====//
  4699. /**
  4700. * Compares two values and returns the result of the comparison as a boolean.
  4701. * @param current The first value which shall be compared.
  4702. * @param cache The second value which shall be compared.
  4703. * @param force If true the returned value is always true.
  4704. * @returns {boolean} True if both variables aren't equal or some of them is undefined or when the force parameter is true, false otherwise.
  4705. */
  4706. function checkCacheSingle(current, cache, force) {
  4707. if (force === true)
  4708. return force;
  4709. if (cache === undefined)
  4710. return true;
  4711. else if (current !== cache)
  4712. return true;
  4713. return false;
  4714. }
  4715. /**
  4716. * Compares two objects with two properties and returns the result of the comparison as a boolean.
  4717. * @param current The first object which shall be compared.
  4718. * @param cache The second object which shall be compared.
  4719. * @param prop1 The name of the first property of the objects which shall be compared.
  4720. * @param prop2 The name of the second property of the objects 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 checkCacheDouble(current, cache, prop1, prop2, force) {
  4725. if (force === true)
  4726. return force;
  4727. if (prop2 === undefined && force === undefined) {
  4728. if (prop1 === true)
  4729. return prop1;
  4730. else
  4731. prop1 = undefined;
  4732. }
  4733. prop1 = prop1 === undefined ? 'w' : prop1;
  4734. prop2 = prop2 === undefined ? 'h' : prop2;
  4735. if (cache === undefined)
  4736. return true;
  4737. else if (current[prop1] !== cache[prop1] || current[prop2] !== cache[prop2])
  4738. return true;
  4739. return false;
  4740. }
  4741. /**
  4742. * Compares two objects which have four properties and returns the result of the comparison as a boolean.
  4743. * @param current The first object with four properties.
  4744. * @param cache The second object with four properties.
  4745. * @returns {boolean} True if both objects aren't equal or some of them is undefined, false otherwise.
  4746. */
  4747. function checkCacheTRBL(current, cache) {
  4748. if (cache === undefined)
  4749. return true;
  4750. else if (current.t !== cache.t ||
  4751. current.r !== cache.r ||
  4752. current.b !== cache.b ||
  4753. current.l !== cache.l)
  4754. return true;
  4755. return false;
  4756. }
  4757. //==== Shortcuts ====//
  4758. /**
  4759. * jQuery type method shortcut.
  4760. */
  4761. function type(obj) {
  4762. return COMPATIBILITY.type(obj);
  4763. }
  4764. /**
  4765. * jQuery extend method shortcut with a appended "true" as first argument.
  4766. */
  4767. function extendDeep() {
  4768. return FRAMEWORK.extend.apply(this, [ true ].concat([].slice.call(arguments)));
  4769. }
  4770. /**
  4771. * jQuery addClass method shortcut.
  4772. */
  4773. function addClass(el, classes) {
  4774. return _frameworkProto.addClass.call(el, classes);
  4775. }
  4776. /**
  4777. * jQuery removeClass method shortcut.
  4778. */
  4779. function removeClass(el, classes) {
  4780. return _frameworkProto.removeClass.call(el, classes);
  4781. }
  4782. /**
  4783. * jQuery remove method shortcut.
  4784. */
  4785. function remove(el) {
  4786. return _frameworkProto.remove.call(el);
  4787. }
  4788. /**
  4789. * Finds the first child element with the given selector of the given element.
  4790. * @param el The root element from which the selector shall be valid.
  4791. * @param selector The selector of the searched element.
  4792. * @returns {*} The first element which is a child of the given element and matches the givens selector.
  4793. */
  4794. function findFirst(el, selector) {
  4795. return _frameworkProto.find.call(el, selector).eq(0);
  4796. }
  4797. //==== API ====//
  4798. /**
  4799. * 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.
  4800. * This behavior can be reset by calling the update method.
  4801. */
  4802. _base.sleep = function () {
  4803. _isSleeping = true;
  4804. };
  4805. /**
  4806. * Updates the plugin and DOM to the current options.
  4807. * This method should only be called if a update is 100% required.
  4808. * @param force True if every property shall be updated and the cache shall be ignored.
  4809. * !INTERNAL USAGE! : force can be a string "auto", "auto+" or "zoom" too
  4810. * 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.
  4811. */
  4812. _base.update = function (force) {
  4813. var attrsChanged;
  4814. var contentSizeC;
  4815. var isString = type(force) == TYPES.s;
  4816. var imgElementSelector = 'img';
  4817. var imgElementLoadEvent = 'load';
  4818. var isPlus = isString && force.slice(-1) == '+';
  4819. if(isString) {
  4820. if (force.indexOf(_strAuto) === 0) {
  4821. attrsChanged = meaningfulAttrsChanged();
  4822. contentSizeC = updateAutoContentSizeChanged();
  4823. if (attrsChanged || contentSizeC || isPlus)
  4824. update(false, contentSizeC, false, isPlus);
  4825. }
  4826. else if (force === 'zoom')
  4827. update(true, true);
  4828. }
  4829. else {
  4830. force = _isSleeping || force;
  4831. _isSleeping = false;
  4832. update(false, false, force, true);
  4833. }
  4834. if(!_isTextarea) {
  4835. _contentElement.find(imgElementSelector).each(function(i, el) {
  4836. var index = COMPATIBILITY.inA(el, _imgs);
  4837. if (index === -1)
  4838. FRAMEWORK(el).off(imgElementLoadEvent, imgOnLoad).on(imgElementLoadEvent, imgOnLoad);
  4839. });
  4840. }
  4841. };
  4842. /**
  4843. Gets or sets the current options. The update method will be called automatically if new options were set.
  4844. * @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.
  4845. * @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.
  4846. * @returns {*}
  4847. */
  4848. _base.options = function (newOptions, value) {
  4849. //return current options if newOptions are undefined or empty
  4850. if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) {
  4851. if (type(newOptions) == TYPES.s) {
  4852. if (arguments.length > 1) {
  4853. var option = { };
  4854. setObjectPropVal(option, newOptions, value);
  4855. setOptions(option);
  4856. update();
  4857. return;
  4858. }
  4859. else
  4860. return getObjectPropVal(_currentOptions, newOptions);
  4861. }
  4862. else
  4863. return _currentOptions;
  4864. }
  4865. setOptions(newOptions);
  4866. var isSleepingTmp = _isSleeping || false;
  4867. _isSleeping = false;
  4868. update();
  4869. _isSleeping = isSleepingTmp;
  4870. };
  4871. /**
  4872. * Restore the DOM, disconnects all observers, remove all resize observers and destroy all methods.
  4873. */
  4874. _base.destroy = function () {
  4875. _destroyed = true;
  4876. //remove this instance from auto update loop
  4877. autoUpdateLoop.remove(_base);
  4878. //disconnect all mutation observers
  4879. disconnectMutationObservers();
  4880. //remove all resize observers
  4881. removeResizeObserver(_sizeObserverElement);
  4882. if (_sizeAutoObserverAdded)
  4883. removeResizeObserver(_sizeAutoObserverElement);
  4884. //remove all extensions
  4885. for(var extName in _extensions)
  4886. _base.removeExt(extName);
  4887. //remove all events from host element
  4888. setupHostMouseTouchEvents(true);
  4889. //remove all events from structure
  4890. setupStructureEvents(true);
  4891. //remove all helper / detection elements
  4892. if (_contentGlueElement)
  4893. remove(_contentGlueElement);
  4894. if (_contentArrangeElement)
  4895. remove(_contentArrangeElement);
  4896. if (_sizeAutoObserverAdded)
  4897. remove(_sizeAutoObserverElement);
  4898. //remove all generated DOM
  4899. setupScrollbarsDOM(true);
  4900. setupScrollbarCornerDOM(true);
  4901. setupStructureDOM(true);
  4902. //remove all generated image load events
  4903. for(var i = 0; i < _imgs[LEXICON.l]; i++)
  4904. FRAMEWORK(_imgs[i]).off('load', imgOnLoad);
  4905. _imgs = undefined;
  4906. //remove this instance from the instances list
  4907. INSTANCES(pluginTargetElement, 0);
  4908. dispatchCallback("onDestroyed");
  4909. //remove all properties and methods
  4910. for (var property in _base)
  4911. delete _base[property];
  4912. _base = undefined;
  4913. };
  4914. /**
  4915. * Scrolls to a given position or element.
  4916. * @param coordinates
  4917. * 1. Can be "coordinates" which looks like:
  4918. * { x : ?, y : ? } OR Object with x and y properties
  4919. * { left : ?, top : ? } OR Object with left and top properties
  4920. * { l : ?, t : ? } OR Object with l and t properties
  4921. * [ ?, ? ] OR Array where the first two element are the coordinates (first is x, second is y)
  4922. * ? A single value which stays for both axis
  4923. * A value can be a number, a string or a calculation.
  4924. *
  4925. * Operators:
  4926. * [NONE] The current scroll will be overwritten by the value.
  4927. * '+=' The value will be added to the current scroll offset
  4928. * '-=' The value will be subtracted from the current scroll offset
  4929. * '*=' The current scroll wil be multiplicated by the value.
  4930. * '/=' The current scroll wil be divided by the value.
  4931. *
  4932. * Units:
  4933. * [NONE] The value is the final scroll amount. final = (value * 1)
  4934. * 'px' Same as none
  4935. * '%' The value is dependent on the current scroll value. final = ((currentScrollValue / 100) * value)
  4936. * 'vw' The value is multiplicated by the viewport width. final = (value * viewportWidth)
  4937. * 'vh' The value is multiplicated by the viewport height. final = (value * viewportHeight)
  4938. *
  4939. * example final values:
  4940. * 200, '200px', '50%', '1vw', '1vh', '+=200', '/=1vw', '*=2px', '-=5vh', '+=33%', '+= 50% - 2px', '-= 1vw - 50%'
  4941. *
  4942. * 2. Can be a HTML or jQuery element:
  4943. * The final scroll offset is the offset (without margin) of the given HTML / jQuery element.
  4944. *
  4945. * 3. Can be a object with a HTML or jQuery element with additional settings:
  4946. * {
  4947. * el : [HTMLElement, jQuery element], MUST be specified, else this object isn't valid.
  4948. * scroll : [string, array, object], Default value is 'always'.
  4949. * block : [string, array, object], Default value is 'begin'.
  4950. * margin : [number, boolean, array, object] Default value is false.
  4951. * }
  4952. *
  4953. * Possible scroll settings are:
  4954. * 'always' Scrolls always.
  4955. * 'ifneeded' Scrolls only if the element isnt fully in view.
  4956. * 'never' Scrolls never.
  4957. *
  4958. * Possible block settings are:
  4959. * 'begin' Both axis shall be docked to the "begin" edge. - The element will be docked to the top and left edge of the viewport.
  4960. * '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.)
  4961. * 'center' Both axis shall be docked to "center". - The element will be centered in the viewport.
  4962. * 'nearest' The element will be docked to the nearest edge(s).
  4963. *
  4964. * Possible margin settings are: -- The actual margin of the element wont be affect, this option affects only the final scroll offset.
  4965. * [BOOLEAN] If true the css margin of the element will be used, if false no margin will be used.
  4966. * [NUMBER] The margin will be used for all edges.
  4967. *
  4968. * @param duration The duration of the scroll animation, OR a jQuery animation configuration object.
  4969. * @param easing The animation easing.
  4970. * @param complete The animation complete callback.
  4971. * @returns {{
  4972. * position: {x: number, y: number},
  4973. * ratio: {x: number, y: number},
  4974. * max: {x: number, y: number},
  4975. * handleOffset: {x: number, y: number},
  4976. * handleLength: {x: number, y: number},
  4977. * handleLengthRatio: {x: number, y: number}, t
  4978. * rackLength: {x: number, y: number},
  4979. * isRTL: boolean,
  4980. * isRTLNormalized: boolean
  4981. * }}
  4982. */
  4983. _base.scroll = function (coordinates, duration, easing, complete) {
  4984. if (arguments.length === 0 || coordinates === undefined) {
  4985. var infoX = _scrollHorizontalInfo;
  4986. var infoY = _scrollVerticalInfo;
  4987. var normalizeInvert = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.i;
  4988. var normalizeNegate = _normalizeRTLCache && _isRTL && _rtlScrollBehavior.n;
  4989. var scrollX = infoX._currentScroll;
  4990. var scrollXRatio = infoX._currentScrollRatio;
  4991. var maxScrollX = infoX._maxScroll;
  4992. scrollXRatio = normalizeInvert ? 1 - scrollXRatio : scrollXRatio;
  4993. scrollX = normalizeInvert ? maxScrollX - scrollX : scrollX;
  4994. scrollX *= normalizeNegate ? -1 : 1;
  4995. maxScrollX *= normalizeNegate ? -1 : 1;
  4996. return {
  4997. position : {
  4998. x : scrollX,
  4999. y : infoY._currentScroll
  5000. },
  5001. ratio : {
  5002. x : scrollXRatio,
  5003. y : infoY._currentScrollRatio
  5004. },
  5005. max : {
  5006. x : maxScrollX,
  5007. y : infoY._maxScroll
  5008. },
  5009. handleOffset : {
  5010. x : infoX._handleOffset,
  5011. y : infoY._handleOffset
  5012. },
  5013. handleLength : {
  5014. x : infoX._handleLength,
  5015. y : infoY._handleLength
  5016. },
  5017. handleLengthRatio : {
  5018. x : infoX._handleLengthRatio,
  5019. y : infoY._handleLengthRatio
  5020. },
  5021. trackLength : {
  5022. x : infoX._trackLength,
  5023. y : infoY._trackLength
  5024. },
  5025. snappedHandleOffset : {
  5026. x : infoX._snappedHandleOffset,
  5027. y : infoY._snappedHandleOffset
  5028. },
  5029. isRTL: _isRTL,
  5030. isRTLNormalized: _normalizeRTLCache
  5031. };
  5032. }
  5033. var normalizeRTL = _normalizeRTLCache;
  5034. var coordinatesXAxisProps = [_strX, _strLeft, 'l'];
  5035. var coordinatesYAxisProps = [_strY, _strTop, 't'];
  5036. var coordinatesOperators = ['+=', '-=', '*=', '/='];
  5037. var durationIsObject = type(duration) == TYPES.o;
  5038. var completeCallback = durationIsObject ? duration.complete : complete;
  5039. var i;
  5040. var finalScroll = { };
  5041. var specialEasing = {};
  5042. var doScrollLeft;
  5043. var doScrollTop;
  5044. var animationOptions;
  5045. var strEnd = 'end';
  5046. var strBegin = 'begin';
  5047. var strCenter = 'center';
  5048. var strNearest = 'nearest';
  5049. var strAlways = 'always';
  5050. var strNever = 'never';
  5051. var strIfNeeded = 'ifneeded';
  5052. var strLength = LEXICON.l;
  5053. var settingsAxis;
  5054. var settingsScroll;
  5055. var settingsBlock;
  5056. var settingsMargin;
  5057. var finalElement;
  5058. var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx'];
  5059. var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest];
  5060. var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded];
  5061. var coordinatesIsElementObj = coordinates.hasOwnProperty('el');
  5062. var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates;
  5063. var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false;
  5064. var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement);
  5065. var proxyCompleteCallback = type(completeCallback) != TYPES.f ? undefined : function() {
  5066. if(doScrollLeft)
  5067. refreshScrollbarHandleOffset(true);
  5068. if(doScrollTop)
  5069. refreshScrollbarHandleOffset(false);
  5070. completeCallback();
  5071. };
  5072. var checkSettingsStringValue = function (currValue, allowedValues) {
  5073. for (i = 0; i < allowedValues[strLength]; i++) {
  5074. if (currValue === allowedValues[i])
  5075. return true;
  5076. }
  5077. return false;
  5078. };
  5079. var getRawScroll = function (isX, coordinates) {
  5080. var coordinateProps = isX ? coordinatesXAxisProps : coordinatesYAxisProps;
  5081. coordinates = type(coordinates) == TYPES.s || type(coordinates) == TYPES.n ? [ coordinates, coordinates ] : coordinates;
  5082. if (type(coordinates) == TYPES.a)
  5083. return isX ? coordinates[0] : coordinates[1];
  5084. else if (type(coordinates) == TYPES.o) {
  5085. //decides RTL normalization "hack" with .n
  5086. //normalizeRTL = type(coordinates.n) == TYPES.b ? coordinates.n : normalizeRTL;
  5087. for (i = 0; i < coordinateProps[strLength]; i++)
  5088. if (coordinateProps[i] in coordinates)
  5089. return coordinates[coordinateProps[i]];
  5090. }
  5091. };
  5092. var getFinalScroll = function (isX, rawScroll) {
  5093. var isString = type(rawScroll) == TYPES.s;
  5094. if(isString)
  5095. _base.update(_strAuto + '+');
  5096. var operator;
  5097. var amount;
  5098. var scrollInfo = isX ? _scrollHorizontalInfo : _scrollVerticalInfo;
  5099. var currScroll = scrollInfo._currentScroll;
  5100. var maxScroll = scrollInfo._maxScroll;
  5101. var mult = ' * ';
  5102. var finalValue;
  5103. var isRTLisX = _isRTL && isX;
  5104. var normalizeShortcuts = isRTLisX && _rtlScrollBehavior.n && !normalizeRTL;
  5105. var strReplace = 'replace';
  5106. var evalFunc = eval;
  5107. var possibleOperator;
  5108. if (isString) {
  5109. //check operator
  5110. if (rawScroll[strLength] > 2) {
  5111. possibleOperator = rawScroll.substr(0, 2);
  5112. if(FRAMEWORK.inArray(possibleOperator, coordinatesOperators) > -1)
  5113. operator = possibleOperator;
  5114. }
  5115. //calculate units and shortcuts
  5116. rawScroll = operator ? rawScroll.substr(2) : rawScroll;
  5117. rawScroll = rawScroll
  5118. [strReplace](/min/g, 0) //'min' = 0%
  5119. [strReplace](/</g, 0) //'<' = 0%
  5120. [strReplace](/max/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'max' = 100%
  5121. [strReplace](/>/g, (normalizeShortcuts ? '-' : _strEmpty) + _strHundredPercent) //'>' = 100%
  5122. [strReplace](/px/g, _strEmpty)
  5123. [strReplace](/%/g, mult + (maxScroll * (isRTLisX && _rtlScrollBehavior.n ? -1 : 1) / 100.0))
  5124. [strReplace](/vw/g, mult + _viewportSize.w)
  5125. [strReplace](/vh/g, mult + _viewportSize.h);
  5126. amount = parseToZeroOrNumber(isNaN(rawScroll) ? parseToZeroOrNumber(evalFunc(rawScroll), true).toFixed() : rawScroll);
  5127. }
  5128. else {
  5129. amount = rawScroll;
  5130. }
  5131. if (amount !== undefined && !isNaN(amount) && type(amount) == TYPES.n) {
  5132. var normalizeIsRTLisX = normalizeRTL && isRTLisX;
  5133. var operatorCurrScroll = currScroll * (normalizeIsRTLisX && _rtlScrollBehavior.n ? -1 : 1);
  5134. var invert = normalizeIsRTLisX && _rtlScrollBehavior.i;
  5135. var negate = normalizeIsRTLisX && _rtlScrollBehavior.n;
  5136. operatorCurrScroll = invert ? (maxScroll - operatorCurrScroll) : operatorCurrScroll;
  5137. switch (operator) {
  5138. case '+=':
  5139. finalValue = operatorCurrScroll + amount;
  5140. break;
  5141. case '-=':
  5142. finalValue = operatorCurrScroll - amount;
  5143. break;
  5144. case '*=':
  5145. finalValue = operatorCurrScroll * amount;
  5146. break;
  5147. case '/=':
  5148. finalValue = operatorCurrScroll / amount;
  5149. break;
  5150. default:
  5151. finalValue = amount;
  5152. break;
  5153. }
  5154. finalValue = invert ? maxScroll - finalValue : finalValue;
  5155. finalValue *= negate ? -1 : 1;
  5156. finalValue = isRTLisX && _rtlScrollBehavior.n ? MATH.min(0, MATH.max(maxScroll, finalValue)) : MATH.max(0, MATH.min(maxScroll, finalValue));
  5157. }
  5158. return finalValue === currScroll ? undefined : finalValue;
  5159. };
  5160. var getPerAxisValue = function (value, valueInternalType, defaultValue, allowedValues) {
  5161. var resultDefault = [ defaultValue, defaultValue ];
  5162. var valueType = type(value);
  5163. var valueArrLength;
  5164. var valueArrItem;
  5165. //value can be [ string, or array of two strings ]
  5166. if (valueType == valueInternalType) {
  5167. value = [value, value];
  5168. }
  5169. else if (valueType == TYPES.a) {
  5170. valueArrLength = value[strLength];
  5171. if (valueArrLength > 2 || valueArrLength < 1)
  5172. value = resultDefault;
  5173. else {
  5174. if (valueArrLength === 1)
  5175. value[1] = defaultValue;
  5176. for (i = 0; i < valueArrLength; i++) {
  5177. valueArrItem = value[i];
  5178. if (type(valueArrItem) != valueInternalType || !checkSettingsStringValue(valueArrItem, allowedValues)) {
  5179. value = resultDefault;
  5180. break;
  5181. }
  5182. }
  5183. }
  5184. }
  5185. else if (valueType == TYPES.o)
  5186. value = [ value[_strX]|| defaultValue, value[_strY] || defaultValue];
  5187. else
  5188. value = resultDefault;
  5189. return { x : value[0], y : value[1] };
  5190. };
  5191. var generateMargin = function (marginTopRightBottomLeftArray) {
  5192. var result = [ ];
  5193. var currValue;
  5194. var currValueType;
  5195. var valueDirections = [ _strTop, _strRight, _strBottom, _strLeft ];
  5196. for(i = 0; i < marginTopRightBottomLeftArray[strLength]; i++) {
  5197. if(i === valueDirections[strLength])
  5198. break;
  5199. currValue = marginTopRightBottomLeftArray[i];
  5200. currValueType = type(currValue);
  5201. if(currValueType == TYPES.b)
  5202. result.push(currValue ? parseToZeroOrNumber(finalElement.css(_strMarginMinus + valueDirections[i])) : 0);
  5203. else
  5204. result.push(currValueType == TYPES.n ? currValue : 0);
  5205. }
  5206. return result;
  5207. };
  5208. if (possibleElementIsJQuery || possibleElementIsHTMLElement) {
  5209. //get settings
  5210. var margin = coordinatesIsElementObj ? coordinates.margin : 0;
  5211. var axis = coordinatesIsElementObj ? coordinates.axis : 0;
  5212. var scroll = coordinatesIsElementObj ? coordinates.scroll : 0;
  5213. var block = coordinatesIsElementObj ? coordinates.block : 0;
  5214. var marginDefault = [ 0, 0, 0, 0 ];
  5215. var marginType = type(margin);
  5216. var marginLength;
  5217. finalElement = possibleElementIsJQuery ? possibleElement : FRAMEWORK(possibleElement);
  5218. if (finalElement[strLength] === 0)
  5219. return;
  5220. _base.update(_strAuto + '+');
  5221. //margin can be [ boolean, number, array of 2, array of 4, object ]
  5222. if (marginType == TYPES.n || marginType == TYPES.b)
  5223. margin = generateMargin([margin, margin, margin, margin]);
  5224. else if (marginType == TYPES.a) {
  5225. marginLength = margin[strLength];
  5226. if(marginLength === 2)
  5227. margin = generateMargin([margin[0], margin[1], margin[0], margin[1]]);
  5228. else if(marginLength >= 4)
  5229. margin = generateMargin(margin);
  5230. else
  5231. margin = marginDefault;
  5232. }
  5233. else if (marginType == TYPES.o)
  5234. margin = generateMargin([margin[_strTop], margin[_strRight], margin[_strBottom], margin[_strLeft]]);
  5235. else
  5236. margin = marginDefault;
  5237. //block = type(block) === TYPES.b ? block ? [ strNearest, strBegin ] : [ strNearest, strEnd ] : block;
  5238. settingsAxis = checkSettingsStringValue(axis, elementObjSettingsAxisValues) ? axis : 'xy';
  5239. settingsScroll = getPerAxisValue(scroll, TYPES.s, strAlways, elementObjSettingsScrollValues);
  5240. settingsBlock = getPerAxisValue(block, TYPES.s, strBegin, elementObjSettingsBlockValues);
  5241. settingsMargin = margin;
  5242. var viewportScroll = {
  5243. l: _scrollHorizontalInfo._currentScroll,
  5244. t: _scrollVerticalInfo._currentScroll
  5245. };
  5246. // use padding element instead of viewport element because padding element has never padding, margin or position applied.
  5247. var viewportOffset = _paddingElement.offset();
  5248. //get coordinates
  5249. var elementOffset = finalElement.offset();
  5250. var doNotScroll = {
  5251. x : settingsScroll.x == strNever || settingsAxis == _strY,
  5252. y : settingsScroll.y == strNever || settingsAxis == _strX
  5253. };
  5254. elementOffset[_strTop] -= settingsMargin[0];
  5255. elementOffset[_strLeft] -= settingsMargin[3];
  5256. var elementScrollCoordinates = {
  5257. x: MATH.round(elementOffset[_strLeft] - viewportOffset[_strLeft] + viewportScroll.l),
  5258. y: MATH.round(elementOffset[_strTop] - viewportOffset[_strTop] + viewportScroll.t)
  5259. };
  5260. if (_isRTL) {
  5261. if (!_rtlScrollBehavior.n && !_rtlScrollBehavior.i)
  5262. elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + viewportScroll.l);
  5263. if (_rtlScrollBehavior.n && normalizeRTL)
  5264. elementScrollCoordinates.x *= -1;
  5265. if (_rtlScrollBehavior.i && normalizeRTL)
  5266. elementScrollCoordinates.x = MATH.round(viewportOffset[_strLeft] - elementOffset[_strLeft] + (_scrollHorizontalInfo._maxScroll - viewportScroll.l));
  5267. }
  5268. //measuring is required
  5269. if (settingsBlock.x != strBegin || settingsBlock.y != strBegin || settingsScroll.x == strIfNeeded || settingsScroll.y == strIfNeeded || _isRTL) {
  5270. var measuringElm = finalElement[0];
  5271. var rawElementSize = _supportTransform ? measuringElm.getBoundingClientRect() : {
  5272. width : measuringElm[LEXICON.oW],
  5273. height : measuringElm[LEXICON.oH]
  5274. };
  5275. var elementSize = {
  5276. w: rawElementSize[_strWidth] + settingsMargin[3] + settingsMargin[1],
  5277. h: rawElementSize[_strHeight] + settingsMargin[0] + settingsMargin[2]
  5278. };
  5279. var finalizeBlock = function(isX) {
  5280. var vars = getScrollbarVars(isX);
  5281. var wh = vars._w_h;
  5282. var lt = vars._left_top;
  5283. var xy = vars._x_y;
  5284. var blockIsEnd = settingsBlock[xy] == (isX ? _isRTL ? strBegin : strEnd : strEnd);
  5285. var blockIsCenter = settingsBlock[xy] == strCenter;
  5286. var blockIsNearest = settingsBlock[xy] == strNearest;
  5287. var scrollNever = settingsScroll[xy] == strNever;
  5288. var scrollIfNeeded = settingsScroll[xy] == strIfNeeded;
  5289. var vpSize = _viewportSize[wh];
  5290. var vpOffset = viewportOffset[lt];
  5291. var elSize = elementSize[wh];
  5292. var elOffset = elementOffset[lt];
  5293. var divide = blockIsCenter ? 2 : 1;
  5294. var elementCenterOffset = elOffset + (elSize / 2);
  5295. var viewportCenterOffset = vpOffset + (vpSize / 2);
  5296. var isInView =
  5297. elSize <= vpSize
  5298. && elOffset >= vpOffset
  5299. && elOffset + elSize <= vpOffset + vpSize;
  5300. if(scrollNever)
  5301. doNotScroll[xy] = true;
  5302. else if(!doNotScroll[xy]) {
  5303. if (blockIsNearest || scrollIfNeeded) {
  5304. doNotScroll[xy] = scrollIfNeeded ? isInView : false;
  5305. blockIsEnd = elSize < vpSize ? elementCenterOffset > viewportCenterOffset : elementCenterOffset < viewportCenterOffset;
  5306. }
  5307. elementScrollCoordinates[xy] -= blockIsEnd || blockIsCenter ? ((vpSize / divide) - (elSize / divide)) * (isX && _isRTL && normalizeRTL ? -1 : 1) : 0;
  5308. }
  5309. };
  5310. finalizeBlock(true);
  5311. finalizeBlock(false);
  5312. }
  5313. if (doNotScroll.y)
  5314. delete elementScrollCoordinates.y;
  5315. if (doNotScroll.x)
  5316. delete elementScrollCoordinates.x;
  5317. coordinates = elementScrollCoordinates;
  5318. }
  5319. finalScroll[_strScrollLeft] = getFinalScroll(true, getRawScroll(true, coordinates));
  5320. finalScroll[_strScrollTop] = getFinalScroll(false, getRawScroll(false, coordinates));
  5321. doScrollLeft = finalScroll[_strScrollLeft] !== undefined;
  5322. doScrollTop = finalScroll[_strScrollTop] !== undefined;
  5323. if ((doScrollLeft || doScrollTop) && (duration > 0 || durationIsObject)) {
  5324. if (durationIsObject) {
  5325. duration.complete = proxyCompleteCallback;
  5326. _viewportElement.animate(finalScroll, duration);
  5327. }
  5328. else {
  5329. animationOptions = {
  5330. duration: duration,
  5331. complete: proxyCompleteCallback
  5332. };
  5333. if (type(easing) == TYPES.a || FRAMEWORK.isPlainObject(easing)) {
  5334. specialEasing[_strScrollLeft] = easing[0] || easing.x;
  5335. specialEasing[_strScrollTop] = easing[1] || easing.y;
  5336. animationOptions.specialEasing = specialEasing;
  5337. }
  5338. else {
  5339. animationOptions.easing = easing;
  5340. }
  5341. _viewportElement.animate(finalScroll, animationOptions);
  5342. }
  5343. }
  5344. else {
  5345. if (doScrollLeft)
  5346. _viewportElement[_strScrollLeft](finalScroll[_strScrollLeft]);
  5347. if (doScrollTop)
  5348. _viewportElement[_strScrollTop](finalScroll[_strScrollTop]);
  5349. }
  5350. };
  5351. /**
  5352. * Stops all scroll animations.
  5353. * @returns {*} The current OverlayScrollbars instance (for chaining).
  5354. */
  5355. _base.scrollStop = function (param1, param2, param3) {
  5356. _viewportElement.stop(param1, param2, param3);
  5357. return _base;
  5358. };
  5359. /**
  5360. * Returns all relevant elements.
  5361. * @param elementName The name of the element which shall be returned.
  5362. * @returns {{target: *, host: *, padding: *, viewport: *, content: *, scrollbarHorizontal: {scrollbar: *, track: *, handle: *}, scrollbarVertical: {scrollbar: *, track: *, handle: *}, scrollbarCorner: *} | *}
  5363. */
  5364. _base.getElements = function (elementName) {
  5365. var obj = {
  5366. target: _targetElementNative,
  5367. host: _hostElementNative,
  5368. padding: _paddingElementNative,
  5369. viewport: _viewportElementNative,
  5370. content: _contentElementNative,
  5371. scrollbarHorizontal: {
  5372. scrollbar: _scrollbarHorizontalElement[0],
  5373. track: _scrollbarHorizontalTrackElement[0],
  5374. handle: _scrollbarHorizontalHandleElement[0]
  5375. },
  5376. scrollbarVertical: {
  5377. scrollbar: _scrollbarVerticalElement[0],
  5378. track: _scrollbarVerticalTrackElement[0],
  5379. handle: _scrollbarVerticalHandleElement[0]
  5380. },
  5381. scrollbarCorner: _scrollbarCornerElement[0]
  5382. };
  5383. return type(elementName) == TYPES.s ? getObjectPropVal(obj, elementName) : obj;
  5384. };
  5385. /**
  5386. * Returns a object which describes the current state of this instance.
  5387. * @param stateProperty A specific property from the state object which shall be returned.
  5388. * @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *}
  5389. */
  5390. _base.getState = function (stateProperty) {
  5391. var prepare = function (obj) {
  5392. if (!FRAMEWORK.isPlainObject(obj))
  5393. return obj;
  5394. var extended = extendDeep({}, obj);
  5395. var changePropertyName = function (from, to) {
  5396. if (extended.hasOwnProperty(from)) {
  5397. extended[to] = extended[from];
  5398. delete extended[from];
  5399. }
  5400. };
  5401. changePropertyName('w', _strWidth); //change w to width
  5402. changePropertyName('h', _strHeight); //change h to height
  5403. delete extended.c; //delete c (the 'changed' prop)
  5404. return extended;
  5405. };
  5406. var obj = {
  5407. sleeping: prepare(_isSleeping) || false,
  5408. autoUpdate: prepare(!_mutationObserversConnected),
  5409. widthAuto: prepare(_widthAutoCache),
  5410. heightAuto: prepare(_heightAutoCache),
  5411. padding: prepare(_cssPaddingCache),
  5412. overflowAmount: prepare(_overflowAmountCache),
  5413. hideOverflow: prepare(_hideOverflowCache),
  5414. hasOverflow: prepare(_hasOverflowCache),
  5415. contentScrollSize: prepare(_contentScrollSizeCache),
  5416. viewportSize: prepare(_viewportSize),
  5417. hostSize: prepare(_hostSizeCache),
  5418. documentMixed : prepare(_documentMixed)
  5419. };
  5420. return type(stateProperty) == TYPES.s ? getObjectPropVal(obj, stateProperty) : obj;
  5421. };
  5422. /**
  5423. * Gets all or specific extension instance.
  5424. * @param extName The name of the extension from which the instance shall be got.
  5425. * @returns {{}} The instance of the extension with the given name or undefined if the instance couldn't be found.
  5426. */
  5427. _base.ext = function(extName) {
  5428. var result;
  5429. var privateMethods = _extensionsPrivateMethods.split(' ');
  5430. var i = 0;
  5431. if(type(extName) == TYPES.s) {
  5432. if(_extensions.hasOwnProperty(extName)) {
  5433. result = extendDeep({}, _extensions[extName]);
  5434. for (; i < privateMethods.length; i++)
  5435. delete result[privateMethods[i]];
  5436. }
  5437. }
  5438. else {
  5439. result = { };
  5440. for(i in _extensions)
  5441. result[i] = extendDeep({ }, _base.ext(i));
  5442. }
  5443. return result;
  5444. };
  5445. /**
  5446. * Adds a extension to this instance.
  5447. * @param extName The name of the extension which shall be added.
  5448. * @param extensionOptions The extension options which shall be used.
  5449. * @returns {{}} The instance of the added extension or undefined if the extension couldn't be added properly.
  5450. */
  5451. _base.addExt = function(extName, extensionOptions) {
  5452. var registeredExtensionObj = window[PLUGINNAME].extension(extName);
  5453. var instance;
  5454. var instanceAdded;
  5455. var instanceContract;
  5456. var contractResult;
  5457. var contractFulfilled = true;
  5458. if(registeredExtensionObj) {
  5459. if(!_extensions.hasOwnProperty(extName)) {
  5460. instance = registeredExtensionObj.extensionFactory.call(_base,
  5461. extendDeep({ }, registeredExtensionObj.defaultOptions),
  5462. FRAMEWORK,
  5463. COMPATIBILITY);
  5464. if (instance) {
  5465. instanceContract = instance.contract;
  5466. if (type(instanceContract) == TYPES.f) {
  5467. contractResult = instanceContract(window);
  5468. contractFulfilled = type(contractResult) == TYPES.b ? contractResult : contractFulfilled;
  5469. }
  5470. if(contractFulfilled) {
  5471. _extensions[extName] = instance;
  5472. instanceAdded = instance.added;
  5473. if(type(instanceAdded) == TYPES.f)
  5474. instanceAdded(extensionOptions);
  5475. return _base.ext(extName);
  5476. }
  5477. }
  5478. }
  5479. else
  5480. return _base.ext(extName);
  5481. }
  5482. else
  5483. console.warn("A extension with the name \"" + extName + "\" isn't registered.");
  5484. };
  5485. /**
  5486. * Removes a extension from this instance.
  5487. * @param extName The name of the extension which shall be removed.
  5488. * @returns {boolean} True if the extension was removed, false otherwise e.g. if the extension wasn't added before.
  5489. */
  5490. _base.removeExt = function(extName) {
  5491. var instance = _extensions[extName];
  5492. var instanceRemoved;
  5493. if(instance) {
  5494. delete _extensions[extName];
  5495. instanceRemoved = instance.removed;
  5496. if(type(instanceRemoved) == TYPES.f)
  5497. instanceRemoved();
  5498. return true;
  5499. }
  5500. return false;
  5501. };
  5502. /**
  5503. * Constructs the plugin.
  5504. * @param targetElement The element to which the plugin shall be applied.
  5505. * @param options The initial options of the plugin.
  5506. * @param extensions The extension(s) which shall be added right after the initialization.
  5507. * @returns {boolean} True if the plugin was successfully initialized, false otherwise.
  5508. */
  5509. function construct(targetElement, options, extensions) {
  5510. _defaultOptions = globals.defaultOptions;
  5511. _nativeScrollbarStyling = globals.nativeScrollbarStyling;
  5512. _nativeScrollbarSize = extendDeep({}, globals.nativeScrollbarSize);
  5513. _nativeScrollbarIsOverlaid = extendDeep({}, globals.nativeScrollbarIsOverlaid);
  5514. _overlayScrollbarDummySize = extendDeep({}, globals.overlayScrollbarDummySize);
  5515. _rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior);
  5516. //parse & set options but don't update
  5517. setOptions(extendDeep({ }, _defaultOptions, _pluginsOptions._validate(options, _pluginsOptions._template, true)));
  5518. //check if the plugin hasn't to be initialized
  5519. if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.x && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) {
  5520. dispatchCallback("onInitializationWithdrawn");
  5521. return false;
  5522. }
  5523. _cssCalc = globals.cssCalc;
  5524. _msieVersion = globals.msie;
  5525. _autoUpdateRecommended = globals.autoUpdateRecommended;
  5526. _supportTransition = globals.supportTransition;
  5527. _supportTransform = globals.supportTransform;
  5528. _supportPassiveEvents = globals.supportPassiveEvents;
  5529. _supportResizeObserver = globals.supportResizeObserver;
  5530. _supportMutationObserver = globals.supportMutationObserver;
  5531. _restrictedMeasuring = globals.restrictedMeasuring;
  5532. _documentElement = FRAMEWORK(targetElement.ownerDocument);
  5533. _documentElementNative = _documentElement[0];
  5534. _windowElement = FRAMEWORK(_documentElementNative.defaultView || _documentElementNative.parentWindow);
  5535. _windowElementNative = _windowElement[0];
  5536. _htmlElement = findFirst(_documentElement, 'html');
  5537. _bodyElement = findFirst(_htmlElement, 'body');
  5538. _targetElement = FRAMEWORK(targetElement);
  5539. _targetElementNative = _targetElement[0];
  5540. _isTextarea = _targetElement.is('textarea');
  5541. _isBody = _targetElement.is('body');
  5542. _documentMixed = _documentElementNative !== document;
  5543. var initBodyScroll;
  5544. if (_isBody) {
  5545. initBodyScroll = {};
  5546. initBodyScroll.l = MATH.max(_targetElement[_strScrollLeft](), _htmlElement[_strScrollLeft](), _windowElement[_strScrollLeft]());
  5547. initBodyScroll.t = MATH.max(_targetElement[_strScrollTop](), _htmlElement[_strScrollTop](), _windowElement[_strScrollTop]());
  5548. }
  5549. //build OverlayScrollbars DOM and Events
  5550. setupStructureDOM();
  5551. setupStructureEvents();
  5552. //build Scrollbars DOM and Events
  5553. setupScrollbarsDOM();
  5554. setupScrollbarEvents(true);
  5555. setupScrollbarEvents(false);
  5556. //build Scrollbar Corner DOM and Events
  5557. setupScrollbarCornerDOM();
  5558. setupScrollbarCornerEvents();
  5559. //create mutation observers
  5560. createMutationObservers();
  5561. if(_isBody) {
  5562. //apply the body scroll to handle it right in the update method
  5563. _viewportElement[_strScrollLeft](initBodyScroll.l)[_strScrollTop](initBodyScroll.t);
  5564. //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
  5565. if(document.activeElement == targetElement && _viewportElementNative.focus) {
  5566. //set a tabindex to make the viewportElement focusable
  5567. _viewportElement.attr('tabindex', '-1');
  5568. _viewportElementNative.focus();
  5569. /* the tabindex has to be removed due to;
  5570. * 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
  5571. * https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
  5572. */
  5573. _viewportElement.one(_strMouseTouchDownEvent, function() {
  5574. _viewportElement.removeAttr('tabindex');
  5575. });
  5576. }
  5577. }
  5578. //build resize observer for the host element
  5579. addResizeObserver(_sizeObserverElement, hostOnResized);
  5580. //update for the first time
  5581. hostOnResized(); //initialize cache for host size
  5582. _base.update(_strAuto); //initialize cache for content
  5583. //the plugin is initialized now!
  5584. _initialized = true;
  5585. dispatchCallback("onInitialized");
  5586. //call all callbacks which would fire before the initialized was complete
  5587. FRAMEWORK.each(_callbacksInitQeueue, function(index, value) { dispatchCallback(value.n, value.a); });
  5588. _callbacksInitQeueue = [ ];
  5589. //add extensions
  5590. if(type(extensions) == TYPES.s)
  5591. extensions = [ extensions ];
  5592. if(COMPATIBILITY.isA(extensions))
  5593. FRAMEWORK.each(extensions, function (index, value) {_base.addExt(value); });
  5594. else if(FRAMEWORK.isPlainObject(extensions))
  5595. FRAMEWORK.each(extensions, function (key, value) { _base.addExt(key, value); });
  5596. //add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions)
  5597. setTimeout(function () {
  5598. if (_supportTransition && !_destroyed)
  5599. addClass(_hostElement, _classNameHostTransition);
  5600. }, 333);
  5601. return _initialized;
  5602. }
  5603. if (construct(pluginTargetElement, options, extensions)) {
  5604. INSTANCES(pluginTargetElement, _base);
  5605. return _base;
  5606. }
  5607. _base = undefined;
  5608. }
  5609. /**
  5610. * Initializes a new OverlayScrollbarsInstance object or changes options if already initialized or returns the current instance.
  5611. * @param pluginTargetElements The elements to which the Plugin shall be initialized.
  5612. * @param options The custom options with which the plugin shall be initialized.
  5613. * @param extensions The extension(s) which shall be added right after initialization.
  5614. * @returns {*}
  5615. */
  5616. window[PLUGINNAME] = function(pluginTargetElements, options, extensions) {
  5617. if(arguments[LEXICON.l] === 0)
  5618. return this;
  5619. var arr = [ ];
  5620. var optsIsPlainObj = FRAMEWORK.isPlainObject(options);
  5621. var inst;
  5622. var result;
  5623. //pluginTargetElements is null or undefined
  5624. if(!pluginTargetElements)
  5625. return optsIsPlainObj || !options ? result : arr;
  5626. /*
  5627. pluginTargetElements will be converted to:
  5628. 1. A jQueryElement Array
  5629. 2. A HTMLElement Array
  5630. 3. A Array with a single HTML Element
  5631. so pluginTargetElements is always a array.
  5632. */
  5633. pluginTargetElements = pluginTargetElements[LEXICON.l] != undefined ? pluginTargetElements : [ pluginTargetElements[0] || pluginTargetElements ];
  5634. initOverlayScrollbarsStatics();
  5635. if(pluginTargetElements[LEXICON.l] > 0) {
  5636. if(optsIsPlainObj) {
  5637. FRAMEWORK.each(pluginTargetElements, function (i, v) {
  5638. inst = v;
  5639. if(inst !== undefined)
  5640. arr.push(OverlayScrollbarsInstance(inst, options, extensions, _pluginsGlobals, _pluginsAutoUpdateLoop));
  5641. });
  5642. }
  5643. else {
  5644. FRAMEWORK.each(pluginTargetElements, function(i, v) {
  5645. inst = INSTANCES(v);
  5646. if((options === '!' && inst instanceof window[PLUGINNAME]) || (COMPATIBILITY.type(options) == TYPES.f && options(v, inst)))
  5647. arr.push(inst);
  5648. else if(options === undefined)
  5649. arr.push(inst);
  5650. });
  5651. }
  5652. result = arr[LEXICON.l] === 1 ? arr[0] : arr;
  5653. }
  5654. return result;
  5655. };
  5656. /**
  5657. * Returns a object which contains global information about the plugin and each instance of it.
  5658. * The returned object is just a copy, that means that changes to the returned object won't have any effect to the original object.
  5659. */
  5660. window[PLUGINNAME].globals = function () {
  5661. initOverlayScrollbarsStatics();
  5662. var globals = FRAMEWORK.extend(true, { }, _pluginsGlobals);
  5663. delete globals['msie'];
  5664. return globals;
  5665. };
  5666. /**
  5667. * Gets or Sets the default options for each new plugin initialization.
  5668. * @param newDefaultOptions The object with which the default options shall be extended.
  5669. */
  5670. window[PLUGINNAME].defaultOptions = function(newDefaultOptions) {
  5671. initOverlayScrollbarsStatics();
  5672. var currDefaultOptions = _pluginsGlobals.defaultOptions;
  5673. if(newDefaultOptions === undefined)
  5674. return FRAMEWORK.extend(true, { }, currDefaultOptions);
  5675. //set the new default options
  5676. _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, { }, currDefaultOptions , _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true));
  5677. };
  5678. /**
  5679. * Registers, Unregisters or returns a extension.
  5680. * Register: Pass the name and the extension. (defaultOptions is optional)
  5681. * Unregister: Pass the name and anything except a function as extension parameter.
  5682. * Get extension: Pass the name of the extension which shall be got.
  5683. * Get all extensions: Pass no arguments.
  5684. * @param extensionName The name of the extension which shall be registered, unregistered or returned.
  5685. * @param extension A function which generates the instance of the extension or anything other to remove a already registered extension.
  5686. * @param defaultOptions The default options which shall be used for the registered extension.
  5687. */
  5688. window[PLUGINNAME].extension = function(extensionName, extension, defaultOptions) {
  5689. var extNameTypeString = COMPATIBILITY.type(extensionName) == TYPES.s;
  5690. var argLen = arguments[LEXICON.l];
  5691. var i = 0;
  5692. if(argLen < 1 || !extNameTypeString) {
  5693. //return a copy of all extension objects
  5694. return FRAMEWORK.extend(true, { length : _pluginsExtensions[LEXICON.l] }, _pluginsExtensions);
  5695. }
  5696. else if(extNameTypeString) {
  5697. if(COMPATIBILITY.type(extension) == TYPES.f) {
  5698. //register extension
  5699. _pluginsExtensions.push({
  5700. name : extensionName,
  5701. extensionFactory : extension,
  5702. defaultOptions : defaultOptions
  5703. });
  5704. }
  5705. else {
  5706. for(; i < _pluginsExtensions[LEXICON.l]; i++) {
  5707. if (_pluginsExtensions[i].name === extensionName) {
  5708. if(argLen > 1)
  5709. _pluginsExtensions.splice(i, 1); //remove extension
  5710. else
  5711. return FRAMEWORK.extend(true, { }, _pluginsExtensions[i]); //return extension with the given name
  5712. }
  5713. }
  5714. }
  5715. }
  5716. };
  5717. return window[PLUGINNAME];
  5718. })();
  5719. if(JQUERY && JQUERY.fn) {
  5720. /**
  5721. * The jQuery initialization interface.
  5722. * @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.
  5723. * @param extensions The extension(s) which shall be added right after initialization.
  5724. * @returns {*} After initialization it returns the jQuery element array, else it returns the instance(s) of the elements which are selected.
  5725. */
  5726. JQUERY.fn.overlayScrollbars = function (options, extensions) {
  5727. var _elements = this;
  5728. if(JQUERY.isPlainObject(options)) {
  5729. JQUERY.each(_elements, function() { PLUGIN(this, options, extensions); });
  5730. return _elements;
  5731. }
  5732. else
  5733. return PLUGIN(_elements, options);
  5734. };
  5735. }
  5736. return PLUGIN;
  5737. }
  5738. ));