mdui.js 204 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474
  1. /*!
  2. * mdui 1.0.2 (https://mdui.org)
  3. * Copyright 2016-2021 zdhxiong
  4. * Licensed under MIT
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  8. typeof define === 'function' && define.amd ? define(factory) :
  9. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.mdui = factory());
  10. }(this, (function () { 'use strict';
  11. !function(){try{return new MouseEvent("test")}catch(e$1){}var e=function(e,t){t=t||{bubbles:!1,cancelable:!1};var n=document.createEvent("MouseEvent");return n.initMouseEvent(e,t.bubbles,t.cancelable,window,0,t.screenX||0,t.screenY||0,t.clientX||0,t.clientY||0,t.ctrlKey||!1,t.altKey||!1,t.shiftKey||!1,t.metaKey||!1,t.button||0,t.relatedTarget||null),n};e.prototype=Event.prototype,window.MouseEvent=e;}();
  12. !function(){function t(t,e){e=e||{bubbles:!1,cancelable:!1,detail:void 0};var n=document.createEvent("CustomEvent");return n.initCustomEvent(t,e.bubbles,e.cancelable,e.detail),n}"function"!=typeof window.CustomEvent&&(t.prototype=window.Event.prototype,window.CustomEvent=t);}();
  13. /**
  14. * @this {Promise}
  15. */
  16. function finallyConstructor(callback) {
  17. var constructor = this.constructor;
  18. return this.then(
  19. function(value) {
  20. // @ts-ignore
  21. return constructor.resolve(callback()).then(function() {
  22. return value;
  23. });
  24. },
  25. function(reason) {
  26. // @ts-ignore
  27. return constructor.resolve(callback()).then(function() {
  28. // @ts-ignore
  29. return constructor.reject(reason);
  30. });
  31. }
  32. );
  33. }
  34. function allSettled(arr) {
  35. var P = this;
  36. return new P(function(resolve, reject) {
  37. if (!(arr && typeof arr.length !== 'undefined')) {
  38. return reject(
  39. new TypeError(
  40. typeof arr +
  41. ' ' +
  42. arr +
  43. ' is not iterable(cannot read property Symbol(Symbol.iterator))'
  44. )
  45. );
  46. }
  47. var args = Array.prototype.slice.call(arr);
  48. if (args.length === 0) { return resolve([]); }
  49. var remaining = args.length;
  50. function res(i, val) {
  51. if (val && (typeof val === 'object' || typeof val === 'function')) {
  52. var then = val.then;
  53. if (typeof then === 'function') {
  54. then.call(
  55. val,
  56. function(val) {
  57. res(i, val);
  58. },
  59. function(e) {
  60. args[i] = { status: 'rejected', reason: e };
  61. if (--remaining === 0) {
  62. resolve(args);
  63. }
  64. }
  65. );
  66. return;
  67. }
  68. }
  69. args[i] = { status: 'fulfilled', value: val };
  70. if (--remaining === 0) {
  71. resolve(args);
  72. }
  73. }
  74. for (var i = 0; i < args.length; i++) {
  75. res(i, args[i]);
  76. }
  77. });
  78. }
  79. // Store setTimeout reference so promise-polyfill will be unaffected by
  80. // other code modifying setTimeout (like sinon.useFakeTimers())
  81. var setTimeoutFunc = setTimeout;
  82. function isArray(x) {
  83. return Boolean(x && typeof x.length !== 'undefined');
  84. }
  85. function noop() {}
  86. // Polyfill for Function.prototype.bind
  87. function bind(fn, thisArg) {
  88. return function() {
  89. fn.apply(thisArg, arguments);
  90. };
  91. }
  92. /**
  93. * @constructor
  94. * @param {Function} fn
  95. */
  96. function Promise$1(fn) {
  97. if (!(this instanceof Promise$1))
  98. { throw new TypeError('Promises must be constructed via new'); }
  99. if (typeof fn !== 'function') { throw new TypeError('not a function'); }
  100. /** @type {!number} */
  101. this._state = 0;
  102. /** @type {!boolean} */
  103. this._handled = false;
  104. /** @type {Promise|undefined} */
  105. this._value = undefined;
  106. /** @type {!Array<!Function>} */
  107. this._deferreds = [];
  108. doResolve(fn, this);
  109. }
  110. function handle(self, deferred) {
  111. while (self._state === 3) {
  112. self = self._value;
  113. }
  114. if (self._state === 0) {
  115. self._deferreds.push(deferred);
  116. return;
  117. }
  118. self._handled = true;
  119. Promise$1._immediateFn(function() {
  120. var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
  121. if (cb === null) {
  122. (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
  123. return;
  124. }
  125. var ret;
  126. try {
  127. ret = cb(self._value);
  128. } catch (e) {
  129. reject(deferred.promise, e);
  130. return;
  131. }
  132. resolve(deferred.promise, ret);
  133. });
  134. }
  135. function resolve(self, newValue) {
  136. try {
  137. // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
  138. if (newValue === self)
  139. { throw new TypeError('A promise cannot be resolved with itself.'); }
  140. if (
  141. newValue &&
  142. (typeof newValue === 'object' || typeof newValue === 'function')
  143. ) {
  144. var then = newValue.then;
  145. if (newValue instanceof Promise$1) {
  146. self._state = 3;
  147. self._value = newValue;
  148. finale(self);
  149. return;
  150. } else if (typeof then === 'function') {
  151. doResolve(bind(then, newValue), self);
  152. return;
  153. }
  154. }
  155. self._state = 1;
  156. self._value = newValue;
  157. finale(self);
  158. } catch (e) {
  159. reject(self, e);
  160. }
  161. }
  162. function reject(self, newValue) {
  163. self._state = 2;
  164. self._value = newValue;
  165. finale(self);
  166. }
  167. function finale(self) {
  168. if (self._state === 2 && self._deferreds.length === 0) {
  169. Promise$1._immediateFn(function() {
  170. if (!self._handled) {
  171. Promise$1._unhandledRejectionFn(self._value);
  172. }
  173. });
  174. }
  175. for (var i = 0, len = self._deferreds.length; i < len; i++) {
  176. handle(self, self._deferreds[i]);
  177. }
  178. self._deferreds = null;
  179. }
  180. /**
  181. * @constructor
  182. */
  183. function Handler(onFulfilled, onRejected, promise) {
  184. this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  185. this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  186. this.promise = promise;
  187. }
  188. /**
  189. * Take a potentially misbehaving resolver function and make sure
  190. * onFulfilled and onRejected are only called once.
  191. *
  192. * Makes no guarantees about asynchrony.
  193. */
  194. function doResolve(fn, self) {
  195. var done = false;
  196. try {
  197. fn(
  198. function(value) {
  199. if (done) { return; }
  200. done = true;
  201. resolve(self, value);
  202. },
  203. function(reason) {
  204. if (done) { return; }
  205. done = true;
  206. reject(self, reason);
  207. }
  208. );
  209. } catch (ex) {
  210. if (done) { return; }
  211. done = true;
  212. reject(self, ex);
  213. }
  214. }
  215. Promise$1.prototype['catch'] = function(onRejected) {
  216. return this.then(null, onRejected);
  217. };
  218. Promise$1.prototype.then = function(onFulfilled, onRejected) {
  219. // @ts-ignore
  220. var prom = new this.constructor(noop);
  221. handle(this, new Handler(onFulfilled, onRejected, prom));
  222. return prom;
  223. };
  224. Promise$1.prototype['finally'] = finallyConstructor;
  225. Promise$1.all = function(arr) {
  226. return new Promise$1(function(resolve, reject) {
  227. if (!isArray(arr)) {
  228. return reject(new TypeError('Promise.all accepts an array'));
  229. }
  230. var args = Array.prototype.slice.call(arr);
  231. if (args.length === 0) { return resolve([]); }
  232. var remaining = args.length;
  233. function res(i, val) {
  234. try {
  235. if (val && (typeof val === 'object' || typeof val === 'function')) {
  236. var then = val.then;
  237. if (typeof then === 'function') {
  238. then.call(
  239. val,
  240. function(val) {
  241. res(i, val);
  242. },
  243. reject
  244. );
  245. return;
  246. }
  247. }
  248. args[i] = val;
  249. if (--remaining === 0) {
  250. resolve(args);
  251. }
  252. } catch (ex) {
  253. reject(ex);
  254. }
  255. }
  256. for (var i = 0; i < args.length; i++) {
  257. res(i, args[i]);
  258. }
  259. });
  260. };
  261. Promise$1.allSettled = allSettled;
  262. Promise$1.resolve = function(value) {
  263. if (value && typeof value === 'object' && value.constructor === Promise$1) {
  264. return value;
  265. }
  266. return new Promise$1(function(resolve) {
  267. resolve(value);
  268. });
  269. };
  270. Promise$1.reject = function(value) {
  271. return new Promise$1(function(resolve, reject) {
  272. reject(value);
  273. });
  274. };
  275. Promise$1.race = function(arr) {
  276. return new Promise$1(function(resolve, reject) {
  277. if (!isArray(arr)) {
  278. return reject(new TypeError('Promise.race accepts an array'));
  279. }
  280. for (var i = 0, len = arr.length; i < len; i++) {
  281. Promise$1.resolve(arr[i]).then(resolve, reject);
  282. }
  283. });
  284. };
  285. // Use polyfill for setImmediate for performance gains
  286. Promise$1._immediateFn =
  287. // @ts-ignore
  288. (typeof setImmediate === 'function' &&
  289. function(fn) {
  290. // @ts-ignore
  291. setImmediate(fn);
  292. }) ||
  293. function(fn) {
  294. setTimeoutFunc(fn, 0);
  295. };
  296. Promise$1._unhandledRejectionFn = function _unhandledRejectionFn(err) {
  297. if (typeof console !== 'undefined' && console) {
  298. console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
  299. }
  300. };
  301. /** @suppress {undefinedVars} */
  302. var globalNS = (function() {
  303. // the only reliable means to get the global object is
  304. // `Function('return this')()`
  305. // However, this causes CSP violations in Chrome apps.
  306. if (typeof self !== 'undefined') {
  307. return self;
  308. }
  309. if (typeof window !== 'undefined') {
  310. return window;
  311. }
  312. if (typeof global !== 'undefined') {
  313. return global;
  314. }
  315. throw new Error('unable to locate global object');
  316. })();
  317. // Expose the polyfill if Promise is undefined or set to a
  318. // non-function value. The latter can be due to a named HTMLElement
  319. // being exposed by browsers for legacy reasons.
  320. // https://github.com/taylorhakes/promise-polyfill/issues/114
  321. if (typeof globalNS['Promise'] !== 'function') {
  322. globalNS['Promise'] = Promise$1;
  323. } else if (!globalNS.Promise.prototype['finally']) {
  324. globalNS.Promise.prototype['finally'] = finallyConstructor;
  325. } else if (!globalNS.Promise.allSettled) {
  326. globalNS.Promise.allSettled = allSettled;
  327. }
  328. function isFunction(target) {
  329. return typeof target === 'function';
  330. }
  331. function isString(target) {
  332. return typeof target === 'string';
  333. }
  334. function isNumber(target) {
  335. return typeof target === 'number';
  336. }
  337. function isBoolean(target) {
  338. return typeof target === 'boolean';
  339. }
  340. function isUndefined(target) {
  341. return typeof target === 'undefined';
  342. }
  343. function isNull(target) {
  344. return target === null;
  345. }
  346. function isWindow(target) {
  347. return target instanceof Window;
  348. }
  349. function isDocument(target) {
  350. return target instanceof Document;
  351. }
  352. function isElement(target) {
  353. return target instanceof Element;
  354. }
  355. function isNode(target) {
  356. return target instanceof Node;
  357. }
  358. /**
  359. * 是否是 IE 浏览器
  360. */
  361. function isIE() {
  362. // @ts-ignore
  363. return !!window.document.documentMode;
  364. }
  365. function isArrayLike(target) {
  366. if (isFunction(target) || isWindow(target)) {
  367. return false;
  368. }
  369. return isNumber(target.length);
  370. }
  371. function isObjectLike(target) {
  372. return typeof target === 'object' && target !== null;
  373. }
  374. function toElement(target) {
  375. return isDocument(target) ? target.documentElement : target;
  376. }
  377. /**
  378. * 把用 - 分隔的字符串转为驼峰(如 box-sizing 转换为 boxSizing)
  379. * @param string
  380. */
  381. function toCamelCase(string) {
  382. return string
  383. .replace(/^-ms-/, 'ms-')
  384. .replace(/-([a-z])/g, function (_, letter) { return letter.toUpperCase(); });
  385. }
  386. /**
  387. * 把驼峰法转为用 - 分隔的字符串(如 boxSizing 转换为 box-sizing)
  388. * @param string
  389. */
  390. function toKebabCase(string) {
  391. return string.replace(/[A-Z]/g, function (replacer) { return '-' + replacer.toLowerCase(); });
  392. }
  393. /**
  394. * 获取元素的样式值
  395. * @param element
  396. * @param name
  397. */
  398. function getComputedStyleValue(element, name) {
  399. return window.getComputedStyle(element).getPropertyValue(toKebabCase(name));
  400. }
  401. /**
  402. * 检查元素的 box-sizing 是否是 border-box
  403. * @param element
  404. */
  405. function isBorderBox(element) {
  406. return getComputedStyleValue(element, 'box-sizing') === 'border-box';
  407. }
  408. /**
  409. * 获取元素的 padding, border, margin 宽度(两侧宽度的和,单位为px)
  410. * @param element
  411. * @param direction
  412. * @param extra
  413. */
  414. function getExtraWidth(element, direction, extra) {
  415. var position = direction === 'width' ? ['Left', 'Right'] : ['Top', 'Bottom'];
  416. return [0, 1].reduce(function (prev, _, index) {
  417. var prop = extra + position[index];
  418. if (extra === 'border') {
  419. prop += 'Width';
  420. }
  421. return prev + parseFloat(getComputedStyleValue(element, prop) || '0');
  422. }, 0);
  423. }
  424. /**
  425. * 获取元素的样式值,对 width 和 height 进行过处理
  426. * @param element
  427. * @param name
  428. */
  429. function getStyle(element, name) {
  430. // width、height 属性使用 getComputedStyle 得到的值不准确,需要使用 getBoundingClientRect 获取
  431. if (name === 'width' || name === 'height') {
  432. var valueNumber = element.getBoundingClientRect()[name];
  433. if (isBorderBox(element)) {
  434. return (valueNumber + "px");
  435. }
  436. return ((valueNumber -
  437. getExtraWidth(element, name, 'border') -
  438. getExtraWidth(element, name, 'padding')) + "px");
  439. }
  440. return getComputedStyleValue(element, name);
  441. }
  442. /**
  443. * 获取子节点组成的数组
  444. * @param target
  445. * @param parent
  446. */
  447. function getChildNodesArray(target, parent) {
  448. var tempParent = document.createElement(parent);
  449. tempParent.innerHTML = target;
  450. return [].slice.call(tempParent.childNodes);
  451. }
  452. /**
  453. * 始终返回 false 的函数
  454. */
  455. function returnFalse() {
  456. return false;
  457. }
  458. /**
  459. * 数值单位的 CSS 属性
  460. */
  461. var cssNumber = [
  462. 'animationIterationCount',
  463. 'columnCount',
  464. 'fillOpacity',
  465. 'flexGrow',
  466. 'flexShrink',
  467. 'fontWeight',
  468. 'gridArea',
  469. 'gridColumn',
  470. 'gridColumnEnd',
  471. 'gridColumnStart',
  472. 'gridRow',
  473. 'gridRowEnd',
  474. 'gridRowStart',
  475. 'lineHeight',
  476. 'opacity',
  477. 'order',
  478. 'orphans',
  479. 'widows',
  480. 'zIndex',
  481. 'zoom' ];
  482. function each(target, callback) {
  483. if (isArrayLike(target)) {
  484. for (var i = 0; i < target.length; i += 1) {
  485. if (callback.call(target[i], i, target[i]) === false) {
  486. return target;
  487. }
  488. }
  489. }
  490. else {
  491. var keys = Object.keys(target);
  492. for (var i$1 = 0; i$1 < keys.length; i$1 += 1) {
  493. if (callback.call(target[keys[i$1]], keys[i$1], target[keys[i$1]]) === false) {
  494. return target;
  495. }
  496. }
  497. }
  498. return target;
  499. }
  500. /**
  501. * 为了使用模块扩充,这里不能使用默认导出
  502. */
  503. var JQ = function JQ(arr) {
  504. var this$1 = this;
  505. this.length = 0;
  506. if (!arr) {
  507. return this;
  508. }
  509. each(arr, function (i, item) {
  510. // @ts-ignore
  511. this$1[i] = item;
  512. });
  513. this.length = arr.length;
  514. return this;
  515. };
  516. function get$() {
  517. var $ = function (selector) {
  518. if (!selector) {
  519. return new JQ();
  520. }
  521. // JQ
  522. if (selector instanceof JQ) {
  523. return selector;
  524. }
  525. // function
  526. if (isFunction(selector)) {
  527. if (/complete|loaded|interactive/.test(document.readyState) &&
  528. document.body) {
  529. selector.call(document, $);
  530. }
  531. else {
  532. document.addEventListener('DOMContentLoaded', function () { return selector.call(document, $); }, false);
  533. }
  534. return new JQ([document]);
  535. }
  536. // String
  537. if (isString(selector)) {
  538. var html = selector.trim();
  539. // 根据 HTML 字符串创建 JQ 对象
  540. if (html[0] === '<' && html[html.length - 1] === '>') {
  541. var toCreate = 'div';
  542. var tags = {
  543. li: 'ul',
  544. tr: 'tbody',
  545. td: 'tr',
  546. th: 'tr',
  547. tbody: 'table',
  548. option: 'select',
  549. };
  550. each(tags, function (childTag, parentTag) {
  551. if (html.indexOf(("<" + childTag)) === 0) {
  552. toCreate = parentTag;
  553. return false;
  554. }
  555. return;
  556. });
  557. return new JQ(getChildNodesArray(html, toCreate));
  558. }
  559. // 根据 CSS 选择器创建 JQ 对象
  560. var isIdSelector = selector[0] === '#' && !selector.match(/[ .<>:~]/);
  561. if (!isIdSelector) {
  562. return new JQ(document.querySelectorAll(selector));
  563. }
  564. var element = document.getElementById(selector.slice(1));
  565. if (element) {
  566. return new JQ([element]);
  567. }
  568. return new JQ();
  569. }
  570. if (isArrayLike(selector) && !isNode(selector)) {
  571. return new JQ(selector);
  572. }
  573. return new JQ([selector]);
  574. };
  575. $.fn = JQ.prototype;
  576. return $;
  577. }
  578. var $ = get$();
  579. // 避免页面加载完后直接执行css动画
  580. // https://css-tricks.com/transitions-only-after-page-load/
  581. setTimeout(function () { return $('body').addClass('mdui-loaded'); });
  582. var mdui = {
  583. $: $,
  584. };
  585. $.fn.each = function (callback) {
  586. return each(this, callback);
  587. };
  588. /**
  589. * 检查 container 元素内是否包含 contains 元素
  590. * @param container 父元素
  591. * @param contains 子元素
  592. * @example
  593. ```js
  594. contains( document, document.body ); // true
  595. contains( document.getElementById('test'), document ); // false
  596. contains( $('.container').get(0), $('.contains').get(0) ); // false
  597. ```
  598. */
  599. function contains(container, contains) {
  600. return container !== contains && toElement(container).contains(contains);
  601. }
  602. /**
  603. * 把第二个数组的元素追加到第一个数组中,并返回合并后的数组
  604. * @param first 第一个数组
  605. * @param second 该数组的元素将被追加到第一个数组中
  606. * @example
  607. ```js
  608. merge( [ 0, 1, 2 ], [ 2, 3, 4 ] )
  609. // [ 0, 1, 2, 2, 3, 4 ]
  610. ```
  611. */
  612. function merge(first, second) {
  613. each(second, function (_, value) {
  614. first.push(value);
  615. });
  616. return first;
  617. }
  618. $.fn.get = function (index) {
  619. return index === undefined
  620. ? [].slice.call(this)
  621. : this[index >= 0 ? index : index + this.length];
  622. };
  623. $.fn.find = function (selector) {
  624. var foundElements = [];
  625. this.each(function (_, element) {
  626. merge(foundElements, $(element.querySelectorAll(selector)).get());
  627. });
  628. return new JQ(foundElements);
  629. };
  630. // 存储事件
  631. var handlers = {};
  632. // 元素ID
  633. var mduiElementId = 1;
  634. /**
  635. * 为元素赋予一个唯一的ID
  636. */
  637. function getElementId(element) {
  638. var key = '_mduiEventId';
  639. // @ts-ignore
  640. if (!element[key]) {
  641. // @ts-ignore
  642. element[key] = ++mduiElementId;
  643. }
  644. // @ts-ignore
  645. return element[key];
  646. }
  647. /**
  648. * 解析事件名中的命名空间
  649. */
  650. function parse(type) {
  651. var parts = type.split('.');
  652. return {
  653. type: parts[0],
  654. ns: parts.slice(1).sort().join(' '),
  655. };
  656. }
  657. /**
  658. * 命名空间匹配规则
  659. */
  660. function matcherFor(ns) {
  661. return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)');
  662. }
  663. /**
  664. * 获取匹配的事件
  665. * @param element
  666. * @param type
  667. * @param func
  668. * @param selector
  669. */
  670. function getHandlers(element, type, func, selector) {
  671. var event = parse(type);
  672. return (handlers[getElementId(element)] || []).filter(function (handler) { return handler &&
  673. (!event.type || handler.type === event.type) &&
  674. (!event.ns || matcherFor(event.ns).test(handler.ns)) &&
  675. (!func || getElementId(handler.func) === getElementId(func)) &&
  676. (!selector || handler.selector === selector); });
  677. }
  678. /**
  679. * 添加事件监听
  680. * @param element
  681. * @param types
  682. * @param func
  683. * @param data
  684. * @param selector
  685. */
  686. function add(element, types, func, data, selector) {
  687. var elementId = getElementId(element);
  688. if (!handlers[elementId]) {
  689. handlers[elementId] = [];
  690. }
  691. // 传入 data.useCapture 来设置 useCapture: true
  692. var useCapture = false;
  693. if (isObjectLike(data) && data.useCapture) {
  694. useCapture = true;
  695. }
  696. types.split(' ').forEach(function (type) {
  697. if (!type) {
  698. return;
  699. }
  700. var event = parse(type);
  701. function callFn(e, elem) {
  702. // 因为鼠标事件模拟事件的 detail 属性是只读的,因此在 e._detail 中存储参数
  703. var result = func.apply(elem,
  704. // @ts-ignore
  705. e._detail === undefined ? [e] : [e].concat(e._detail));
  706. if (result === false) {
  707. e.preventDefault();
  708. e.stopPropagation();
  709. }
  710. }
  711. function proxyFn(e) {
  712. // @ts-ignore
  713. if (e._ns && !matcherFor(e._ns).test(event.ns)) {
  714. return;
  715. }
  716. // @ts-ignore
  717. e._data = data;
  718. if (selector) {
  719. // 事件代理
  720. $(element)
  721. .find(selector)
  722. .get()
  723. .reverse()
  724. .forEach(function (elem) {
  725. if (elem === e.target ||
  726. contains(elem, e.target)) {
  727. callFn(e, elem);
  728. }
  729. });
  730. }
  731. else {
  732. // 不使用事件代理
  733. callFn(e, element);
  734. }
  735. }
  736. var handler = {
  737. type: event.type,
  738. ns: event.ns,
  739. func: func,
  740. selector: selector,
  741. id: handlers[elementId].length,
  742. proxy: proxyFn,
  743. };
  744. handlers[elementId].push(handler);
  745. element.addEventListener(handler.type, proxyFn, useCapture);
  746. });
  747. }
  748. /**
  749. * 移除事件监听
  750. * @param element
  751. * @param types
  752. * @param func
  753. * @param selector
  754. */
  755. function remove(element, types, func, selector) {
  756. var handlersInElement = handlers[getElementId(element)] || [];
  757. var removeEvent = function (handler) {
  758. delete handlersInElement[handler.id];
  759. element.removeEventListener(handler.type, handler.proxy, false);
  760. };
  761. if (!types) {
  762. handlersInElement.forEach(function (handler) { return removeEvent(handler); });
  763. }
  764. else {
  765. types.split(' ').forEach(function (type) {
  766. if (type) {
  767. getHandlers(element, type, func, selector).forEach(function (handler) { return removeEvent(handler); });
  768. }
  769. });
  770. }
  771. }
  772. $.fn.trigger = function (type, extraParameters) {
  773. var event = parse(type);
  774. var eventObject;
  775. var eventParams = {
  776. bubbles: true,
  777. cancelable: true,
  778. };
  779. var isMouseEvent = ['click', 'mousedown', 'mouseup', 'mousemove'].indexOf(event.type) > -1;
  780. if (isMouseEvent) {
  781. // Note: MouseEvent 无法传入 detail 参数
  782. eventObject = new MouseEvent(event.type, eventParams);
  783. }
  784. else {
  785. eventParams.detail = extraParameters;
  786. eventObject = new CustomEvent(event.type, eventParams);
  787. }
  788. // @ts-ignore
  789. eventObject._detail = extraParameters;
  790. // @ts-ignore
  791. eventObject._ns = event.ns;
  792. return this.each(function () {
  793. this.dispatchEvent(eventObject);
  794. });
  795. };
  796. function extend(target, object1) {
  797. var objectN = [], len = arguments.length - 2;
  798. while ( len-- > 0 ) objectN[ len ] = arguments[ len + 2 ];
  799. objectN.unshift(object1);
  800. each(objectN, function (_, object) {
  801. each(object, function (prop, value) {
  802. if (!isUndefined(value)) {
  803. target[prop] = value;
  804. }
  805. });
  806. });
  807. return target;
  808. }
  809. /**
  810. * 将数组或对象序列化,序列化后的字符串可作为 URL 查询字符串使用
  811. *
  812. * 若传入数组,则格式必须和 serializeArray 方法的返回值一样
  813. * @param obj 对象或数组
  814. * @example
  815. ```js
  816. param({ width: 1680, height: 1050 });
  817. // width=1680&height=1050
  818. ```
  819. * @example
  820. ```js
  821. param({ foo: { one: 1, two: 2 }})
  822. // foo[one]=1&foo[two]=2
  823. ```
  824. * @example
  825. ```js
  826. param({ids: [1, 2, 3]})
  827. // ids[]=1&ids[]=2&ids[]=3
  828. ```
  829. * @example
  830. ```js
  831. param([
  832. {"name":"name","value":"mdui"},
  833. {"name":"password","value":"123456"}
  834. ])
  835. // name=mdui&password=123456
  836. ```
  837. */
  838. function param(obj) {
  839. if (!isObjectLike(obj) && !Array.isArray(obj)) {
  840. return '';
  841. }
  842. var args = [];
  843. function destructure(key, value) {
  844. var keyTmp;
  845. if (isObjectLike(value)) {
  846. each(value, function (i, v) {
  847. if (Array.isArray(value) && !isObjectLike(v)) {
  848. keyTmp = '';
  849. }
  850. else {
  851. keyTmp = i;
  852. }
  853. destructure((key + "[" + keyTmp + "]"), v);
  854. });
  855. }
  856. else {
  857. if (value == null || value === '') {
  858. keyTmp = '=';
  859. }
  860. else {
  861. keyTmp = "=" + (encodeURIComponent(value));
  862. }
  863. args.push(encodeURIComponent(key) + keyTmp);
  864. }
  865. }
  866. if (Array.isArray(obj)) {
  867. each(obj, function () {
  868. destructure(this.name, this.value);
  869. });
  870. }
  871. else {
  872. each(obj, destructure);
  873. }
  874. return args.join('&');
  875. }
  876. // 全局配置参数
  877. var globalOptions = {};
  878. // 全局事件名
  879. var ajaxEvents = {
  880. ajaxStart: 'start.mdui.ajax',
  881. ajaxSuccess: 'success.mdui.ajax',
  882. ajaxError: 'error.mdui.ajax',
  883. ajaxComplete: 'complete.mdui.ajax',
  884. };
  885. /**
  886. * 判断此请求方法是否通过查询字符串提交参数
  887. * @param method 请求方法,大写
  888. */
  889. function isQueryStringData(method) {
  890. return ['GET', 'HEAD'].indexOf(method) >= 0;
  891. }
  892. /**
  893. * 添加参数到 URL 上,且 URL 中不存在 ? 时,自动把第一个 & 替换为 ?
  894. * @param url
  895. * @param query
  896. */
  897. function appendQuery(url, query) {
  898. return (url + "&" + query).replace(/[&?]{1,2}/, '?');
  899. }
  900. /**
  901. * 合并请求参数,参数优先级:options > globalOptions > defaults
  902. * @param options
  903. */
  904. function mergeOptions(options) {
  905. // 默认参数
  906. var defaults = {
  907. url: '',
  908. method: 'GET',
  909. data: '',
  910. processData: true,
  911. async: true,
  912. cache: true,
  913. username: '',
  914. password: '',
  915. headers: {},
  916. xhrFields: {},
  917. statusCode: {},
  918. dataType: 'text',
  919. contentType: 'application/x-www-form-urlencoded',
  920. timeout: 0,
  921. global: true,
  922. };
  923. // globalOptions 中的回调函数不合并
  924. each(globalOptions, function (key, value) {
  925. var callbacks = [
  926. 'beforeSend',
  927. 'success',
  928. 'error',
  929. 'complete',
  930. 'statusCode' ];
  931. // @ts-ignore
  932. if (callbacks.indexOf(key) < 0 && !isUndefined(value)) {
  933. defaults[key] = value;
  934. }
  935. });
  936. return extend({}, defaults, options);
  937. }
  938. /**
  939. * 发送 ajax 请求
  940. * @param options
  941. * @example
  942. ```js
  943. ajax({
  944. method: "POST",
  945. url: "some.php",
  946. data: { name: "John", location: "Boston" }
  947. }).then(function( msg ) {
  948. alert( "Data Saved: " + msg );
  949. });
  950. ```
  951. */
  952. function ajax(options) {
  953. // 是否已取消请求
  954. var isCanceled = false;
  955. // 事件参数
  956. var eventParams = {};
  957. // 参数合并
  958. var mergedOptions = mergeOptions(options);
  959. var url = mergedOptions.url || window.location.toString();
  960. var method = mergedOptions.method.toUpperCase();
  961. var data = mergedOptions.data;
  962. var processData = mergedOptions.processData;
  963. var async = mergedOptions.async;
  964. var cache = mergedOptions.cache;
  965. var username = mergedOptions.username;
  966. var password = mergedOptions.password;
  967. var headers = mergedOptions.headers;
  968. var xhrFields = mergedOptions.xhrFields;
  969. var statusCode = mergedOptions.statusCode;
  970. var dataType = mergedOptions.dataType;
  971. var contentType = mergedOptions.contentType;
  972. var timeout = mergedOptions.timeout;
  973. var global = mergedOptions.global;
  974. // 需要发送的数据
  975. // GET/HEAD 请求和 processData 为 true 时,转换为查询字符串格式,特殊格式不转换
  976. if (data &&
  977. (isQueryStringData(method) || processData) &&
  978. !isString(data) &&
  979. !(data instanceof ArrayBuffer) &&
  980. !(data instanceof Blob) &&
  981. !(data instanceof Document) &&
  982. !(data instanceof FormData)) {
  983. data = param(data);
  984. }
  985. // 对于 GET、HEAD 类型的请求,把 data 数据添加到 URL 中
  986. if (data && isQueryStringData(method)) {
  987. // 查询字符串拼接到 URL 中
  988. url = appendQuery(url, data);
  989. data = null;
  990. }
  991. /**
  992. * 触发事件和回调函数
  993. * @param event
  994. * @param params
  995. * @param callback
  996. * @param args
  997. */
  998. function trigger(event, params, callback) {
  999. var args = [], len = arguments.length - 3;
  1000. while ( len-- > 0 ) args[ len ] = arguments[ len + 3 ];
  1001. // 触发全局事件
  1002. if (global) {
  1003. $(document).trigger(event, params);
  1004. }
  1005. // 触发 ajax 回调和事件
  1006. var result1;
  1007. var result2;
  1008. if (callback) {
  1009. // 全局回调
  1010. if (callback in globalOptions) {
  1011. // @ts-ignore
  1012. result1 = globalOptions[callback].apply(globalOptions, args);
  1013. }
  1014. // 自定义回调
  1015. if (mergedOptions[callback]) {
  1016. // @ts-ignore
  1017. result2 = mergedOptions[callback].apply(mergedOptions, args);
  1018. }
  1019. // beforeSend 回调返回 false 时取消 ajax 请求
  1020. if (callback === 'beforeSend' &&
  1021. (result1 === false || result2 === false)) {
  1022. isCanceled = true;
  1023. }
  1024. }
  1025. }
  1026. // XMLHttpRequest 请求
  1027. function XHR() {
  1028. var textStatus;
  1029. return new Promise(function (resolve, reject) {
  1030. // GET/HEAD 请求的缓存处理
  1031. if (isQueryStringData(method) && !cache) {
  1032. url = appendQuery(url, ("_=" + (Date.now())));
  1033. }
  1034. // 创建 XHR
  1035. var xhr = new XMLHttpRequest();
  1036. xhr.open(method, url, async, username, password);
  1037. if (contentType ||
  1038. (data && !isQueryStringData(method) && contentType !== false)) {
  1039. xhr.setRequestHeader('Content-Type', contentType);
  1040. }
  1041. // 设置 Accept
  1042. if (dataType === 'json') {
  1043. xhr.setRequestHeader('Accept', 'application/json, text/javascript');
  1044. }
  1045. // 添加 headers
  1046. if (headers) {
  1047. each(headers, function (key, value) {
  1048. // undefined 值不发送,string 和 null 需要发送
  1049. if (!isUndefined(value)) {
  1050. xhr.setRequestHeader(key, value + ''); // 把 null 转换成字符串
  1051. }
  1052. });
  1053. }
  1054. // 检查是否是跨域请求,跨域请求时不添加 X-Requested-With
  1055. var crossDomain = /^([\w-]+:)?\/\/([^/]+)/.test(url) &&
  1056. RegExp.$2 !== window.location.host;
  1057. if (!crossDomain) {
  1058. xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  1059. }
  1060. if (xhrFields) {
  1061. each(xhrFields, function (key, value) {
  1062. // @ts-ignore
  1063. xhr[key] = value;
  1064. });
  1065. }
  1066. eventParams.xhr = xhr;
  1067. eventParams.options = mergedOptions;
  1068. var xhrTimeout;
  1069. xhr.onload = function () {
  1070. if (xhrTimeout) {
  1071. clearTimeout(xhrTimeout);
  1072. }
  1073. // AJAX 返回的 HTTP 响应码是否表示成功
  1074. var isHttpStatusSuccess = (xhr.status >= 200 && xhr.status < 300) ||
  1075. xhr.status === 304 ||
  1076. xhr.status === 0;
  1077. var responseData;
  1078. if (isHttpStatusSuccess) {
  1079. if (xhr.status === 204 || method === 'HEAD') {
  1080. textStatus = 'nocontent';
  1081. }
  1082. else if (xhr.status === 304) {
  1083. textStatus = 'notmodified';
  1084. }
  1085. else {
  1086. textStatus = 'success';
  1087. }
  1088. if (dataType === 'json') {
  1089. try {
  1090. responseData =
  1091. method === 'HEAD' ? undefined : JSON.parse(xhr.responseText);
  1092. eventParams.data = responseData;
  1093. }
  1094. catch (err) {
  1095. textStatus = 'parsererror';
  1096. trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, textStatus);
  1097. reject(new Error(textStatus));
  1098. }
  1099. if (textStatus !== 'parsererror') {
  1100. trigger(ajaxEvents.ajaxSuccess, eventParams, 'success', responseData, textStatus, xhr);
  1101. resolve(responseData);
  1102. }
  1103. }
  1104. else {
  1105. responseData =
  1106. method === 'HEAD'
  1107. ? undefined
  1108. : xhr.responseType === 'text' || xhr.responseType === ''
  1109. ? xhr.responseText
  1110. : xhr.response;
  1111. eventParams.data = responseData;
  1112. trigger(ajaxEvents.ajaxSuccess, eventParams, 'success', responseData, textStatus, xhr);
  1113. resolve(responseData);
  1114. }
  1115. }
  1116. else {
  1117. textStatus = 'error';
  1118. trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, textStatus);
  1119. reject(new Error(textStatus));
  1120. }
  1121. // statusCode
  1122. each([globalOptions.statusCode, statusCode], function (_, func) {
  1123. if (func && func[xhr.status]) {
  1124. if (isHttpStatusSuccess) {
  1125. func[xhr.status](responseData, textStatus, xhr);
  1126. }
  1127. else {
  1128. func[xhr.status](xhr, textStatus);
  1129. }
  1130. }
  1131. });
  1132. trigger(ajaxEvents.ajaxComplete, eventParams, 'complete', xhr, textStatus);
  1133. };
  1134. xhr.onerror = function () {
  1135. if (xhrTimeout) {
  1136. clearTimeout(xhrTimeout);
  1137. }
  1138. trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, xhr.statusText);
  1139. trigger(ajaxEvents.ajaxComplete, eventParams, 'complete', xhr, 'error');
  1140. reject(new Error(xhr.statusText));
  1141. };
  1142. xhr.onabort = function () {
  1143. var statusText = 'abort';
  1144. if (xhrTimeout) {
  1145. statusText = 'timeout';
  1146. clearTimeout(xhrTimeout);
  1147. }
  1148. trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, statusText);
  1149. trigger(ajaxEvents.ajaxComplete, eventParams, 'complete', xhr, statusText);
  1150. reject(new Error(statusText));
  1151. };
  1152. // ajax start 回调
  1153. trigger(ajaxEvents.ajaxStart, eventParams, 'beforeSend', xhr);
  1154. if (isCanceled) {
  1155. reject(new Error('cancel'));
  1156. return;
  1157. }
  1158. // Timeout
  1159. if (timeout > 0) {
  1160. xhrTimeout = setTimeout(function () {
  1161. xhr.abort();
  1162. }, timeout);
  1163. }
  1164. // 发送 XHR
  1165. xhr.send(data);
  1166. });
  1167. }
  1168. return XHR();
  1169. }
  1170. $.ajax = ajax;
  1171. /**
  1172. * 为 Ajax 请求设置全局配置参数
  1173. * @param options 键值对参数
  1174. * @example
  1175. ```js
  1176. ajaxSetup({
  1177. dataType: 'json',
  1178. method: 'POST',
  1179. });
  1180. ```
  1181. */
  1182. function ajaxSetup(options) {
  1183. return extend(globalOptions, options);
  1184. }
  1185. $.ajaxSetup = ajaxSetup;
  1186. $.contains = contains;
  1187. var dataNS = '_mduiElementDataStorage';
  1188. /**
  1189. * 在元素上设置键值对数据
  1190. * @param element
  1191. * @param object
  1192. */
  1193. function setObjectToElement(element, object) {
  1194. // @ts-ignore
  1195. if (!element[dataNS]) {
  1196. // @ts-ignore
  1197. element[dataNS] = {};
  1198. }
  1199. each(object, function (key, value) {
  1200. // @ts-ignore
  1201. element[dataNS][toCamelCase(key)] = value;
  1202. });
  1203. }
  1204. function data(element, key, value) {
  1205. var obj;
  1206. // 根据键值对设置值
  1207. // data(element, { 'key' : 'value' })
  1208. if (isObjectLike(key)) {
  1209. setObjectToElement(element, key);
  1210. return key;
  1211. }
  1212. // 根据 key、value 设置值
  1213. // data(element, 'key', 'value')
  1214. if (!isUndefined(value)) {
  1215. setObjectToElement(element, ( obj = {}, obj[key] = value, obj ));
  1216. return value;
  1217. }
  1218. // 获取所有值
  1219. // data(element)
  1220. if (isUndefined(key)) {
  1221. // @ts-ignore
  1222. return element[dataNS] ? element[dataNS] : {};
  1223. }
  1224. // 从 dataNS 中获取指定值
  1225. // data(element, 'key')
  1226. key = toCamelCase(key);
  1227. // @ts-ignore
  1228. if (element[dataNS] && key in element[dataNS]) {
  1229. // @ts-ignore
  1230. return element[dataNS][key];
  1231. }
  1232. return undefined;
  1233. }
  1234. $.data = data;
  1235. $.each = each;
  1236. $.extend = function () {
  1237. var this$1 = this;
  1238. var objectN = [], len = arguments.length;
  1239. while ( len-- ) objectN[ len ] = arguments[ len ];
  1240. if (objectN.length === 1) {
  1241. each(objectN[0], function (prop, value) {
  1242. this$1[prop] = value;
  1243. });
  1244. return this;
  1245. }
  1246. return extend.apply(void 0, [ objectN.shift(), objectN.shift() ].concat( objectN ));
  1247. };
  1248. function map(elements, callback) {
  1249. var ref;
  1250. var value;
  1251. var ret = [];
  1252. each(elements, function (i, element) {
  1253. value = callback.call(window, element, i);
  1254. if (value != null) {
  1255. ret.push(value);
  1256. }
  1257. });
  1258. return (ref = []).concat.apply(ref, ret);
  1259. }
  1260. $.map = map;
  1261. $.merge = merge;
  1262. $.param = param;
  1263. /**
  1264. * 移除指定元素上存放的数据
  1265. * @param element 存放数据的元素
  1266. * @param name
  1267. * 数据键名
  1268. *
  1269. * 若未指定键名,将移除元素上所有数据
  1270. *
  1271. * 多个键名可以用空格分隔,或者用数组表示多个键名
  1272. @example
  1273. ```js
  1274. // 移除元素上键名为 name 的数据
  1275. removeData(document.body, 'name');
  1276. ```
  1277. * @example
  1278. ```js
  1279. // 移除元素上键名为 name1 和 name2 的数据
  1280. removeData(document.body, 'name1 name2');
  1281. ```
  1282. * @example
  1283. ```js
  1284. // 移除元素上键名为 name1 和 name2 的数据
  1285. removeData(document.body, ['name1', 'name2']);
  1286. ```
  1287. * @example
  1288. ```js
  1289. // 移除元素上所有数据
  1290. removeData(document.body);
  1291. ```
  1292. */
  1293. function removeData(element, name) {
  1294. // @ts-ignore
  1295. if (!element[dataNS]) {
  1296. return;
  1297. }
  1298. var remove = function (nameItem) {
  1299. nameItem = toCamelCase(nameItem);
  1300. // @ts-ignore
  1301. if (element[dataNS][nameItem]) {
  1302. // @ts-ignore
  1303. element[dataNS][nameItem] = null;
  1304. // @ts-ignore
  1305. delete element[dataNS][nameItem];
  1306. }
  1307. };
  1308. if (isUndefined(name)) {
  1309. // @ts-ignore
  1310. element[dataNS] = null;
  1311. // @ts-ignore
  1312. delete element[dataNS];
  1313. // @ts-ignore
  1314. }
  1315. else if (isString(name)) {
  1316. name
  1317. .split(' ')
  1318. .filter(function (nameItem) { return nameItem; })
  1319. .forEach(function (nameItem) { return remove(nameItem); });
  1320. }
  1321. else {
  1322. each(name, function (_, nameItem) { return remove(nameItem); });
  1323. }
  1324. }
  1325. $.removeData = removeData;
  1326. /**
  1327. * 过滤掉数组中的重复元素
  1328. * @param arr 数组
  1329. * @example
  1330. ```js
  1331. unique([1, 2, 12, 3, 2, 1, 2, 1, 1]);
  1332. // [1, 2, 12, 3]
  1333. ```
  1334. */
  1335. function unique(arr) {
  1336. var result = [];
  1337. each(arr, function (_, val) {
  1338. if (result.indexOf(val) === -1) {
  1339. result.push(val);
  1340. }
  1341. });
  1342. return result;
  1343. }
  1344. $.unique = unique;
  1345. $.fn.add = function (selector) {
  1346. return new JQ(unique(merge(this.get(), $(selector).get())));
  1347. };
  1348. each(['add', 'remove', 'toggle'], function (_, name) {
  1349. $.fn[(name + "Class")] = function (className) {
  1350. if (name === 'remove' && !arguments.length) {
  1351. return this.each(function (_, element) {
  1352. element.setAttribute('class', '');
  1353. });
  1354. }
  1355. return this.each(function (i, element) {
  1356. if (!isElement(element)) {
  1357. return;
  1358. }
  1359. var classes = (isFunction(className)
  1360. ? className.call(element, i, element.getAttribute('class') || '')
  1361. : className)
  1362. .split(' ')
  1363. .filter(function (name) { return name; });
  1364. each(classes, function (_, cls) {
  1365. element.classList[name](cls);
  1366. });
  1367. });
  1368. };
  1369. });
  1370. each(['insertBefore', 'insertAfter'], function (nameIndex, name) {
  1371. $.fn[name] = function (target) {
  1372. var $element = nameIndex ? $(this.get().reverse()) : this; // 顺序和 jQuery 保持一致
  1373. var $target = $(target);
  1374. var result = [];
  1375. $target.each(function (index, target) {
  1376. if (!target.parentNode) {
  1377. return;
  1378. }
  1379. $element.each(function (_, element) {
  1380. var newItem = index
  1381. ? element.cloneNode(true)
  1382. : element;
  1383. var existingItem = nameIndex ? target.nextSibling : target;
  1384. result.push(newItem);
  1385. target.parentNode.insertBefore(newItem, existingItem);
  1386. });
  1387. });
  1388. return $(nameIndex ? result.reverse() : result);
  1389. };
  1390. });
  1391. /**
  1392. * 是否不是 HTML 字符串(包裹在 <> 中)
  1393. * @param target
  1394. */
  1395. function isPlainText(target) {
  1396. return (isString(target) && (target[0] !== '<' || target[target.length - 1] !== '>'));
  1397. }
  1398. each(['before', 'after'], function (nameIndex, name) {
  1399. $.fn[name] = function () {
  1400. var args = [], len = arguments.length;
  1401. while ( len-- ) args[ len ] = arguments[ len ];
  1402. // after 方法,多个参数需要按参数顺序添加到元素后面,所以需要将参数顺序反向处理
  1403. if (nameIndex === 1) {
  1404. args = args.reverse();
  1405. }
  1406. return this.each(function (index, element) {
  1407. var targets = isFunction(args[0])
  1408. ? [args[0].call(element, index, element.innerHTML)]
  1409. : args;
  1410. each(targets, function (_, target) {
  1411. var $target;
  1412. if (isPlainText(target)) {
  1413. $target = $(getChildNodesArray(target, 'div'));
  1414. }
  1415. else if (index && isElement(target)) {
  1416. $target = $(target.cloneNode(true));
  1417. }
  1418. else {
  1419. $target = $(target);
  1420. }
  1421. $target[nameIndex ? 'insertAfter' : 'insertBefore'](element);
  1422. });
  1423. });
  1424. };
  1425. });
  1426. $.fn.off = function (types, selector, callback) {
  1427. var this$1 = this;
  1428. // types 是对象
  1429. if (isObjectLike(types)) {
  1430. each(types, function (type, fn) {
  1431. // this.off('click', undefined, function () {})
  1432. // this.off('click', '.box', function () {})
  1433. this$1.off(type, selector, fn);
  1434. });
  1435. return this;
  1436. }
  1437. // selector 不存在
  1438. if (selector === false || isFunction(selector)) {
  1439. callback = selector;
  1440. selector = undefined;
  1441. // this.off('click', undefined, function () {})
  1442. }
  1443. // callback 传入 `false`,相当于 `return false`
  1444. if (callback === false) {
  1445. callback = returnFalse;
  1446. }
  1447. return this.each(function () {
  1448. remove(this, types, callback, selector);
  1449. });
  1450. };
  1451. $.fn.on = function (types, selector, data, callback, one) {
  1452. var this$1 = this;
  1453. // types 可以是 type/func 对象
  1454. if (isObjectLike(types)) {
  1455. // (types-Object, selector, data)
  1456. if (!isString(selector)) {
  1457. // (types-Object, data)
  1458. data = data || selector;
  1459. selector = undefined;
  1460. }
  1461. each(types, function (type, fn) {
  1462. // selector 和 data 都可能是 undefined
  1463. // @ts-ignore
  1464. this$1.on(type, selector, data, fn, one);
  1465. });
  1466. return this;
  1467. }
  1468. if (data == null && callback == null) {
  1469. // (types, fn)
  1470. callback = selector;
  1471. data = selector = undefined;
  1472. }
  1473. else if (callback == null) {
  1474. if (isString(selector)) {
  1475. // (types, selector, fn)
  1476. callback = data;
  1477. data = undefined;
  1478. }
  1479. else {
  1480. // (types, data, fn)
  1481. callback = data;
  1482. data = selector;
  1483. selector = undefined;
  1484. }
  1485. }
  1486. if (callback === false) {
  1487. callback = returnFalse;
  1488. }
  1489. else if (!callback) {
  1490. return this;
  1491. }
  1492. // $().one()
  1493. if (one) {
  1494. // eslint-disable-next-line @typescript-eslint/no-this-alias
  1495. var _this = this;
  1496. var origCallback = callback;
  1497. callback = function (event) {
  1498. _this.off(event.type, selector, callback);
  1499. // eslint-disable-next-line prefer-rest-params
  1500. return origCallback.apply(this, arguments);
  1501. };
  1502. }
  1503. return this.each(function () {
  1504. add(this, types, callback, data, selector);
  1505. });
  1506. };
  1507. each(ajaxEvents, function (name, eventName) {
  1508. $.fn[name] = function (fn) {
  1509. return this.on(eventName, function (e, params) {
  1510. fn(e, params.xhr, params.options, params.data);
  1511. });
  1512. };
  1513. });
  1514. $.fn.map = function (callback) {
  1515. return new JQ(map(this, function (element, i) { return callback.call(element, i, element); }));
  1516. };
  1517. $.fn.clone = function () {
  1518. return this.map(function () {
  1519. return this.cloneNode(true);
  1520. });
  1521. };
  1522. $.fn.is = function (selector) {
  1523. var isMatched = false;
  1524. if (isFunction(selector)) {
  1525. this.each(function (index, element) {
  1526. if (selector.call(element, index, element)) {
  1527. isMatched = true;
  1528. }
  1529. });
  1530. return isMatched;
  1531. }
  1532. if (isString(selector)) {
  1533. this.each(function (_, element) {
  1534. if (isDocument(element) || isWindow(element)) {
  1535. return;
  1536. }
  1537. // @ts-ignore
  1538. var matches = element.matches || element.msMatchesSelector;
  1539. if (matches.call(element, selector)) {
  1540. isMatched = true;
  1541. }
  1542. });
  1543. return isMatched;
  1544. }
  1545. var $compareWith = $(selector);
  1546. this.each(function (_, element) {
  1547. $compareWith.each(function (_, compare) {
  1548. if (element === compare) {
  1549. isMatched = true;
  1550. }
  1551. });
  1552. });
  1553. return isMatched;
  1554. };
  1555. $.fn.remove = function (selector) {
  1556. return this.each(function (_, element) {
  1557. if (element.parentNode && (!selector || $(element).is(selector))) {
  1558. element.parentNode.removeChild(element);
  1559. }
  1560. });
  1561. };
  1562. each(['prepend', 'append'], function (nameIndex, name) {
  1563. $.fn[name] = function () {
  1564. var args = [], len = arguments.length;
  1565. while ( len-- ) args[ len ] = arguments[ len ];
  1566. return this.each(function (index, element) {
  1567. var ref;
  1568. var childNodes = element.childNodes;
  1569. var childLength = childNodes.length;
  1570. var child = childLength
  1571. ? childNodes[nameIndex ? childLength - 1 : 0]
  1572. : document.createElement('div');
  1573. if (!childLength) {
  1574. element.appendChild(child);
  1575. }
  1576. var contents = isFunction(args[0])
  1577. ? [args[0].call(element, index, element.innerHTML)]
  1578. : args;
  1579. // 如果不是字符串,则仅第一个元素使用原始元素,其他的都克隆自第一个元素
  1580. if (index) {
  1581. contents = contents.map(function (content) {
  1582. return isString(content) ? content : $(content).clone();
  1583. });
  1584. }
  1585. (ref = $(child))[nameIndex ? 'after' : 'before'].apply(ref, contents);
  1586. if (!childLength) {
  1587. element.removeChild(child);
  1588. }
  1589. });
  1590. };
  1591. });
  1592. each(['appendTo', 'prependTo'], function (nameIndex, name) {
  1593. $.fn[name] = function (target) {
  1594. var extraChilds = [];
  1595. var $target = $(target).map(function (_, element) {
  1596. var childNodes = element.childNodes;
  1597. var childLength = childNodes.length;
  1598. if (childLength) {
  1599. return childNodes[nameIndex ? 0 : childLength - 1];
  1600. }
  1601. var child = document.createElement('div');
  1602. element.appendChild(child);
  1603. extraChilds.push(child);
  1604. return child;
  1605. });
  1606. var $result = this[nameIndex ? 'insertBefore' : 'insertAfter']($target);
  1607. $(extraChilds).remove();
  1608. return $result;
  1609. };
  1610. });
  1611. each(['attr', 'prop', 'css'], function (nameIndex, name) {
  1612. function set(element, key, value) {
  1613. // 值为 undefined 时,不修改
  1614. if (isUndefined(value)) {
  1615. return;
  1616. }
  1617. switch (nameIndex) {
  1618. // attr
  1619. case 0:
  1620. if (isNull(value)) {
  1621. element.removeAttribute(key);
  1622. }
  1623. else {
  1624. element.setAttribute(key, value);
  1625. }
  1626. break;
  1627. // prop
  1628. case 1:
  1629. // @ts-ignore
  1630. element[key] = value;
  1631. break;
  1632. // css
  1633. default:
  1634. key = toCamelCase(key);
  1635. // @ts-ignore
  1636. element.style[key] = isNumber(value)
  1637. ? ("" + value + (cssNumber.indexOf(key) > -1 ? '' : 'px'))
  1638. : value;
  1639. break;
  1640. }
  1641. }
  1642. function get(element, key) {
  1643. switch (nameIndex) {
  1644. // attr
  1645. case 0:
  1646. // 属性不存在时,原生 getAttribute 方法返回 null,而 jquery 返回 undefined。这里和 jquery 保持一致
  1647. var value = element.getAttribute(key);
  1648. return isNull(value) ? undefined : value;
  1649. // prop
  1650. case 1:
  1651. // @ts-ignore
  1652. return element[key];
  1653. // css
  1654. default:
  1655. return getStyle(element, key);
  1656. }
  1657. }
  1658. $.fn[name] = function (key, value) {
  1659. var this$1 = this;
  1660. if (isObjectLike(key)) {
  1661. each(key, function (k, v) {
  1662. // @ts-ignore
  1663. this$1[name](k, v);
  1664. });
  1665. return this;
  1666. }
  1667. if (arguments.length === 1) {
  1668. var element = this[0];
  1669. return isElement(element) ? get(element, key) : undefined;
  1670. }
  1671. return this.each(function (i, element) {
  1672. set(element, key, isFunction(value) ? value.call(element, i, get(element, key)) : value);
  1673. });
  1674. };
  1675. });
  1676. $.fn.children = function (selector) {
  1677. var children = [];
  1678. this.each(function (_, element) {
  1679. each(element.childNodes, function (__, childNode) {
  1680. if (!isElement(childNode)) {
  1681. return;
  1682. }
  1683. if (!selector || $(childNode).is(selector)) {
  1684. children.push(childNode);
  1685. }
  1686. });
  1687. });
  1688. return new JQ(unique(children));
  1689. };
  1690. $.fn.slice = function () {
  1691. var args = [], len = arguments.length;
  1692. while ( len-- ) args[ len ] = arguments[ len ];
  1693. return new JQ([].slice.apply(this, args));
  1694. };
  1695. $.fn.eq = function (index) {
  1696. var ret = index === -1 ? this.slice(index) : this.slice(index, +index + 1);
  1697. return new JQ(ret);
  1698. };
  1699. function dir($elements, nameIndex, node, selector, filter) {
  1700. var ret = [];
  1701. var target;
  1702. $elements.each(function (_, element) {
  1703. target = element[node];
  1704. // 不能包含最顶层的 document 元素
  1705. while (target && isElement(target)) {
  1706. // prevUntil, nextUntil, parentsUntil
  1707. if (nameIndex === 2) {
  1708. if (selector && $(target).is(selector)) {
  1709. break;
  1710. }
  1711. if (!filter || $(target).is(filter)) {
  1712. ret.push(target);
  1713. }
  1714. }
  1715. // prev, next, parent
  1716. else if (nameIndex === 0) {
  1717. if (!selector || $(target).is(selector)) {
  1718. ret.push(target);
  1719. }
  1720. break;
  1721. }
  1722. // prevAll, nextAll, parents
  1723. else {
  1724. if (!selector || $(target).is(selector)) {
  1725. ret.push(target);
  1726. }
  1727. }
  1728. // @ts-ignore
  1729. target = target[node];
  1730. }
  1731. });
  1732. return new JQ(unique(ret));
  1733. }
  1734. each(['', 's', 'sUntil'], function (nameIndex, name) {
  1735. $.fn[("parent" + name)] = function (selector, filter) {
  1736. // parents、parentsUntil 需要把元素的顺序反向处理,以便和 jQuery 的结果一致
  1737. var $nodes = !nameIndex ? this : $(this.get().reverse());
  1738. return dir($nodes, nameIndex, 'parentNode', selector, filter);
  1739. };
  1740. });
  1741. $.fn.closest = function (selector) {
  1742. if (this.is(selector)) {
  1743. return this;
  1744. }
  1745. var matched = [];
  1746. this.parents().each(function (_, element) {
  1747. if ($(element).is(selector)) {
  1748. matched.push(element);
  1749. return false;
  1750. }
  1751. });
  1752. return new JQ(matched);
  1753. };
  1754. var rbrace = /^(?:{[\w\W]*\}|\[[\w\W]*\])$/;
  1755. // 从 `data-*` 中获取的值,需要经过该函数转换
  1756. function getData(value) {
  1757. if (value === 'true') {
  1758. return true;
  1759. }
  1760. if (value === 'false') {
  1761. return false;
  1762. }
  1763. if (value === 'null') {
  1764. return null;
  1765. }
  1766. if (value === +value + '') {
  1767. return +value;
  1768. }
  1769. if (rbrace.test(value)) {
  1770. return JSON.parse(value);
  1771. }
  1772. return value;
  1773. }
  1774. // 若 value 不存在,则从 `data-*` 中获取值
  1775. function dataAttr(element, key, value) {
  1776. if (isUndefined(value) && element.nodeType === 1) {
  1777. var name = 'data-' + toKebabCase(key);
  1778. value = element.getAttribute(name);
  1779. if (isString(value)) {
  1780. try {
  1781. value = getData(value);
  1782. }
  1783. catch (e) { }
  1784. }
  1785. else {
  1786. value = undefined;
  1787. }
  1788. }
  1789. return value;
  1790. }
  1791. $.fn.data = function (key, value) {
  1792. // 获取所有值
  1793. if (isUndefined(key)) {
  1794. if (!this.length) {
  1795. return undefined;
  1796. }
  1797. var element = this[0];
  1798. var resultData = data(element);
  1799. // window, document 上不存在 `data-*` 属性
  1800. if (element.nodeType !== 1) {
  1801. return resultData;
  1802. }
  1803. // 从 `data-*` 中获取值
  1804. var attrs = element.attributes;
  1805. var i = attrs.length;
  1806. while (i--) {
  1807. if (attrs[i]) {
  1808. var name = attrs[i].name;
  1809. if (name.indexOf('data-') === 0) {
  1810. name = toCamelCase(name.slice(5));
  1811. resultData[name] = dataAttr(element, name, resultData[name]);
  1812. }
  1813. }
  1814. }
  1815. return resultData;
  1816. }
  1817. // 同时设置多个值
  1818. if (isObjectLike(key)) {
  1819. return this.each(function () {
  1820. data(this, key);
  1821. });
  1822. }
  1823. // value 传入了 undefined
  1824. if (arguments.length === 2 && isUndefined(value)) {
  1825. return this;
  1826. }
  1827. // 设置值
  1828. if (!isUndefined(value)) {
  1829. return this.each(function () {
  1830. data(this, key, value);
  1831. });
  1832. }
  1833. // 获取值
  1834. if (!this.length) {
  1835. return undefined;
  1836. }
  1837. return dataAttr(this[0], key, data(this[0], key));
  1838. };
  1839. $.fn.empty = function () {
  1840. return this.each(function () {
  1841. this.innerHTML = '';
  1842. });
  1843. };
  1844. $.fn.extend = function (obj) {
  1845. each(obj, function (prop, value) {
  1846. // 在 JQ 对象上扩展方法时,需要自己添加 typescript 的类型定义
  1847. $.fn[prop] = value;
  1848. });
  1849. return this;
  1850. };
  1851. $.fn.filter = function (selector) {
  1852. if (isFunction(selector)) {
  1853. return this.map(function (index, element) { return selector.call(element, index, element) ? element : undefined; });
  1854. }
  1855. if (isString(selector)) {
  1856. return this.map(function (_, element) { return $(element).is(selector) ? element : undefined; });
  1857. }
  1858. var $selector = $(selector);
  1859. return this.map(function (_, element) { return $selector.get().indexOf(element) > -1 ? element : undefined; });
  1860. };
  1861. $.fn.first = function () {
  1862. return this.eq(0);
  1863. };
  1864. $.fn.has = function (selector) {
  1865. var $targets = isString(selector) ? this.find(selector) : $(selector);
  1866. var length = $targets.length;
  1867. return this.map(function () {
  1868. for (var i = 0; i < length; i += 1) {
  1869. if (contains(this, $targets[i])) {
  1870. return this;
  1871. }
  1872. }
  1873. return;
  1874. });
  1875. };
  1876. $.fn.hasClass = function (className) {
  1877. return this[0].classList.contains(className);
  1878. };
  1879. /**
  1880. * 值上面的 padding、border、margin 处理
  1881. * @param element
  1882. * @param name
  1883. * @param value
  1884. * @param funcIndex
  1885. * @param includeMargin
  1886. * @param multiply
  1887. */
  1888. function handleExtraWidth(element, name, value, funcIndex, includeMargin, multiply) {
  1889. // 获取元素的 padding, border, margin 宽度(两侧宽度的和)
  1890. var getExtraWidthValue = function (extra) {
  1891. return (getExtraWidth(element, name.toLowerCase(), extra) *
  1892. multiply);
  1893. };
  1894. if (funcIndex === 2 && includeMargin) {
  1895. value += getExtraWidthValue('margin');
  1896. }
  1897. if (isBorderBox(element)) {
  1898. // IE 为 box-sizing: border-box 时,得到的值不含 border 和 padding,这里先修复
  1899. // 仅获取时需要处理,multiply === 1 为 get
  1900. if (isIE() && multiply === 1) {
  1901. value += getExtraWidthValue('border');
  1902. value += getExtraWidthValue('padding');
  1903. }
  1904. if (funcIndex === 0) {
  1905. value -= getExtraWidthValue('border');
  1906. }
  1907. if (funcIndex === 1) {
  1908. value -= getExtraWidthValue('border');
  1909. value -= getExtraWidthValue('padding');
  1910. }
  1911. }
  1912. else {
  1913. if (funcIndex === 0) {
  1914. value += getExtraWidthValue('padding');
  1915. }
  1916. if (funcIndex === 2) {
  1917. value += getExtraWidthValue('border');
  1918. value += getExtraWidthValue('padding');
  1919. }
  1920. }
  1921. return value;
  1922. }
  1923. /**
  1924. * 获取元素的样式值
  1925. * @param element
  1926. * @param name
  1927. * @param funcIndex 0: innerWidth, innerHeight; 1: width, height; 2: outerWidth, outerHeight
  1928. * @param includeMargin
  1929. */
  1930. function get(element, name, funcIndex, includeMargin) {
  1931. var clientProp = "client" + name;
  1932. var scrollProp = "scroll" + name;
  1933. var offsetProp = "offset" + name;
  1934. var innerProp = "inner" + name;
  1935. // $(window).width()
  1936. if (isWindow(element)) {
  1937. // outerWidth, outerHeight 需要包含滚动条的宽度
  1938. return funcIndex === 2
  1939. ? element[innerProp]
  1940. : toElement(document)[clientProp];
  1941. }
  1942. // $(document).width()
  1943. if (isDocument(element)) {
  1944. var doc = toElement(element);
  1945. return Math.max(
  1946. // @ts-ignore
  1947. element.body[scrollProp], doc[scrollProp],
  1948. // @ts-ignore
  1949. element.body[offsetProp], doc[offsetProp], doc[clientProp]);
  1950. }
  1951. var value = parseFloat(getComputedStyleValue(element, name.toLowerCase()) || '0');
  1952. return handleExtraWidth(element, name, value, funcIndex, includeMargin, 1);
  1953. }
  1954. /**
  1955. * 设置元素的样式值
  1956. * @param element
  1957. * @param elementIndex
  1958. * @param name
  1959. * @param funcIndex 0: innerWidth, innerHeight; 1: width, height; 2: outerWidth, outerHeight
  1960. * @param includeMargin
  1961. * @param value
  1962. */
  1963. function set(element, elementIndex, name, funcIndex, includeMargin, value) {
  1964. var computedValue = isFunction(value)
  1965. ? value.call(element, elementIndex, get(element, name, funcIndex, includeMargin))
  1966. : value;
  1967. if (computedValue == null) {
  1968. return;
  1969. }
  1970. var $element = $(element);
  1971. var dimension = name.toLowerCase();
  1972. // 特殊的值,不需要计算 padding、border、margin
  1973. if (['auto', 'inherit', ''].indexOf(computedValue) > -1) {
  1974. $element.css(dimension, computedValue);
  1975. return;
  1976. }
  1977. // 其他值保留原始单位。注意:如果不使用 px 作为单位,则算出的值一般是不准确的
  1978. var suffix = computedValue.toString().replace(/\b[0-9.]*/, '');
  1979. var numerical = parseFloat(computedValue);
  1980. computedValue =
  1981. handleExtraWidth(element, name, numerical, funcIndex, includeMargin, -1) +
  1982. (suffix || 'px');
  1983. $element.css(dimension, computedValue);
  1984. }
  1985. each(['Width', 'Height'], function (_, name) {
  1986. each([("inner" + name), name.toLowerCase(), ("outer" + name)], function (funcIndex, funcName) {
  1987. $.fn[funcName] = function (margin, value) {
  1988. // 是否是赋值操作
  1989. var isSet = arguments.length && (funcIndex < 2 || !isBoolean(margin));
  1990. var includeMargin = margin === true || value === true;
  1991. // 获取第一个元素的值
  1992. if (!isSet) {
  1993. return this.length
  1994. ? get(this[0], name, funcIndex, includeMargin)
  1995. : undefined;
  1996. }
  1997. // 设置每个元素的值
  1998. return this.each(function (index, element) { return set(element, index, name, funcIndex, includeMargin, margin); });
  1999. };
  2000. });
  2001. });
  2002. $.fn.hide = function () {
  2003. return this.each(function () {
  2004. this.style.display = 'none';
  2005. });
  2006. };
  2007. each(['val', 'html', 'text'], function (nameIndex, name) {
  2008. var props = {
  2009. 0: 'value',
  2010. 1: 'innerHTML',
  2011. 2: 'textContent',
  2012. };
  2013. var propName = props[nameIndex];
  2014. function get($elements) {
  2015. // text() 获取所有元素的文本
  2016. if (nameIndex === 2) {
  2017. // @ts-ignore
  2018. return map($elements, function (element) { return toElement(element)[propName]; }).join('');
  2019. }
  2020. // 空集合时,val() 和 html() 返回 undefined
  2021. if (!$elements.length) {
  2022. return undefined;
  2023. }
  2024. // val() 和 html() 仅获取第一个元素的内容
  2025. var firstElement = $elements[0];
  2026. // select multiple 返回数组
  2027. if (nameIndex === 0 && $(firstElement).is('select[multiple]')) {
  2028. return map($(firstElement).find('option:checked'), function (element) { return element.value; });
  2029. }
  2030. // @ts-ignore
  2031. return firstElement[propName];
  2032. }
  2033. function set(element, value) {
  2034. // text() 和 html() 赋值为 undefined,则保持原内容不变
  2035. // val() 赋值为 undefined 则赋值为空
  2036. if (isUndefined(value)) {
  2037. if (nameIndex !== 0) {
  2038. return;
  2039. }
  2040. value = '';
  2041. }
  2042. if (nameIndex === 1 && isElement(value)) {
  2043. value = value.outerHTML;
  2044. }
  2045. // @ts-ignore
  2046. element[propName] = value;
  2047. }
  2048. $.fn[name] = function (value) {
  2049. // 获取值
  2050. if (!arguments.length) {
  2051. return get(this);
  2052. }
  2053. // 设置值
  2054. return this.each(function (i, element) {
  2055. var computedValue = isFunction(value)
  2056. ? value.call(element, i, get($(element)))
  2057. : value;
  2058. // value 是数组,则选中数组中的元素,反选不在数组中的元素
  2059. if (nameIndex === 0 && Array.isArray(computedValue)) {
  2060. // select[multiple]
  2061. if ($(element).is('select[multiple]')) {
  2062. map($(element).find('option'), function (option) { return (option.selected =
  2063. computedValue.indexOf(option.value) >
  2064. -1); });
  2065. }
  2066. // 其他 checkbox, radio 等元素
  2067. else {
  2068. element.checked =
  2069. computedValue.indexOf(element.value) > -1;
  2070. }
  2071. }
  2072. else {
  2073. set(element, computedValue);
  2074. }
  2075. });
  2076. };
  2077. });
  2078. $.fn.index = function (selector) {
  2079. if (!arguments.length) {
  2080. return this.eq(0).parent().children().get().indexOf(this[0]);
  2081. }
  2082. if (isString(selector)) {
  2083. return $(selector).get().indexOf(this[0]);
  2084. }
  2085. return this.get().indexOf($(selector)[0]);
  2086. };
  2087. $.fn.last = function () {
  2088. return this.eq(-1);
  2089. };
  2090. each(['', 'All', 'Until'], function (nameIndex, name) {
  2091. $.fn[("next" + name)] = function (selector, filter) {
  2092. return dir(this, nameIndex, 'nextElementSibling', selector, filter);
  2093. };
  2094. });
  2095. $.fn.not = function (selector) {
  2096. var $excludes = this.filter(selector);
  2097. return this.map(function (_, element) { return $excludes.index(element) > -1 ? undefined : element; });
  2098. };
  2099. /**
  2100. * 返回最近的用于定位的父元素
  2101. */
  2102. $.fn.offsetParent = function () {
  2103. return this.map(function () {
  2104. var offsetParent = this.offsetParent;
  2105. while (offsetParent && $(offsetParent).css('position') === 'static') {
  2106. offsetParent = offsetParent.offsetParent;
  2107. }
  2108. return offsetParent || document.documentElement;
  2109. });
  2110. };
  2111. function floatStyle($element, name) {
  2112. return parseFloat($element.css(name));
  2113. }
  2114. $.fn.position = function () {
  2115. if (!this.length) {
  2116. return undefined;
  2117. }
  2118. var $element = this.eq(0);
  2119. var currentOffset;
  2120. var parentOffset = {
  2121. left: 0,
  2122. top: 0,
  2123. };
  2124. if ($element.css('position') === 'fixed') {
  2125. currentOffset = $element[0].getBoundingClientRect();
  2126. }
  2127. else {
  2128. currentOffset = $element.offset();
  2129. var $offsetParent = $element.offsetParent();
  2130. parentOffset = $offsetParent.offset();
  2131. parentOffset.top += floatStyle($offsetParent, 'border-top-width');
  2132. parentOffset.left += floatStyle($offsetParent, 'border-left-width');
  2133. }
  2134. return {
  2135. top: currentOffset.top - parentOffset.top - floatStyle($element, 'margin-top'),
  2136. left: currentOffset.left -
  2137. parentOffset.left -
  2138. floatStyle($element, 'margin-left'),
  2139. };
  2140. };
  2141. function get$1(element) {
  2142. if (!element.getClientRects().length) {
  2143. return { top: 0, left: 0 };
  2144. }
  2145. var rect = element.getBoundingClientRect();
  2146. var win = element.ownerDocument.defaultView;
  2147. return {
  2148. top: rect.top + win.pageYOffset,
  2149. left: rect.left + win.pageXOffset,
  2150. };
  2151. }
  2152. function set$1(element, value, index) {
  2153. var $element = $(element);
  2154. var position = $element.css('position');
  2155. if (position === 'static') {
  2156. $element.css('position', 'relative');
  2157. }
  2158. var currentOffset = get$1(element);
  2159. var currentTopString = $element.css('top');
  2160. var currentLeftString = $element.css('left');
  2161. var currentTop;
  2162. var currentLeft;
  2163. var calculatePosition = (position === 'absolute' || position === 'fixed') &&
  2164. (currentTopString + currentLeftString).indexOf('auto') > -1;
  2165. if (calculatePosition) {
  2166. var currentPosition = $element.position();
  2167. currentTop = currentPosition.top;
  2168. currentLeft = currentPosition.left;
  2169. }
  2170. else {
  2171. currentTop = parseFloat(currentTopString);
  2172. currentLeft = parseFloat(currentLeftString);
  2173. }
  2174. var computedValue = isFunction(value)
  2175. ? value.call(element, index, extend({}, currentOffset))
  2176. : value;
  2177. $element.css({
  2178. top: computedValue.top != null
  2179. ? computedValue.top - currentOffset.top + currentTop
  2180. : undefined,
  2181. left: computedValue.left != null
  2182. ? computedValue.left - currentOffset.left + currentLeft
  2183. : undefined,
  2184. });
  2185. }
  2186. $.fn.offset = function (value) {
  2187. // 获取坐标
  2188. if (!arguments.length) {
  2189. if (!this.length) {
  2190. return undefined;
  2191. }
  2192. return get$1(this[0]);
  2193. }
  2194. // 设置坐标
  2195. return this.each(function (index) {
  2196. set$1(this, value, index);
  2197. });
  2198. };
  2199. $.fn.one = function (types, selector, data, callback) {
  2200. // @ts-ignore
  2201. return this.on(types, selector, data, callback, true);
  2202. };
  2203. each(['', 'All', 'Until'], function (nameIndex, name) {
  2204. $.fn[("prev" + name)] = function (selector, filter) {
  2205. // prevAll、prevUntil 需要把元素的顺序倒序处理,以便和 jQuery 的结果一致
  2206. var $nodes = !nameIndex ? this : $(this.get().reverse());
  2207. return dir($nodes, nameIndex, 'previousElementSibling', selector, filter);
  2208. };
  2209. });
  2210. $.fn.removeAttr = function (attributeName) {
  2211. var names = attributeName.split(' ').filter(function (name) { return name; });
  2212. return this.each(function () {
  2213. var this$1 = this;
  2214. each(names, function (_, name) {
  2215. this$1.removeAttribute(name);
  2216. });
  2217. });
  2218. };
  2219. $.fn.removeData = function (name) {
  2220. return this.each(function () {
  2221. removeData(this, name);
  2222. });
  2223. };
  2224. $.fn.removeProp = function (name) {
  2225. return this.each(function () {
  2226. try {
  2227. // @ts-ignore
  2228. delete this[name];
  2229. }
  2230. catch (e) { }
  2231. });
  2232. };
  2233. $.fn.replaceWith = function (newContent) {
  2234. this.each(function (index, element) {
  2235. var content = newContent;
  2236. if (isFunction(content)) {
  2237. content = content.call(element, index, element.innerHTML);
  2238. }
  2239. else if (index && !isString(content)) {
  2240. content = $(content).clone();
  2241. }
  2242. $(element).before(content);
  2243. });
  2244. return this.remove();
  2245. };
  2246. $.fn.replaceAll = function (target) {
  2247. var this$1 = this;
  2248. return $(target).map(function (index, element) {
  2249. $(element).replaceWith(index ? this$1.clone() : this$1);
  2250. return this$1.get();
  2251. });
  2252. };
  2253. /**
  2254. * 将表单元素的值组合成键值对数组
  2255. * @returns {Array}
  2256. */
  2257. $.fn.serializeArray = function () {
  2258. var result = [];
  2259. this.each(function (_, element) {
  2260. var elements = element instanceof HTMLFormElement ? element.elements : [element];
  2261. $(elements).each(function (_, element) {
  2262. var $element = $(element);
  2263. var type = element.type;
  2264. var nodeName = element.nodeName.toLowerCase();
  2265. if (nodeName !== 'fieldset' &&
  2266. element.name &&
  2267. !element.disabled &&
  2268. ['input', 'select', 'textarea', 'keygen'].indexOf(nodeName) > -1 &&
  2269. ['submit', 'button', 'image', 'reset', 'file'].indexOf(type) === -1 &&
  2270. (['radio', 'checkbox'].indexOf(type) === -1 ||
  2271. element.checked)) {
  2272. var value = $element.val();
  2273. var valueArr = Array.isArray(value) ? value : [value];
  2274. valueArr.forEach(function (value) {
  2275. result.push({
  2276. name: element.name,
  2277. value: value,
  2278. });
  2279. });
  2280. }
  2281. });
  2282. });
  2283. return result;
  2284. };
  2285. $.fn.serialize = function () {
  2286. return param(this.serializeArray());
  2287. };
  2288. var elementDisplay = {};
  2289. /**
  2290. * 获取元素的初始 display 值,用于 .show() 方法
  2291. * @param nodeName
  2292. */
  2293. function defaultDisplay(nodeName) {
  2294. var element;
  2295. var display;
  2296. if (!elementDisplay[nodeName]) {
  2297. element = document.createElement(nodeName);
  2298. document.body.appendChild(element);
  2299. display = getStyle(element, 'display');
  2300. element.parentNode.removeChild(element);
  2301. if (display === 'none') {
  2302. display = 'block';
  2303. }
  2304. elementDisplay[nodeName] = display;
  2305. }
  2306. return elementDisplay[nodeName];
  2307. }
  2308. /**
  2309. * 显示指定元素
  2310. * @returns {JQ}
  2311. */
  2312. $.fn.show = function () {
  2313. return this.each(function () {
  2314. if (this.style.display === 'none') {
  2315. this.style.display = '';
  2316. }
  2317. if (getStyle(this, 'display') === 'none') {
  2318. this.style.display = defaultDisplay(this.nodeName);
  2319. }
  2320. });
  2321. };
  2322. /**
  2323. * 取得同辈元素的集合
  2324. * @param selector {String=}
  2325. * @returns {JQ}
  2326. */
  2327. $.fn.siblings = function (selector) {
  2328. return this.prevAll(selector).add(this.nextAll(selector));
  2329. };
  2330. /**
  2331. * 切换元素的显示状态
  2332. */
  2333. $.fn.toggle = function () {
  2334. return this.each(function () {
  2335. getStyle(this, 'display') === 'none' ? $(this).show() : $(this).hide();
  2336. });
  2337. };
  2338. $.fn.reflow = function () {
  2339. return this.each(function () {
  2340. return this.clientLeft;
  2341. });
  2342. };
  2343. $.fn.transition = function (duration) {
  2344. if (isNumber(duration)) {
  2345. duration = duration + "ms";
  2346. }
  2347. return this.each(function () {
  2348. this.style.webkitTransitionDuration = duration;
  2349. this.style.transitionDuration = duration;
  2350. });
  2351. };
  2352. $.fn.transitionEnd = function (callback) {
  2353. // eslint-disable-next-line @typescript-eslint/no-this-alias
  2354. var that = this;
  2355. var events = ['webkitTransitionEnd', 'transitionend'];
  2356. function fireCallback(e) {
  2357. if (e.target !== this) {
  2358. return;
  2359. }
  2360. // @ts-ignore
  2361. callback.call(this, e);
  2362. each(events, function (_, event) {
  2363. that.off(event, fireCallback);
  2364. });
  2365. }
  2366. each(events, function (_, event) {
  2367. that.on(event, fireCallback);
  2368. });
  2369. return this;
  2370. };
  2371. $.fn.transformOrigin = function (transformOrigin) {
  2372. return this.each(function () {
  2373. this.style.webkitTransformOrigin = transformOrigin;
  2374. this.style.transformOrigin = transformOrigin;
  2375. });
  2376. };
  2377. $.fn.transform = function (transform) {
  2378. return this.each(function () {
  2379. this.style.webkitTransform = transform;
  2380. this.style.transform = transform;
  2381. });
  2382. };
  2383. /**
  2384. * CSS 选择器和初始化函数组成的对象
  2385. */
  2386. var entries = {};
  2387. /**
  2388. * 注册并执行初始化函数
  2389. * @param selector CSS 选择器
  2390. * @param apiInit 初始化函数
  2391. * @param i 元素索引
  2392. * @param element 元素
  2393. */
  2394. function mutation(selector, apiInit, i, element) {
  2395. var selectors = data(element, '_mdui_mutation');
  2396. if (!selectors) {
  2397. selectors = [];
  2398. data(element, '_mdui_mutation', selectors);
  2399. }
  2400. if (selectors.indexOf(selector) === -1) {
  2401. selectors.push(selector);
  2402. apiInit.call(element, i, element);
  2403. }
  2404. }
  2405. $.fn.mutation = function () {
  2406. return this.each(function (i, element) {
  2407. var $this = $(element);
  2408. each(entries, function (selector, apiInit) {
  2409. if ($this.is(selector)) {
  2410. mutation(selector, apiInit, i, element);
  2411. }
  2412. $this.find(selector).each(function (i, element) {
  2413. mutation(selector, apiInit, i, element);
  2414. });
  2415. });
  2416. });
  2417. };
  2418. $.showOverlay = function (zIndex) {
  2419. var $overlay = $('.mdui-overlay');
  2420. if ($overlay.length) {
  2421. $overlay.data('_overlay_is_deleted', false);
  2422. if (!isUndefined(zIndex)) {
  2423. $overlay.css('z-index', zIndex);
  2424. }
  2425. }
  2426. else {
  2427. if (isUndefined(zIndex)) {
  2428. zIndex = 2000;
  2429. }
  2430. $overlay = $('<div class="mdui-overlay">')
  2431. .appendTo(document.body)
  2432. .reflow()
  2433. .css('z-index', zIndex);
  2434. }
  2435. var level = $overlay.data('_overlay_level') || 0;
  2436. return $overlay.data('_overlay_level', ++level).addClass('mdui-overlay-show');
  2437. };
  2438. $.hideOverlay = function (force) {
  2439. if ( force === void 0 ) force = false;
  2440. var $overlay = $('.mdui-overlay');
  2441. if (!$overlay.length) {
  2442. return;
  2443. }
  2444. var level = force ? 1 : $overlay.data('_overlay_level');
  2445. if (level > 1) {
  2446. $overlay.data('_overlay_level', --level);
  2447. return;
  2448. }
  2449. $overlay
  2450. .data('_overlay_level', 0)
  2451. .removeClass('mdui-overlay-show')
  2452. .data('_overlay_is_deleted', true)
  2453. .transitionEnd(function () {
  2454. if ($overlay.data('_overlay_is_deleted')) {
  2455. $overlay.remove();
  2456. }
  2457. });
  2458. };
  2459. $.lockScreen = function () {
  2460. var $body = $('body');
  2461. // 不直接把 body 设为 box-sizing: border-box,避免污染全局样式
  2462. var newBodyWidth = $body.width();
  2463. var level = $body.data('_lockscreen_level') || 0;
  2464. $body
  2465. .addClass('mdui-locked')
  2466. .width(newBodyWidth)
  2467. .data('_lockscreen_level', ++level);
  2468. };
  2469. $.unlockScreen = function (force) {
  2470. if ( force === void 0 ) force = false;
  2471. var $body = $('body');
  2472. var level = force ? 1 : $body.data('_lockscreen_level');
  2473. if (level > 1) {
  2474. $body.data('_lockscreen_level', --level);
  2475. return;
  2476. }
  2477. $body.data('_lockscreen_level', 0).removeClass('mdui-locked').width('');
  2478. };
  2479. $.throttle = function (fn, delay) {
  2480. if ( delay === void 0 ) delay = 16;
  2481. var timer = null;
  2482. return function () {
  2483. var this$1 = this;
  2484. var args = [], len = arguments.length;
  2485. while ( len-- ) args[ len ] = arguments[ len ];
  2486. if (isNull(timer)) {
  2487. timer = setTimeout(function () {
  2488. fn.apply(this$1, args);
  2489. timer = null;
  2490. }, delay);
  2491. }
  2492. };
  2493. };
  2494. var GUID = {};
  2495. $.guid = function (name) {
  2496. if (!isUndefined(name) && !isUndefined(GUID[name])) {
  2497. return GUID[name];
  2498. }
  2499. function s4() {
  2500. return Math.floor((1 + Math.random()) * 0x10000)
  2501. .toString(16)
  2502. .substring(1);
  2503. }
  2504. var guid = '_' +
  2505. s4() +
  2506. s4() +
  2507. '-' +
  2508. s4() +
  2509. '-' +
  2510. s4() +
  2511. '-' +
  2512. s4() +
  2513. '-' +
  2514. s4() +
  2515. s4() +
  2516. s4();
  2517. if (!isUndefined(name)) {
  2518. GUID[name] = guid;
  2519. }
  2520. return guid;
  2521. };
  2522. mdui.mutation = function (selector, apiInit) {
  2523. if (isUndefined(selector) || isUndefined(apiInit)) {
  2524. $(document).mutation();
  2525. return;
  2526. }
  2527. entries[selector] = apiInit;
  2528. $(selector).each(function (i, element) { return mutation(selector, apiInit, i, element); });
  2529. };
  2530. /**
  2531. * 触发组件上的事件
  2532. * @param eventName 事件名
  2533. * @param componentName 组件名
  2534. * @param target 在该元素上触发事件
  2535. * @param instance 组件实例
  2536. * @param parameters 事件参数
  2537. */
  2538. function componentEvent(eventName, componentName, target, instance, parameters) {
  2539. if (!parameters) {
  2540. parameters = {};
  2541. }
  2542. // @ts-ignore
  2543. parameters.inst = instance;
  2544. var fullEventName = eventName + ".mdui." + componentName;
  2545. // jQuery 事件
  2546. // @ts-ignore
  2547. if (typeof jQuery !== 'undefined') {
  2548. // @ts-ignore
  2549. jQuery(target).trigger(fullEventName, parameters);
  2550. }
  2551. var $target = $(target);
  2552. // mdui.jq 事件
  2553. $target.trigger(fullEventName, parameters);
  2554. var eventParams = {
  2555. bubbles: true,
  2556. cancelable: true,
  2557. detail: parameters,
  2558. };
  2559. var eventObject = new CustomEvent(fullEventName, eventParams);
  2560. // @ts-ignore
  2561. eventObject._detail = parameters;
  2562. $target[0].dispatchEvent(eventObject);
  2563. }
  2564. var $document = $(document);
  2565. var $window = $(window);
  2566. $('body');
  2567. var DEFAULT_OPTIONS = {
  2568. tolerance: 5,
  2569. offset: 0,
  2570. initialClass: 'mdui-headroom',
  2571. pinnedClass: 'mdui-headroom-pinned-top',
  2572. unpinnedClass: 'mdui-headroom-unpinned-top',
  2573. };
  2574. var Headroom = function Headroom(selector, options) {
  2575. if ( options === void 0 ) options = {};
  2576. /**
  2577. * 配置参数
  2578. */
  2579. this.options = extend({}, DEFAULT_OPTIONS);
  2580. /**
  2581. * 当前 headroom 的状态
  2582. */
  2583. this.state = 'pinned';
  2584. /**
  2585. * 当前是否启用
  2586. */
  2587. this.isEnable = false;
  2588. /**
  2589. * 上次滚动后,垂直方向的距离
  2590. */
  2591. this.lastScrollY = 0;
  2592. /**
  2593. * AnimationFrame ID
  2594. */
  2595. this.rafId = 0;
  2596. this.$element = $(selector).first();
  2597. extend(this.options, options);
  2598. // tolerance 参数若为数值,转换为对象
  2599. var tolerance = this.options.tolerance;
  2600. if (isNumber(tolerance)) {
  2601. this.options.tolerance = {
  2602. down: tolerance,
  2603. up: tolerance,
  2604. };
  2605. }
  2606. this.enable();
  2607. };
  2608. /**
  2609. * 滚动时的处理
  2610. */
  2611. Headroom.prototype.onScroll = function onScroll () {
  2612. var this$1 = this;
  2613. this.rafId = window.requestAnimationFrame(function () {
  2614. var currentScrollY = window.pageYOffset;
  2615. var direction = currentScrollY > this$1.lastScrollY ? 'down' : 'up';
  2616. var tolerance = this$1.options.tolerance[direction];
  2617. var scrolled = Math.abs(currentScrollY - this$1.lastScrollY);
  2618. var toleranceExceeded = scrolled >= tolerance;
  2619. if (currentScrollY > this$1.lastScrollY &&
  2620. currentScrollY >= this$1.options.offset &&
  2621. toleranceExceeded) {
  2622. this$1.unpin();
  2623. }
  2624. else if ((currentScrollY < this$1.lastScrollY && toleranceExceeded) ||
  2625. currentScrollY <= this$1.options.offset) {
  2626. this$1.pin();
  2627. }
  2628. this$1.lastScrollY = currentScrollY;
  2629. });
  2630. };
  2631. /**
  2632. * 触发组件事件
  2633. * @param name
  2634. */
  2635. Headroom.prototype.triggerEvent = function triggerEvent (name) {
  2636. componentEvent(name, 'headroom', this.$element, this);
  2637. };
  2638. /**
  2639. * 动画结束的回调
  2640. */
  2641. Headroom.prototype.transitionEnd = function transitionEnd () {
  2642. if (this.state === 'pinning') {
  2643. this.state = 'pinned';
  2644. this.triggerEvent('pinned');
  2645. }
  2646. if (this.state === 'unpinning') {
  2647. this.state = 'unpinned';
  2648. this.triggerEvent('unpinned');
  2649. }
  2650. };
  2651. /**
  2652. * 使元素固定住
  2653. */
  2654. Headroom.prototype.pin = function pin () {
  2655. var this$1 = this;
  2656. if (this.state === 'pinning' ||
  2657. this.state === 'pinned' ||
  2658. !this.$element.hasClass(this.options.initialClass)) {
  2659. return;
  2660. }
  2661. this.triggerEvent('pin');
  2662. this.state = 'pinning';
  2663. this.$element
  2664. .removeClass(this.options.unpinnedClass)
  2665. .addClass(this.options.pinnedClass)
  2666. .transitionEnd(function () { return this$1.transitionEnd(); });
  2667. };
  2668. /**
  2669. * 使元素隐藏
  2670. */
  2671. Headroom.prototype.unpin = function unpin () {
  2672. var this$1 = this;
  2673. if (this.state === 'unpinning' ||
  2674. this.state === 'unpinned' ||
  2675. !this.$element.hasClass(this.options.initialClass)) {
  2676. return;
  2677. }
  2678. this.triggerEvent('unpin');
  2679. this.state = 'unpinning';
  2680. this.$element
  2681. .removeClass(this.options.pinnedClass)
  2682. .addClass(this.options.unpinnedClass)
  2683. .transitionEnd(function () { return this$1.transitionEnd(); });
  2684. };
  2685. /**
  2686. * 启用 headroom 插件
  2687. */
  2688. Headroom.prototype.enable = function enable () {
  2689. var this$1 = this;
  2690. if (this.isEnable) {
  2691. return;
  2692. }
  2693. this.isEnable = true;
  2694. this.state = 'pinned';
  2695. this.$element
  2696. .addClass(this.options.initialClass)
  2697. .removeClass(this.options.pinnedClass)
  2698. .removeClass(this.options.unpinnedClass);
  2699. this.lastScrollY = window.pageYOffset;
  2700. $window.on('scroll', function () { return this$1.onScroll(); });
  2701. };
  2702. /**
  2703. * 禁用 headroom 插件
  2704. */
  2705. Headroom.prototype.disable = function disable () {
  2706. var this$1 = this;
  2707. if (!this.isEnable) {
  2708. return;
  2709. }
  2710. this.isEnable = false;
  2711. this.$element
  2712. .removeClass(this.options.initialClass)
  2713. .removeClass(this.options.pinnedClass)
  2714. .removeClass(this.options.unpinnedClass);
  2715. $window.off('scroll', function () { return this$1.onScroll(); });
  2716. window.cancelAnimationFrame(this.rafId);
  2717. };
  2718. /**
  2719. * 获取当前状态。共包含四种状态:`pinning`、`pinned`、`unpinning`、`unpinned`
  2720. */
  2721. Headroom.prototype.getState = function getState () {
  2722. return this.state;
  2723. };
  2724. mdui.Headroom = Headroom;
  2725. /**
  2726. * 解析 DATA API 参数
  2727. * @param element 元素
  2728. * @param name 属性名
  2729. */
  2730. function parseOptions(element, name) {
  2731. var attr = $(element).attr(name);
  2732. if (!attr) {
  2733. return {};
  2734. }
  2735. return new Function('', ("var json = " + attr + "; return JSON.parse(JSON.stringify(json));"))();
  2736. }
  2737. var customAttr = 'mdui-headroom';
  2738. $(function () {
  2739. mdui.mutation(("[" + customAttr + "]"), function () {
  2740. new mdui.Headroom(this, parseOptions(this, customAttr));
  2741. });
  2742. });
  2743. var DEFAULT_OPTIONS$1 = {
  2744. accordion: false,
  2745. };
  2746. var CollapseAbstract = function CollapseAbstract(selector, options) {
  2747. if ( options === void 0 ) options = {};
  2748. /**
  2749. * 配置参数
  2750. */
  2751. this.options = extend({}, DEFAULT_OPTIONS$1);
  2752. // CSS 类名
  2753. var classPrefix = "mdui-" + (this.getNamespace()) + "-item";
  2754. this.classItem = classPrefix;
  2755. this.classItemOpen = classPrefix + "-open";
  2756. this.classHeader = classPrefix + "-header";
  2757. this.classBody = classPrefix + "-body";
  2758. this.$element = $(selector).first();
  2759. extend(this.options, options);
  2760. this.bindEvent();
  2761. };
  2762. /**
  2763. * 绑定事件
  2764. */
  2765. CollapseAbstract.prototype.bindEvent = function bindEvent () {
  2766. // eslint-disable-next-line @typescript-eslint/no-this-alias
  2767. var that = this;
  2768. // 点击 header 时,打开/关闭 item
  2769. this.$element.on('click', ("." + (this.classHeader)), function () {
  2770. var $header = $(this);
  2771. var $item = $header.parent();
  2772. var $items = that.getItems();
  2773. $items.each(function (_, item) {
  2774. if ($item.is(item)) {
  2775. that.toggle(item);
  2776. }
  2777. });
  2778. });
  2779. // 点击关闭按钮时,关闭 item
  2780. this.$element.on('click', ("[mdui-" + (this.getNamespace()) + "-item-close]"), function () {
  2781. var $target = $(this);
  2782. var $item = $target.parents(("." + (that.classItem))).first();
  2783. that.close($item);
  2784. });
  2785. };
  2786. /**
  2787. * 指定 item 是否处于打开状态
  2788. * @param $item
  2789. */
  2790. CollapseAbstract.prototype.isOpen = function isOpen ($item) {
  2791. return $item.hasClass(this.classItemOpen);
  2792. };
  2793. /**
  2794. * 获取所有 item
  2795. */
  2796. CollapseAbstract.prototype.getItems = function getItems () {
  2797. return this.$element.children(("." + (this.classItem)));
  2798. };
  2799. /**
  2800. * 获取指定 item
  2801. * @param item
  2802. */
  2803. CollapseAbstract.prototype.getItem = function getItem (item) {
  2804. if (isNumber(item)) {
  2805. return this.getItems().eq(item);
  2806. }
  2807. return $(item).first();
  2808. };
  2809. /**
  2810. * 触发组件事件
  2811. * @param name 事件名
  2812. * @param $item 事件触发的目标 item
  2813. */
  2814. CollapseAbstract.prototype.triggerEvent = function triggerEvent (name, $item) {
  2815. componentEvent(name, this.getNamespace(), $item, this);
  2816. };
  2817. /**
  2818. * 动画结束回调
  2819. * @param $content body 元素
  2820. * @param $item item 元素
  2821. */
  2822. CollapseAbstract.prototype.transitionEnd = function transitionEnd ($content, $item) {
  2823. if (this.isOpen($item)) {
  2824. $content.transition(0).height('auto').reflow().transition('');
  2825. this.triggerEvent('opened', $item);
  2826. }
  2827. else {
  2828. $content.height('');
  2829. this.triggerEvent('closed', $item);
  2830. }
  2831. };
  2832. /**
  2833. * 打开指定面板项
  2834. * @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象
  2835. */
  2836. CollapseAbstract.prototype.open = function open (item) {
  2837. var this$1 = this;
  2838. var $item = this.getItem(item);
  2839. if (this.isOpen($item)) {
  2840. return;
  2841. }
  2842. // 关闭其他项
  2843. if (this.options.accordion) {
  2844. this.$element.children(("." + (this.classItemOpen))).each(function (_, element) {
  2845. var $element = $(element);
  2846. if (!$element.is($item)) {
  2847. this$1.close($element);
  2848. }
  2849. });
  2850. }
  2851. var $content = $item.children(("." + (this.classBody)));
  2852. $content
  2853. .height($content[0].scrollHeight)
  2854. .transitionEnd(function () { return this$1.transitionEnd($content, $item); });
  2855. this.triggerEvent('open', $item);
  2856. $item.addClass(this.classItemOpen);
  2857. };
  2858. /**
  2859. * 关闭指定面板项
  2860. * @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象
  2861. */
  2862. CollapseAbstract.prototype.close = function close (item) {
  2863. var this$1 = this;
  2864. var $item = this.getItem(item);
  2865. if (!this.isOpen($item)) {
  2866. return;
  2867. }
  2868. var $content = $item.children(("." + (this.classBody)));
  2869. this.triggerEvent('close', $item);
  2870. $item.removeClass(this.classItemOpen);
  2871. $content
  2872. .transition(0)
  2873. .height($content[0].scrollHeight)
  2874. .reflow()
  2875. .transition('')
  2876. .height('')
  2877. .transitionEnd(function () { return this$1.transitionEnd($content, $item); });
  2878. };
  2879. /**
  2880. * 切换指定面板项的打开状态
  2881. * @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象
  2882. */
  2883. CollapseAbstract.prototype.toggle = function toggle (item) {
  2884. var $item = this.getItem(item);
  2885. this.isOpen($item) ? this.close($item) : this.open($item);
  2886. };
  2887. /**
  2888. * 打开所有面板项
  2889. */
  2890. CollapseAbstract.prototype.openAll = function openAll () {
  2891. var this$1 = this;
  2892. this.getItems().each(function (_, element) { return this$1.open(element); });
  2893. };
  2894. /**
  2895. * 关闭所有面板项
  2896. */
  2897. CollapseAbstract.prototype.closeAll = function closeAll () {
  2898. var this$1 = this;
  2899. this.getItems().each(function (_, element) { return this$1.close(element); });
  2900. };
  2901. var Collapse = /*@__PURE__*/(function (CollapseAbstract) {
  2902. function Collapse () {
  2903. CollapseAbstract.apply(this, arguments);
  2904. }
  2905. if ( CollapseAbstract ) Collapse.__proto__ = CollapseAbstract;
  2906. Collapse.prototype = Object.create( CollapseAbstract && CollapseAbstract.prototype );
  2907. Collapse.prototype.constructor = Collapse;
  2908. Collapse.prototype.getNamespace = function getNamespace () {
  2909. return 'collapse';
  2910. };
  2911. return Collapse;
  2912. }(CollapseAbstract));
  2913. mdui.Collapse = Collapse;
  2914. var customAttr$1 = 'mdui-collapse';
  2915. $(function () {
  2916. mdui.mutation(("[" + customAttr$1 + "]"), function () {
  2917. new mdui.Collapse(this, parseOptions(this, customAttr$1));
  2918. });
  2919. });
  2920. var Panel = /*@__PURE__*/(function (CollapseAbstract) {
  2921. function Panel () {
  2922. CollapseAbstract.apply(this, arguments);
  2923. }
  2924. if ( CollapseAbstract ) Panel.__proto__ = CollapseAbstract;
  2925. Panel.prototype = Object.create( CollapseAbstract && CollapseAbstract.prototype );
  2926. Panel.prototype.constructor = Panel;
  2927. Panel.prototype.getNamespace = function getNamespace () {
  2928. return 'panel';
  2929. };
  2930. return Panel;
  2931. }(CollapseAbstract));
  2932. mdui.Panel = Panel;
  2933. var customAttr$2 = 'mdui-panel';
  2934. $(function () {
  2935. mdui.mutation(("[" + customAttr$2 + "]"), function () {
  2936. new mdui.Panel(this, parseOptions(this, customAttr$2));
  2937. });
  2938. });
  2939. var Table = function Table(selector) {
  2940. /**
  2941. * 表头 tr 元素
  2942. */
  2943. this.$thRow = $();
  2944. /**
  2945. * 表格 body 中的 tr 元素
  2946. */
  2947. this.$tdRows = $();
  2948. /**
  2949. * 表头的 checkbox 元素
  2950. */
  2951. this.$thCheckbox = $();
  2952. /**
  2953. * 表格 body 中的 checkbox 元素
  2954. */
  2955. this.$tdCheckboxs = $();
  2956. /**
  2957. * 表格行是否可选择
  2958. */
  2959. this.selectable = false;
  2960. /**
  2961. * 已选中的行数
  2962. */
  2963. this.selectedRow = 0;
  2964. this.$element = $(selector).first();
  2965. this.init();
  2966. };
  2967. /**
  2968. * 初始化表格
  2969. */
  2970. Table.prototype.init = function init () {
  2971. this.$thRow = this.$element.find('thead tr');
  2972. this.$tdRows = this.$element.find('tbody tr');
  2973. this.selectable = this.$element.hasClass('mdui-table-selectable');
  2974. this.updateThCheckbox();
  2975. this.updateTdCheckbox();
  2976. this.updateNumericCol();
  2977. };
  2978. /**
  2979. * 生成 checkbox 的 HTML 结构
  2980. * @param tag 标签名
  2981. */
  2982. Table.prototype.createCheckboxHTML = function createCheckboxHTML (tag) {
  2983. return ("<" + tag + " class=\"mdui-table-cell-checkbox\">" +
  2984. '<label class="mdui-checkbox">' +
  2985. '<input type="checkbox"/>' +
  2986. '<i class="mdui-checkbox-icon"></i>' +
  2987. '</label>' +
  2988. "</" + tag + ">");
  2989. };
  2990. /**
  2991. * 更新表头 checkbox 的状态
  2992. */
  2993. Table.prototype.updateThCheckboxStatus = function updateThCheckboxStatus () {
  2994. var checkbox = this.$thCheckbox[0];
  2995. var selectedRow = this.selectedRow;
  2996. var tdRowsLength = this.$tdRows.length;
  2997. checkbox.checked = selectedRow === tdRowsLength;
  2998. checkbox.indeterminate = !!selectedRow && selectedRow !== tdRowsLength;
  2999. };
  3000. /**
  3001. * 更新表格行的 checkbox
  3002. */
  3003. Table.prototype.updateTdCheckbox = function updateTdCheckbox () {
  3004. var this$1 = this;
  3005. var rowSelectedClass = 'mdui-table-row-selected';
  3006. this.$tdRows.each(function (_, row) {
  3007. var $row = $(row);
  3008. // 移除旧的 checkbox
  3009. $row.find('.mdui-table-cell-checkbox').remove();
  3010. if (!this$1.selectable) {
  3011. return;
  3012. }
  3013. // 创建 DOM
  3014. var $checkbox = $(this$1.createCheckboxHTML('td'))
  3015. .prependTo($row)
  3016. .find('input[type="checkbox"]');
  3017. // 默认选中的行
  3018. if ($row.hasClass(rowSelectedClass)) {
  3019. $checkbox[0].checked = true;
  3020. this$1.selectedRow++;
  3021. }
  3022. this$1.updateThCheckboxStatus();
  3023. // 绑定事件
  3024. $checkbox.on('change', function () {
  3025. if ($checkbox[0].checked) {
  3026. $row.addClass(rowSelectedClass);
  3027. this$1.selectedRow++;
  3028. }
  3029. else {
  3030. $row.removeClass(rowSelectedClass);
  3031. this$1.selectedRow--;
  3032. }
  3033. this$1.updateThCheckboxStatus();
  3034. });
  3035. this$1.$tdCheckboxs = this$1.$tdCheckboxs.add($checkbox);
  3036. });
  3037. };
  3038. /**
  3039. * 更新表头的 checkbox
  3040. */
  3041. Table.prototype.updateThCheckbox = function updateThCheckbox () {
  3042. var this$1 = this;
  3043. // 移除旧的 checkbox
  3044. this.$thRow.find('.mdui-table-cell-checkbox').remove();
  3045. if (!this.selectable) {
  3046. return;
  3047. }
  3048. this.$thCheckbox = $(this.createCheckboxHTML('th'))
  3049. .prependTo(this.$thRow)
  3050. .find('input[type="checkbox"]')
  3051. .on('change', function () {
  3052. var isCheckedAll = this$1.$thCheckbox[0].checked;
  3053. this$1.selectedRow = isCheckedAll ? this$1.$tdRows.length : 0;
  3054. this$1.$tdCheckboxs.each(function (_, checkbox) {
  3055. checkbox.checked = isCheckedAll;
  3056. });
  3057. this$1.$tdRows.each(function (_, row) {
  3058. isCheckedAll
  3059. ? $(row).addClass('mdui-table-row-selected')
  3060. : $(row).removeClass('mdui-table-row-selected');
  3061. });
  3062. });
  3063. };
  3064. /**
  3065. * 更新数值列
  3066. */
  3067. Table.prototype.updateNumericCol = function updateNumericCol () {
  3068. var this$1 = this;
  3069. var numericClass = 'mdui-table-col-numeric';
  3070. this.$thRow.find('th').each(function (i, th) {
  3071. var isNumericCol = $(th).hasClass(numericClass);
  3072. this$1.$tdRows.each(function (_, row) {
  3073. var $td = $(row).find('td').eq(i);
  3074. isNumericCol
  3075. ? $td.addClass(numericClass)
  3076. : $td.removeClass(numericClass);
  3077. });
  3078. });
  3079. };
  3080. var dataName = '_mdui_table';
  3081. $(function () {
  3082. mdui.mutation('.mdui-table', function () {
  3083. var $element = $(this);
  3084. if (!$element.data(dataName)) {
  3085. $element.data(dataName, new Table($element));
  3086. }
  3087. });
  3088. });
  3089. mdui.updateTables = function (selector) {
  3090. var $elements = isUndefined(selector) ? $('.mdui-table') : $(selector);
  3091. $elements.each(function (_, element) {
  3092. var $element = $(element);
  3093. var instance = $element.data(dataName);
  3094. if (instance) {
  3095. instance.init();
  3096. }
  3097. else {
  3098. $element.data(dataName, new Table($element));
  3099. }
  3100. });
  3101. };
  3102. /**
  3103. * touch 事件后的 500ms 内禁用 mousedown 事件
  3104. *
  3105. * 不支持触控的屏幕上事件顺序为 mousedown -> mouseup -> click
  3106. * 支持触控的屏幕上事件顺序为 touchstart -> touchend -> mousedown -> mouseup -> click
  3107. *
  3108. * 在每一个事件中都使用 TouchHandler.isAllow(event) 判断事件是否可执行
  3109. * 在 touchstart 和 touchmove、touchend、touchcancel
  3110. *
  3111. * (function () {
  3112. * $document
  3113. * .on(start, function (e) {
  3114. * if (!isAllow(e)) {
  3115. * return;
  3116. * }
  3117. * register(e);
  3118. * console.log(e.type);
  3119. * })
  3120. * .on(move, function (e) {
  3121. * if (!isAllow(e)) {
  3122. * return;
  3123. * }
  3124. * console.log(e.type);
  3125. * })
  3126. * .on(end, function (e) {
  3127. * if (!isAllow(e)) {
  3128. * return;
  3129. * }
  3130. * console.log(e.type);
  3131. * })
  3132. * .on(unlock, register);
  3133. * })();
  3134. */
  3135. var startEvent = 'touchstart mousedown';
  3136. var moveEvent = 'touchmove mousemove';
  3137. var endEvent = 'touchend mouseup';
  3138. var cancelEvent = 'touchcancel mouseleave';
  3139. var unlockEvent = 'touchend touchmove touchcancel';
  3140. var touches = 0;
  3141. /**
  3142. * 该事件是否被允许,在执行事件前调用该方法判断事件是否可以执行
  3143. * 若已触发 touch 事件,则阻止之后的鼠标事件
  3144. * @param event
  3145. */
  3146. function isAllow(event) {
  3147. return !(touches &&
  3148. [
  3149. 'mousedown',
  3150. 'mouseup',
  3151. 'mousemove',
  3152. 'click',
  3153. 'mouseover',
  3154. 'mouseout',
  3155. 'mouseenter',
  3156. 'mouseleave' ].indexOf(event.type) > -1);
  3157. }
  3158. /**
  3159. * 在 touchstart 和 touchmove、touchend、touchcancel 事件中调用该方法注册事件
  3160. * @param event
  3161. */
  3162. function register(event) {
  3163. if (event.type === 'touchstart') {
  3164. // 触发了 touch 事件
  3165. touches += 1;
  3166. }
  3167. else if (['touchmove', 'touchend', 'touchcancel'].indexOf(event.type) > -1) {
  3168. // touch 事件结束 500ms 后解除对鼠标事件的阻止
  3169. setTimeout(function () {
  3170. if (touches) {
  3171. touches -= 1;
  3172. }
  3173. }, 500);
  3174. }
  3175. }
  3176. /**
  3177. * Inspired by https://github.com/nolimits4web/Framework7/blob/master/src/js/fast-clicks.js
  3178. * https://github.com/nolimits4web/Framework7/blob/master/LICENSE
  3179. *
  3180. * Inspired by https://github.com/fians/Waves
  3181. */
  3182. /**
  3183. * 显示涟漪动画
  3184. * @param event
  3185. * @param $ripple
  3186. */
  3187. function show(event, $ripple) {
  3188. // 鼠标右键不产生涟漪
  3189. if (event instanceof MouseEvent && event.button === 2) {
  3190. return;
  3191. }
  3192. // 点击位置坐标
  3193. var touchPosition = typeof TouchEvent !== 'undefined' &&
  3194. event instanceof TouchEvent &&
  3195. event.touches.length
  3196. ? event.touches[0]
  3197. : event;
  3198. var touchStartX = touchPosition.pageX;
  3199. var touchStartY = touchPosition.pageY;
  3200. // 涟漪位置
  3201. var offset = $ripple.offset();
  3202. var height = $ripple.innerHeight();
  3203. var width = $ripple.innerWidth();
  3204. var center = {
  3205. x: touchStartX - offset.left,
  3206. y: touchStartY - offset.top,
  3207. };
  3208. var diameter = Math.max(Math.pow(Math.pow(height, 2) + Math.pow(width, 2), 0.5), 48);
  3209. // 涟漪扩散动画
  3210. var translate = "translate3d(" + (-center.x + width / 2) + "px," +
  3211. (-center.y + height / 2) + "px, 0) scale(1)";
  3212. // 涟漪的 DOM 结构,并缓存动画效果
  3213. $("<div class=\"mdui-ripple-wave\" " +
  3214. "style=\"width:" + diameter + "px;height:" + diameter + "px;" +
  3215. "margin-top:-" + (diameter / 2) + "px;margin-left:-" + (diameter / 2) + "px;" +
  3216. "left:" + (center.x) + "px;top:" + (center.y) + "px;\"></div>")
  3217. .data('_ripple_wave_translate', translate)
  3218. .prependTo($ripple)
  3219. .reflow()
  3220. .transform(translate);
  3221. }
  3222. /**
  3223. * 隐藏并移除涟漪
  3224. * @param $wave
  3225. */
  3226. function removeRipple($wave) {
  3227. if (!$wave.length || $wave.data('_ripple_wave_removed')) {
  3228. return;
  3229. }
  3230. $wave.data('_ripple_wave_removed', true);
  3231. var removeTimer = setTimeout(function () { return $wave.remove(); }, 400);
  3232. var translate = $wave.data('_ripple_wave_translate');
  3233. $wave
  3234. .addClass('mdui-ripple-wave-fill')
  3235. .transform(translate.replace('scale(1)', 'scale(1.01)'))
  3236. .transitionEnd(function () {
  3237. clearTimeout(removeTimer);
  3238. $wave
  3239. .addClass('mdui-ripple-wave-out')
  3240. .transform(translate.replace('scale(1)', 'scale(1.01)'));
  3241. removeTimer = setTimeout(function () { return $wave.remove(); }, 700);
  3242. setTimeout(function () {
  3243. $wave.transitionEnd(function () {
  3244. clearTimeout(removeTimer);
  3245. $wave.remove();
  3246. });
  3247. }, 0);
  3248. });
  3249. }
  3250. /**
  3251. * 隐藏涟漪动画
  3252. * @param this
  3253. */
  3254. function hide() {
  3255. var $ripple = $(this);
  3256. $ripple.children('.mdui-ripple-wave').each(function (_, wave) {
  3257. removeRipple($(wave));
  3258. });
  3259. $ripple.off((moveEvent + " " + endEvent + " " + cancelEvent), hide);
  3260. }
  3261. /**
  3262. * 显示涟漪,并绑定 touchend 等事件
  3263. * @param event
  3264. */
  3265. function showRipple(event) {
  3266. if (!isAllow(event)) {
  3267. return;
  3268. }
  3269. register(event);
  3270. // Chrome 59 点击滚动条时,会在 document 上触发事件
  3271. if (event.target === document) {
  3272. return;
  3273. }
  3274. var $target = $(event.target);
  3275. // 获取含 .mdui-ripple 类的元素
  3276. var $ripple = $target.hasClass('mdui-ripple')
  3277. ? $target
  3278. : $target.parents('.mdui-ripple').first();
  3279. if (!$ripple.length) {
  3280. return;
  3281. }
  3282. // 禁用状态的元素上不产生涟漪效果
  3283. if ($ripple.prop('disabled') || !isUndefined($ripple.attr('disabled'))) {
  3284. return;
  3285. }
  3286. if (event.type === 'touchstart') {
  3287. var hidden = false;
  3288. // touchstart 触发指定时间后开始涟漪动画,避免手指滑动时也触发涟漪
  3289. var timer = setTimeout(function () {
  3290. timer = 0;
  3291. show(event, $ripple);
  3292. }, 200);
  3293. var hideRipple = function () {
  3294. // 如果手指没有移动,且涟漪动画还没有开始,则开始涟漪动画
  3295. if (timer) {
  3296. clearTimeout(timer);
  3297. timer = 0;
  3298. show(event, $ripple);
  3299. }
  3300. if (!hidden) {
  3301. hidden = true;
  3302. hide.call($ripple);
  3303. }
  3304. };
  3305. // 手指移动后,移除涟漪动画
  3306. var touchMove = function () {
  3307. if (timer) {
  3308. clearTimeout(timer);
  3309. timer = 0;
  3310. }
  3311. hideRipple();
  3312. };
  3313. $ripple.on('touchmove', touchMove).on('touchend touchcancel', hideRipple);
  3314. }
  3315. else {
  3316. show(event, $ripple);
  3317. $ripple.on((moveEvent + " " + endEvent + " " + cancelEvent), hide);
  3318. }
  3319. }
  3320. $(function () {
  3321. $document.on(startEvent, showRipple).on(unlockEvent, register);
  3322. });
  3323. var defaultData = {
  3324. reInit: false,
  3325. domLoadedEvent: false,
  3326. };
  3327. /**
  3328. * 输入框事件
  3329. * @param event
  3330. * @param data
  3331. */
  3332. function inputEvent(event, data) {
  3333. if ( data === void 0 ) data = {};
  3334. data = extend({}, defaultData, data);
  3335. var input = event.target;
  3336. var $input = $(input);
  3337. var eventType = event.type;
  3338. var value = $input.val();
  3339. // 文本框类型
  3340. var inputType = $input.attr('type') || '';
  3341. if (['checkbox', 'button', 'submit', 'range', 'radio', 'image'].indexOf(inputType) > -1) {
  3342. return;
  3343. }
  3344. var $textfield = $input.parent('.mdui-textfield');
  3345. // 输入框是否聚焦
  3346. if (eventType === 'focus') {
  3347. $textfield.addClass('mdui-textfield-focus');
  3348. }
  3349. if (eventType === 'blur') {
  3350. $textfield.removeClass('mdui-textfield-focus');
  3351. }
  3352. // 输入框是否为空
  3353. if (eventType === 'blur' || eventType === 'input') {
  3354. value
  3355. ? $textfield.addClass('mdui-textfield-not-empty')
  3356. : $textfield.removeClass('mdui-textfield-not-empty');
  3357. }
  3358. // 输入框是否禁用
  3359. input.disabled
  3360. ? $textfield.addClass('mdui-textfield-disabled')
  3361. : $textfield.removeClass('mdui-textfield-disabled');
  3362. // 表单验证
  3363. if ((eventType === 'input' || eventType === 'blur') &&
  3364. !data.domLoadedEvent &&
  3365. input.validity) {
  3366. input.validity.valid
  3367. ? $textfield.removeClass('mdui-textfield-invalid-html5')
  3368. : $textfield.addClass('mdui-textfield-invalid-html5');
  3369. }
  3370. // textarea 高度自动调整
  3371. if ($input.is('textarea')) {
  3372. // IE bug:textarea 的值仅为多个换行,不含其他内容时,textarea 的高度不准确
  3373. // 此时,在计算高度前,在值的开头加入一个空格,计算完后,移除空格
  3374. var inputValue = value;
  3375. var hasExtraSpace = false;
  3376. if (inputValue.replace(/[\r\n]/g, '') === '') {
  3377. $input.val(' ' + inputValue);
  3378. hasExtraSpace = true;
  3379. }
  3380. // 设置 textarea 高度
  3381. $input.outerHeight('');
  3382. var height = $input.outerHeight();
  3383. var scrollHeight = input.scrollHeight;
  3384. if (scrollHeight > height) {
  3385. $input.outerHeight(scrollHeight);
  3386. }
  3387. // 计算完,还原 textarea 的值
  3388. if (hasExtraSpace) {
  3389. $input.val(inputValue);
  3390. }
  3391. }
  3392. // 实时字数统计
  3393. if (data.reInit) {
  3394. $textfield.find('.mdui-textfield-counter').remove();
  3395. }
  3396. var maxLength = $input.attr('maxlength');
  3397. if (maxLength) {
  3398. if (data.reInit || data.domLoadedEvent) {
  3399. $('<div class="mdui-textfield-counter">' +
  3400. "<span class=\"mdui-textfield-counter-inputed\"></span> / " + maxLength +
  3401. '</div>').appendTo($textfield);
  3402. }
  3403. $textfield
  3404. .find('.mdui-textfield-counter-inputed')
  3405. .text(value.length.toString());
  3406. }
  3407. // 含 帮助文本、错误提示、字数统计 时,增加文本框底部内边距
  3408. if ($textfield.find('.mdui-textfield-helper').length ||
  3409. $textfield.find('.mdui-textfield-error').length ||
  3410. maxLength) {
  3411. $textfield.addClass('mdui-textfield-has-bottom');
  3412. }
  3413. }
  3414. $(function () {
  3415. // 绑定事件
  3416. $document.on('input focus blur', '.mdui-textfield-input', { useCapture: true }, inputEvent);
  3417. // 可展开文本框展开
  3418. $document.on('click', '.mdui-textfield-expandable .mdui-textfield-icon', function () {
  3419. $(this)
  3420. .parents('.mdui-textfield')
  3421. .addClass('mdui-textfield-expanded')
  3422. .find('.mdui-textfield-input')[0]
  3423. .focus();
  3424. });
  3425. // 可展开文本框关闭
  3426. $document.on('click', '.mdui-textfield-expanded .mdui-textfield-close', function () {
  3427. $(this)
  3428. .parents('.mdui-textfield')
  3429. .removeClass('mdui-textfield-expanded')
  3430. .find('.mdui-textfield-input')
  3431. .val('');
  3432. });
  3433. /**
  3434. * 初始化文本框
  3435. */
  3436. mdui.mutation('.mdui-textfield', function () {
  3437. $(this).find('.mdui-textfield-input').trigger('input', {
  3438. domLoadedEvent: true,
  3439. });
  3440. });
  3441. });
  3442. mdui.updateTextFields = function (selector) {
  3443. var $elements = isUndefined(selector) ? $('.mdui-textfield') : $(selector);
  3444. $elements.each(function (_, element) {
  3445. $(element).find('.mdui-textfield-input').trigger('input', {
  3446. reInit: true,
  3447. });
  3448. });
  3449. };
  3450. /**
  3451. * 滑块的值改变后修改滑块样式
  3452. * @param $slider
  3453. */
  3454. function updateValueStyle($slider) {
  3455. var data = $slider.data();
  3456. var $track = data._slider_$track;
  3457. var $fill = data._slider_$fill;
  3458. var $thumb = data._slider_$thumb;
  3459. var $input = data._slider_$input;
  3460. var min = data._slider_min;
  3461. var max = data._slider_max;
  3462. var isDisabled = data._slider_disabled;
  3463. var isDiscrete = data._slider_discrete;
  3464. var $thumbText = data._slider_$thumbText;
  3465. var value = $input.val();
  3466. var percent = ((value - min) / (max - min)) * 100;
  3467. $fill.width((percent + "%"));
  3468. $track.width(((100 - percent) + "%"));
  3469. if (isDisabled) {
  3470. $fill.css('padding-right', '6px');
  3471. $track.css('padding-left', '6px');
  3472. }
  3473. $thumb.css('left', (percent + "%"));
  3474. if (isDiscrete) {
  3475. $thumbText.text(value);
  3476. }
  3477. percent === 0
  3478. ? $slider.addClass('mdui-slider-zero')
  3479. : $slider.removeClass('mdui-slider-zero');
  3480. }
  3481. /**
  3482. * 重新初始化滑块
  3483. * @param $slider
  3484. */
  3485. function reInit($slider) {
  3486. var $track = $('<div class="mdui-slider-track"></div>');
  3487. var $fill = $('<div class="mdui-slider-fill"></div>');
  3488. var $thumb = $('<div class="mdui-slider-thumb"></div>');
  3489. var $input = $slider.find('input[type="range"]');
  3490. var isDisabled = $input[0].disabled;
  3491. var isDiscrete = $slider.hasClass('mdui-slider-discrete');
  3492. // 禁用状态
  3493. isDisabled
  3494. ? $slider.addClass('mdui-slider-disabled')
  3495. : $slider.removeClass('mdui-slider-disabled');
  3496. // 重新填充 HTML
  3497. $slider.find('.mdui-slider-track').remove();
  3498. $slider.find('.mdui-slider-fill').remove();
  3499. $slider.find('.mdui-slider-thumb').remove();
  3500. $slider.append($track).append($fill).append($thumb);
  3501. // 间续型滑块
  3502. var $thumbText = $();
  3503. if (isDiscrete) {
  3504. $thumbText = $('<span></span>');
  3505. $thumb.empty().append($thumbText);
  3506. }
  3507. $slider.data('_slider_$track', $track);
  3508. $slider.data('_slider_$fill', $fill);
  3509. $slider.data('_slider_$thumb', $thumb);
  3510. $slider.data('_slider_$input', $input);
  3511. $slider.data('_slider_min', $input.attr('min'));
  3512. $slider.data('_slider_max', $input.attr('max'));
  3513. $slider.data('_slider_disabled', isDisabled);
  3514. $slider.data('_slider_discrete', isDiscrete);
  3515. $slider.data('_slider_$thumbText', $thumbText);
  3516. // 设置默认值
  3517. updateValueStyle($slider);
  3518. }
  3519. var rangeSelector = '.mdui-slider input[type="range"]';
  3520. $(function () {
  3521. // 滑块滑动事件
  3522. $document.on('input change', rangeSelector, function () {
  3523. var $slider = $(this).parent();
  3524. updateValueStyle($slider);
  3525. });
  3526. // 开始触摸滑块事件
  3527. $document.on(startEvent, rangeSelector, function (event) {
  3528. if (!isAllow(event)) {
  3529. return;
  3530. }
  3531. register(event);
  3532. if (this.disabled) {
  3533. return;
  3534. }
  3535. var $slider = $(this).parent();
  3536. $slider.addClass('mdui-slider-focus');
  3537. });
  3538. // 结束触摸滑块事件
  3539. $document.on(endEvent, rangeSelector, function (event) {
  3540. if (!isAllow(event)) {
  3541. return;
  3542. }
  3543. if (this.disabled) {
  3544. return;
  3545. }
  3546. var $slider = $(this).parent();
  3547. $slider.removeClass('mdui-slider-focus');
  3548. });
  3549. $document.on(unlockEvent, rangeSelector, register);
  3550. /**
  3551. * 初始化滑块
  3552. */
  3553. mdui.mutation('.mdui-slider', function () {
  3554. reInit($(this));
  3555. });
  3556. });
  3557. mdui.updateSliders = function (selector) {
  3558. var $elements = isUndefined(selector) ? $('.mdui-slider') : $(selector);
  3559. $elements.each(function (_, element) {
  3560. reInit($(element));
  3561. });
  3562. };
  3563. var DEFAULT_OPTIONS$2 = {
  3564. trigger: 'hover',
  3565. };
  3566. var Fab = function Fab(selector, options) {
  3567. var this$1 = this;
  3568. if ( options === void 0 ) options = {};
  3569. /**
  3570. * 配置参数
  3571. */
  3572. this.options = extend({}, DEFAULT_OPTIONS$2);
  3573. /**
  3574. * 当前 fab 的状态
  3575. */
  3576. this.state = 'closed';
  3577. this.$element = $(selector).first();
  3578. extend(this.options, options);
  3579. this.$btn = this.$element.find('.mdui-fab');
  3580. this.$dial = this.$element.find('.mdui-fab-dial');
  3581. this.$dialBtns = this.$dial.find('.mdui-fab');
  3582. if (this.options.trigger === 'hover') {
  3583. this.$btn.on('touchstart mouseenter', function () { return this$1.open(); });
  3584. this.$element.on('mouseleave', function () { return this$1.close(); });
  3585. }
  3586. if (this.options.trigger === 'click') {
  3587. this.$btn.on(startEvent, function () { return this$1.open(); });
  3588. }
  3589. // 触摸屏幕其他地方关闭快速拨号
  3590. $document.on(startEvent, function (event) {
  3591. if ($(event.target).parents('.mdui-fab-wrapper').length) {
  3592. return;
  3593. }
  3594. this$1.close();
  3595. });
  3596. };
  3597. /**
  3598. * 触发组件事件
  3599. * @param name
  3600. */
  3601. Fab.prototype.triggerEvent = function triggerEvent (name) {
  3602. componentEvent(name, 'fab', this.$element, this);
  3603. };
  3604. /**
  3605. * 当前是否为打开状态
  3606. */
  3607. Fab.prototype.isOpen = function isOpen () {
  3608. return this.state === 'opening' || this.state === 'opened';
  3609. };
  3610. /**
  3611. * 打开快速拨号菜单
  3612. */
  3613. Fab.prototype.open = function open () {
  3614. var this$1 = this;
  3615. if (this.isOpen()) {
  3616. return;
  3617. }
  3618. // 为菜单中的按钮添加不同的 transition-delay
  3619. this.$dialBtns.each(function (index, btn) {
  3620. var delay = (15 * (this$1.$dialBtns.length - index)) + "ms";
  3621. btn.style.transitionDelay = delay;
  3622. btn.style.webkitTransitionDelay = delay;
  3623. });
  3624. this.$dial.css('height', 'auto').addClass('mdui-fab-dial-show');
  3625. // 如果按钮中存在 .mdui-fab-opened 的图标,则进行图标切换
  3626. if (this.$btn.find('.mdui-fab-opened').length) {
  3627. this.$btn.addClass('mdui-fab-opened');
  3628. }
  3629. this.state = 'opening';
  3630. this.triggerEvent('open');
  3631. // 打开顺序为从下到上逐个打开,最上面的打开后才表示动画完成
  3632. this.$dialBtns.first().transitionEnd(function () {
  3633. if (this$1.$btn.hasClass('mdui-fab-opened')) {
  3634. this$1.state = 'opened';
  3635. this$1.triggerEvent('opened');
  3636. }
  3637. });
  3638. };
  3639. /**
  3640. * 关闭快速拨号菜单
  3641. */
  3642. Fab.prototype.close = function close () {
  3643. var this$1 = this;
  3644. if (!this.isOpen()) {
  3645. return;
  3646. }
  3647. // 为菜单中的按钮添加不同的 transition-delay
  3648. this.$dialBtns.each(function (index, btn) {
  3649. var delay = (15 * index) + "ms";
  3650. btn.style.transitionDelay = delay;
  3651. btn.style.webkitTransitionDelay = delay;
  3652. });
  3653. this.$dial.removeClass('mdui-fab-dial-show');
  3654. this.$btn.removeClass('mdui-fab-opened');
  3655. this.state = 'closing';
  3656. this.triggerEvent('close');
  3657. // 从上往下依次关闭,最后一个关闭后才表示动画完成
  3658. this.$dialBtns.last().transitionEnd(function () {
  3659. if (this$1.$btn.hasClass('mdui-fab-opened')) {
  3660. return;
  3661. }
  3662. this$1.state = 'closed';
  3663. this$1.triggerEvent('closed');
  3664. this$1.$dial.css('height', 0);
  3665. });
  3666. };
  3667. /**
  3668. * 切换快速拨号菜单的打开状态
  3669. */
  3670. Fab.prototype.toggle = function toggle () {
  3671. this.isOpen() ? this.close() : this.open();
  3672. };
  3673. /**
  3674. * 以动画的形式显示整个浮动操作按钮
  3675. */
  3676. Fab.prototype.show = function show () {
  3677. this.$element.removeClass('mdui-fab-hide');
  3678. };
  3679. /**
  3680. * 以动画的形式隐藏整个浮动操作按钮
  3681. */
  3682. Fab.prototype.hide = function hide () {
  3683. this.$element.addClass('mdui-fab-hide');
  3684. };
  3685. /**
  3686. * 返回当前快速拨号菜单的打开状态。共包含四种状态:`opening`、`opened`、`closing`、`closed`
  3687. */
  3688. Fab.prototype.getState = function getState () {
  3689. return this.state;
  3690. };
  3691. mdui.Fab = Fab;
  3692. var customAttr$3 = 'mdui-fab';
  3693. $(function () {
  3694. // mouseenter 不冒泡,无法进行事件委托,这里用 mouseover 代替。
  3695. // 不管是 click 、 mouseover 还是 touchstart ,都先初始化。
  3696. $document.on('touchstart mousedown mouseover', ("[" + customAttr$3 + "]"), function () {
  3697. new mdui.Fab(this, parseOptions(this, customAttr$3));
  3698. });
  3699. });
  3700. /**
  3701. * 最终生成的元素结构为:
  3702. * <select class="mdui-select" mdui-select="{position: 'top'}" style="display: none;"> // $native
  3703. * <option value="1">State 1</option>
  3704. * <option value="2">State 2</option>
  3705. * <option value="3" disabled="">State 3</option>
  3706. * </select>
  3707. * <div class="mdui-select mdui-select-position-top" style="" id="88dec0e4-d4a2-c6d0-0e7f-1ba4501e0553"> // $element
  3708. * <span class="mdui-select-selected">State 1</span> // $selected
  3709. * <div class="mdui-select-menu" style="transform-origin: center 100% 0px;"> // $menu
  3710. * <div class="mdui-select-menu-item mdui-ripple" selected="">State 1</div> // $items
  3711. * <div class="mdui-select-menu-item mdui-ripple">State 2</div>
  3712. * <div class="mdui-select-menu-item mdui-ripple" disabled="">State 3</div>
  3713. * </div>
  3714. * </div>
  3715. */
  3716. var DEFAULT_OPTIONS$3 = {
  3717. position: 'auto',
  3718. gutter: 16,
  3719. };
  3720. var Select = function Select(selector, options) {
  3721. var this$1 = this;
  3722. if ( options === void 0 ) options = {};
  3723. /**
  3724. * 生成的 `<div class="mdui-select">` 元素的 JQ 对象
  3725. */
  3726. this.$element = $();
  3727. /**
  3728. * 配置参数
  3729. */
  3730. this.options = extend({}, DEFAULT_OPTIONS$3);
  3731. /**
  3732. * select 的 size 属性的值,根据该值设置 select 的高度
  3733. */
  3734. this.size = 0;
  3735. /**
  3736. * 占位元素,显示已选中菜单项的文本
  3737. */
  3738. this.$selected = $();
  3739. /**
  3740. * 菜单项的外层元素的 JQ 对象
  3741. */
  3742. this.$menu = $();
  3743. /**
  3744. * 菜单项数组的 JQ 对象
  3745. */
  3746. this.$items = $();
  3747. /**
  3748. * 当前选中的菜单项的索引号
  3749. */
  3750. this.selectedIndex = 0;
  3751. /**
  3752. * 当前选中菜单项的文本
  3753. */
  3754. this.selectedText = '';
  3755. /**
  3756. * 当前选中菜单项的值
  3757. */
  3758. this.selectedValue = '';
  3759. /**
  3760. * 当前 select 的状态
  3761. */
  3762. this.state = 'closed';
  3763. this.$native = $(selector).first();
  3764. this.$native.hide();
  3765. extend(this.options, options);
  3766. // 为当前 select 生成唯一 ID
  3767. this.uniqueID = $.guid();
  3768. // 生成 select
  3769. this.handleUpdate();
  3770. // 点击 select 外面区域关闭
  3771. $document.on('click touchstart', function (event) {
  3772. var $target = $(event.target);
  3773. if (this$1.isOpen() &&
  3774. !$target.is(this$1.$element) &&
  3775. !contains(this$1.$element[0], $target[0])) {
  3776. this$1.close();
  3777. }
  3778. });
  3779. };
  3780. /**
  3781. * 调整菜单位置
  3782. */
  3783. Select.prototype.readjustMenu = function readjustMenu () {
  3784. var windowHeight = $window.height();
  3785. // mdui-select 高度
  3786. var elementHeight = this.$element.height();
  3787. // 菜单项高度
  3788. var $itemFirst = this.$items.first();
  3789. var itemHeight = $itemFirst.height();
  3790. var itemMargin = parseInt($itemFirst.css('margin-top'));
  3791. // 菜单高度
  3792. var menuWidth = this.$element.innerWidth() + 0.01; // 必须比真实宽度多一点,不然会出现省略号
  3793. var menuHeight = itemHeight * this.size + itemMargin * 2;
  3794. // mdui-select 在窗口中的位置
  3795. var elementTop = this.$element[0].getBoundingClientRect().top;
  3796. var transformOriginY;
  3797. var menuMarginTop;
  3798. if (this.options.position === 'bottom') {
  3799. menuMarginTop = elementHeight;
  3800. transformOriginY = '0px';
  3801. }
  3802. else if (this.options.position === 'top') {
  3803. menuMarginTop = -menuHeight - 1;
  3804. transformOriginY = '100%';
  3805. }
  3806. else {
  3807. // 菜单高度不能超过窗口高度
  3808. var menuMaxHeight = windowHeight - this.options.gutter * 2;
  3809. if (menuHeight > menuMaxHeight) {
  3810. menuHeight = menuMaxHeight;
  3811. }
  3812. // 菜单的 margin-top
  3813. menuMarginTop = -(itemMargin +
  3814. this.selectedIndex * itemHeight +
  3815. (itemHeight - elementHeight) / 2);
  3816. var menuMaxMarginTop = -(itemMargin +
  3817. (this.size - 1) * itemHeight +
  3818. (itemHeight - elementHeight) / 2);
  3819. if (menuMarginTop < menuMaxMarginTop) {
  3820. menuMarginTop = menuMaxMarginTop;
  3821. }
  3822. // 菜单不能超出窗口
  3823. var menuTop = elementTop + menuMarginTop;
  3824. if (menuTop < this.options.gutter) {
  3825. // 不能超出窗口上方
  3826. menuMarginTop = -(elementTop - this.options.gutter);
  3827. }
  3828. else if (menuTop + menuHeight + this.options.gutter > windowHeight) {
  3829. // 不能超出窗口下方
  3830. menuMarginTop = -(elementTop +
  3831. menuHeight +
  3832. this.options.gutter -
  3833. windowHeight);
  3834. }
  3835. // transform 的 Y 轴坐标
  3836. transformOriginY = (this.selectedIndex * itemHeight + itemHeight / 2 + itemMargin) + "px";
  3837. }
  3838. // 设置样式
  3839. this.$element.innerWidth(menuWidth);
  3840. this.$menu
  3841. .innerWidth(menuWidth)
  3842. .height(menuHeight)
  3843. .css({
  3844. 'margin-top': menuMarginTop + 'px',
  3845. 'transform-origin': 'center ' + transformOriginY + ' 0',
  3846. });
  3847. };
  3848. /**
  3849. * select 是否为打开状态
  3850. */
  3851. Select.prototype.isOpen = function isOpen () {
  3852. return this.state === 'opening' || this.state === 'opened';
  3853. };
  3854. /**
  3855. * 对原生 select 组件进行了修改后,需要调用该方法
  3856. */
  3857. Select.prototype.handleUpdate = function handleUpdate () {
  3858. var this$1 = this;
  3859. if (this.isOpen()) {
  3860. this.close();
  3861. }
  3862. this.selectedValue = this.$native.val();
  3863. var itemsData = [];
  3864. this.$items = $();
  3865. // 生成 HTML
  3866. this.$native.find('option').each(function (index, option) {
  3867. var text = option.textContent || '';
  3868. var value = option.value;
  3869. var disabled = option.disabled;
  3870. var selected = this$1.selectedValue === value;
  3871. itemsData.push({
  3872. value: value,
  3873. text: text,
  3874. disabled: disabled,
  3875. selected: selected,
  3876. index: index,
  3877. });
  3878. if (selected) {
  3879. this$1.selectedText = text;
  3880. this$1.selectedIndex = index;
  3881. }
  3882. this$1.$items = this$1.$items.add('<div class="mdui-select-menu-item mdui-ripple"' +
  3883. (disabled ? ' disabled' : '') +
  3884. (selected ? ' selected' : '') +
  3885. ">" + text + "</div>");
  3886. });
  3887. this.$selected = $(("<span class=\"mdui-select-selected\">" + (this.selectedText) + "</span>"));
  3888. this.$element = $("<div class=\"mdui-select mdui-select-position-" + (this.options.position) + "\" " +
  3889. "style=\"" + (this.$native.attr('style')) + "\" " +
  3890. "id=\"" + (this.uniqueID) + "\"></div>")
  3891. .show()
  3892. .append(this.$selected);
  3893. this.$menu = $('<div class="mdui-select-menu"></div>')
  3894. .appendTo(this.$element)
  3895. .append(this.$items);
  3896. $(("#" + (this.uniqueID))).remove();
  3897. this.$native.after(this.$element);
  3898. // 根据 select 的 size 属性设置高度
  3899. this.size = parseInt(this.$native.attr('size') || '0');
  3900. if (this.size <= 0) {
  3901. this.size = this.$items.length;
  3902. if (this.size > 8) {
  3903. this.size = 8;
  3904. }
  3905. }
  3906. // 点击选项时关闭下拉菜单
  3907. // eslint-disable-next-line @typescript-eslint/no-this-alias
  3908. var that = this;
  3909. this.$items.on('click', function () {
  3910. if (that.state === 'closing') {
  3911. return;
  3912. }
  3913. var $item = $(this);
  3914. var index = $item.index();
  3915. var data = itemsData[index];
  3916. if (data.disabled) {
  3917. return;
  3918. }
  3919. that.$selected.text(data.text);
  3920. that.$native.val(data.value);
  3921. that.$items.removeAttr('selected');
  3922. $item.attr('selected', '');
  3923. that.selectedIndex = data.index;
  3924. that.selectedValue = data.value;
  3925. that.selectedText = data.text;
  3926. that.$native.trigger('change');
  3927. that.close();
  3928. });
  3929. // 点击 $element 时打开下拉菜单
  3930. this.$element.on('click', function (event) {
  3931. var $target = $(event.target);
  3932. // 在菜单上点击时不打开
  3933. if ($target.is('.mdui-select-menu') ||
  3934. $target.is('.mdui-select-menu-item')) {
  3935. return;
  3936. }
  3937. this$1.toggle();
  3938. });
  3939. };
  3940. /**
  3941. * 动画结束的回调
  3942. */
  3943. Select.prototype.transitionEnd = function transitionEnd () {
  3944. this.$element.removeClass('mdui-select-closing');
  3945. if (this.state === 'opening') {
  3946. this.state = 'opened';
  3947. this.triggerEvent('opened');
  3948. this.$menu.css('overflow-y', 'auto');
  3949. }
  3950. if (this.state === 'closing') {
  3951. this.state = 'closed';
  3952. this.triggerEvent('closed');
  3953. // 恢复样式
  3954. this.$element.innerWidth('');
  3955. this.$menu.css({
  3956. 'margin-top': '',
  3957. height: '',
  3958. width: '',
  3959. });
  3960. }
  3961. };
  3962. /**
  3963. * 触发组件事件
  3964. * @param name
  3965. */
  3966. Select.prototype.triggerEvent = function triggerEvent (name) {
  3967. componentEvent(name, 'select', this.$native, this);
  3968. };
  3969. /**
  3970. * 切换下拉菜单的打开状态
  3971. */
  3972. Select.prototype.toggle = function toggle () {
  3973. this.isOpen() ? this.close() : this.open();
  3974. };
  3975. /**
  3976. * 打开下拉菜单
  3977. */
  3978. Select.prototype.open = function open () {
  3979. var this$1 = this;
  3980. if (this.isOpen()) {
  3981. return;
  3982. }
  3983. this.state = 'opening';
  3984. this.triggerEvent('open');
  3985. this.readjustMenu();
  3986. this.$element.addClass('mdui-select-open');
  3987. this.$menu.transitionEnd(function () { return this$1.transitionEnd(); });
  3988. };
  3989. /**
  3990. * 关闭下拉菜单
  3991. */
  3992. Select.prototype.close = function close () {
  3993. var this$1 = this;
  3994. if (!this.isOpen()) {
  3995. return;
  3996. }
  3997. this.state = 'closing';
  3998. this.triggerEvent('close');
  3999. this.$menu.css('overflow-y', '');
  4000. this.$element
  4001. .removeClass('mdui-select-open')
  4002. .addClass('mdui-select-closing');
  4003. this.$menu.transitionEnd(function () { return this$1.transitionEnd(); });
  4004. };
  4005. /**
  4006. * 获取当前菜单的状态。共包含四种状态:`opening`、`opened`、`closing`、`closed`
  4007. */
  4008. Select.prototype.getState = function getState () {
  4009. return this.state;
  4010. };
  4011. mdui.Select = Select;
  4012. var customAttr$4 = 'mdui-select';
  4013. $(function () {
  4014. mdui.mutation(("[" + customAttr$4 + "]"), function () {
  4015. new mdui.Select(this, parseOptions(this, customAttr$4));
  4016. });
  4017. });
  4018. $(function () {
  4019. // 滚动时隐藏应用栏
  4020. mdui.mutation('.mdui-appbar-scroll-hide', function () {
  4021. new mdui.Headroom(this);
  4022. });
  4023. // 滚动时只隐藏应用栏中的工具栏
  4024. mdui.mutation('.mdui-appbar-scroll-toolbar-hide', function () {
  4025. new mdui.Headroom(this, {
  4026. pinnedClass: 'mdui-headroom-pinned-toolbar',
  4027. unpinnedClass: 'mdui-headroom-unpinned-toolbar',
  4028. });
  4029. });
  4030. });
  4031. var DEFAULT_OPTIONS$4 = {
  4032. trigger: 'click',
  4033. loop: false,
  4034. };
  4035. var Tab = function Tab(selector, options) {
  4036. var this$1 = this;
  4037. if ( options === void 0 ) options = {};
  4038. /**
  4039. * 配置参数
  4040. */
  4041. this.options = extend({}, DEFAULT_OPTIONS$4);
  4042. /**
  4043. * 当前激活的 tab 的索引号。为 -1 时表示没有激活的选项卡,或不存在选项卡
  4044. */
  4045. this.activeIndex = -1;
  4046. this.$element = $(selector).first();
  4047. extend(this.options, options);
  4048. this.$tabs = this.$element.children('a');
  4049. this.$indicator = $('<div class="mdui-tab-indicator"></div>').appendTo(this.$element);
  4050. // 根据 url hash 获取默认激活的选项卡
  4051. var hash = window.location.hash;
  4052. if (hash) {
  4053. this.$tabs.each(function (index, tab) {
  4054. if ($(tab).attr('href') === hash) {
  4055. this$1.activeIndex = index;
  4056. return false;
  4057. }
  4058. return true;
  4059. });
  4060. }
  4061. // 含 .mdui-tab-active 的元素默认激活
  4062. if (this.activeIndex === -1) {
  4063. this.$tabs.each(function (index, tab) {
  4064. if ($(tab).hasClass('mdui-tab-active')) {
  4065. this$1.activeIndex = index;
  4066. return false;
  4067. }
  4068. return true;
  4069. });
  4070. }
  4071. // 存在选项卡时,默认激活第一个选项卡
  4072. if (this.$tabs.length && this.activeIndex === -1) {
  4073. this.activeIndex = 0;
  4074. }
  4075. // 设置激活状态选项卡
  4076. this.setActive();
  4077. // 监听窗口大小变化事件,调整指示器位置
  4078. $window.on('resize', $.throttle(function () { return this$1.setIndicatorPosition(); }, 100));
  4079. // 监听点击选项卡事件
  4080. this.$tabs.each(function (_, tab) {
  4081. this$1.bindTabEvent(tab);
  4082. });
  4083. };
  4084. /**
  4085. * 指定选项卡是否已禁用
  4086. * @param $tab
  4087. */
  4088. Tab.prototype.isDisabled = function isDisabled ($tab) {
  4089. return $tab.attr('disabled') !== undefined;
  4090. };
  4091. /**
  4092. * 绑定在 Tab 上点击或悬浮的事件
  4093. * @param tab
  4094. */
  4095. Tab.prototype.bindTabEvent = function bindTabEvent (tab) {
  4096. var this$1 = this;
  4097. var $tab = $(tab);
  4098. // 点击或鼠标移入触发的事件
  4099. var clickEvent = function () {
  4100. // 禁用状态的选项卡无法选中
  4101. if (this$1.isDisabled($tab)) {
  4102. return false;
  4103. }
  4104. this$1.activeIndex = this$1.$tabs.index(tab);
  4105. this$1.setActive();
  4106. };
  4107. // 无论 trigger 是 click 还是 hover,都会响应 click 事件
  4108. $tab.on('click', clickEvent);
  4109. // trigger 为 hover 时,额外响应 mouseenter 事件
  4110. if (this.options.trigger === 'hover') {
  4111. $tab.on('mouseenter', clickEvent);
  4112. }
  4113. // 阻止链接的默认点击动作
  4114. $tab.on('click', function () {
  4115. if (($tab.attr('href') || '').indexOf('#') === 0) {
  4116. return false;
  4117. }
  4118. });
  4119. };
  4120. /**
  4121. * 触发组件事件
  4122. * @param name
  4123. * @param $element
  4124. * @param parameters
  4125. */
  4126. Tab.prototype.triggerEvent = function triggerEvent (name, $element, parameters) {
  4127. if ( parameters === void 0 ) parameters = {};
  4128. componentEvent(name, 'tab', $element, this, parameters);
  4129. };
  4130. /**
  4131. * 设置激活状态的选项卡
  4132. */
  4133. Tab.prototype.setActive = function setActive () {
  4134. var this$1 = this;
  4135. this.$tabs.each(function (index, tab) {
  4136. var $tab = $(tab);
  4137. var targetId = $tab.attr('href') || '';
  4138. // 设置选项卡激活状态
  4139. if (index === this$1.activeIndex && !this$1.isDisabled($tab)) {
  4140. if (!$tab.hasClass('mdui-tab-active')) {
  4141. this$1.triggerEvent('change', this$1.$element, {
  4142. index: this$1.activeIndex,
  4143. id: targetId.substr(1),
  4144. });
  4145. this$1.triggerEvent('show', $tab);
  4146. $tab.addClass('mdui-tab-active');
  4147. }
  4148. $(targetId).show();
  4149. this$1.setIndicatorPosition();
  4150. }
  4151. else {
  4152. $tab.removeClass('mdui-tab-active');
  4153. $(targetId).hide();
  4154. }
  4155. });
  4156. };
  4157. /**
  4158. * 设置选项卡指示器的位置
  4159. */
  4160. Tab.prototype.setIndicatorPosition = function setIndicatorPosition () {
  4161. // 选项卡数量为 0 时,不显示指示器
  4162. if (this.activeIndex === -1) {
  4163. this.$indicator.css({
  4164. left: 0,
  4165. width: 0,
  4166. });
  4167. return;
  4168. }
  4169. var $activeTab = this.$tabs.eq(this.activeIndex);
  4170. if (this.isDisabled($activeTab)) {
  4171. return;
  4172. }
  4173. var activeTabOffset = $activeTab.offset();
  4174. this.$indicator.css({
  4175. left: ((activeTabOffset.left +
  4176. this.$element[0].scrollLeft -
  4177. this.$element[0].getBoundingClientRect().left) + "px"),
  4178. width: (($activeTab.innerWidth()) + "px"),
  4179. });
  4180. };
  4181. /**
  4182. * 切换到下一个选项卡
  4183. */
  4184. Tab.prototype.next = function next () {
  4185. if (this.activeIndex === -1) {
  4186. return;
  4187. }
  4188. if (this.$tabs.length > this.activeIndex + 1) {
  4189. this.activeIndex++;
  4190. }
  4191. else if (this.options.loop) {
  4192. this.activeIndex = 0;
  4193. }
  4194. this.setActive();
  4195. };
  4196. /**
  4197. * 切换到上一个选项卡
  4198. */
  4199. Tab.prototype.prev = function prev () {
  4200. if (this.activeIndex === -1) {
  4201. return;
  4202. }
  4203. if (this.activeIndex > 0) {
  4204. this.activeIndex--;
  4205. }
  4206. else if (this.options.loop) {
  4207. this.activeIndex = this.$tabs.length - 1;
  4208. }
  4209. this.setActive();
  4210. };
  4211. /**
  4212. * 显示指定索引号、或指定id的选项卡
  4213. * @param index 索引号、或id
  4214. */
  4215. Tab.prototype.show = function show (index) {
  4216. var this$1 = this;
  4217. if (this.activeIndex === -1) {
  4218. return;
  4219. }
  4220. if (isNumber(index)) {
  4221. this.activeIndex = index;
  4222. }
  4223. else {
  4224. this.$tabs.each(function (i, tab) {
  4225. if (tab.id === index) {
  4226. this$1.activeIndex = i;
  4227. return false;
  4228. }
  4229. });
  4230. }
  4231. this.setActive();
  4232. };
  4233. /**
  4234. * 在父元素的宽度变化时,需要调用该方法重新调整指示器位置
  4235. * 在添加或删除选项卡时,需要调用该方法
  4236. */
  4237. Tab.prototype.handleUpdate = function handleUpdate () {
  4238. var this$1 = this;
  4239. var $oldTabs = this.$tabs; // 旧的 tabs JQ对象
  4240. var $newTabs = this.$element.children('a'); // 新的 tabs JQ对象
  4241. var oldTabsElement = $oldTabs.get(); // 旧的 tabs 元素数组
  4242. var newTabsElement = $newTabs.get(); // 新的 tabs 元素数组
  4243. if (!$newTabs.length) {
  4244. this.activeIndex = -1;
  4245. this.$tabs = $newTabs;
  4246. this.setIndicatorPosition();
  4247. return;
  4248. }
  4249. // 重新遍历选项卡,找出新增的选项卡
  4250. $newTabs.each(function (index, tab) {
  4251. // 有新增的选项卡
  4252. if (oldTabsElement.indexOf(tab) < 0) {
  4253. this$1.bindTabEvent(tab);
  4254. if (this$1.activeIndex === -1) {
  4255. this$1.activeIndex = 0;
  4256. }
  4257. else if (index <= this$1.activeIndex) {
  4258. this$1.activeIndex++;
  4259. }
  4260. }
  4261. });
  4262. // 找出被移除的选项卡
  4263. $oldTabs.each(function (index, tab) {
  4264. // 有被移除的选项卡
  4265. if (newTabsElement.indexOf(tab) < 0) {
  4266. if (index < this$1.activeIndex) {
  4267. this$1.activeIndex--;
  4268. }
  4269. else if (index === this$1.activeIndex) {
  4270. this$1.activeIndex = 0;
  4271. }
  4272. }
  4273. });
  4274. this.$tabs = $newTabs;
  4275. this.setActive();
  4276. };
  4277. mdui.Tab = Tab;
  4278. var customAttr$5 = 'mdui-tab';
  4279. $(function () {
  4280. mdui.mutation(("[" + customAttr$5 + "]"), function () {
  4281. new mdui.Tab(this, parseOptions(this, customAttr$5));
  4282. });
  4283. });
  4284. /**
  4285. * 在桌面设备上默认显示抽屉栏,不显示遮罩层
  4286. * 在手机和平板设备上默认不显示抽屉栏,始终显示遮罩层,且覆盖导航栏
  4287. */
  4288. var DEFAULT_OPTIONS$5 = {
  4289. overlay: false,
  4290. swipe: false,
  4291. };
  4292. var Drawer = function Drawer(selector, options) {
  4293. var this$1 = this;
  4294. if ( options === void 0 ) options = {};
  4295. /**
  4296. * 配置参数
  4297. */
  4298. this.options = extend({}, DEFAULT_OPTIONS$5);
  4299. /**
  4300. * 当前是否显示着遮罩层
  4301. */
  4302. this.overlay = false;
  4303. this.$element = $(selector).first();
  4304. extend(this.options, options);
  4305. this.position = this.$element.hasClass('mdui-drawer-right')
  4306. ? 'right'
  4307. : 'left';
  4308. if (this.$element.hasClass('mdui-drawer-close')) {
  4309. this.state = 'closed';
  4310. }
  4311. else if (this.$element.hasClass('mdui-drawer-open')) {
  4312. this.state = 'opened';
  4313. }
  4314. else if (this.isDesktop()) {
  4315. this.state = 'opened';
  4316. }
  4317. else {
  4318. this.state = 'closed';
  4319. }
  4320. // 浏览器窗口大小调整时
  4321. $window.on('resize', $.throttle(function () {
  4322. if (this$1.isDesktop()) {
  4323. // 由手机平板切换到桌面时
  4324. // 如果显示着遮罩,则隐藏遮罩
  4325. if (this$1.overlay && !this$1.options.overlay) {
  4326. $.hideOverlay();
  4327. this$1.overlay = false;
  4328. $.unlockScreen();
  4329. }
  4330. // 没有强制关闭,则状态为打开状态
  4331. if (!this$1.$element.hasClass('mdui-drawer-close')) {
  4332. this$1.state = 'opened';
  4333. }
  4334. }
  4335. else if (!this$1.overlay && this$1.state === 'opened') {
  4336. // 由桌面切换到手机平板时。如果抽屉栏是打开着的且没有遮罩层,则关闭抽屉栏
  4337. if (this$1.$element.hasClass('mdui-drawer-open')) {
  4338. $.showOverlay();
  4339. this$1.overlay = true;
  4340. $.lockScreen();
  4341. $('.mdui-overlay').one('click', function () { return this$1.close(); });
  4342. }
  4343. else {
  4344. this$1.state = 'closed';
  4345. }
  4346. }
  4347. }, 100));
  4348. // 绑定关闭按钮事件
  4349. this.$element.find('[mdui-drawer-close]').each(function (_, close) {
  4350. $(close).on('click', function () { return this$1.close(); });
  4351. });
  4352. this.swipeSupport();
  4353. };
  4354. /**
  4355. * 是否是桌面设备
  4356. */
  4357. Drawer.prototype.isDesktop = function isDesktop () {
  4358. return $window.width() >= 1024;
  4359. };
  4360. /**
  4361. * 滑动手势支持
  4362. */
  4363. Drawer.prototype.swipeSupport = function swipeSupport () {
  4364. // eslint-disable-next-line @typescript-eslint/no-this-alias
  4365. var that = this;
  4366. // 抽屉栏滑动手势控制
  4367. var openNavEventHandler;
  4368. var touchStartX;
  4369. var touchStartY;
  4370. var swipeStartX;
  4371. var swiping = null;
  4372. var maybeSwiping = false;
  4373. var $body = $('body');
  4374. // 手势触发的范围
  4375. var swipeAreaWidth = 24;
  4376. function setPosition(translateX) {
  4377. var rtlTranslateMultiplier = that.position === 'right' ? -1 : 1;
  4378. var transformCSS = "translate(" + (-1 * rtlTranslateMultiplier * translateX) + "px, 0) !important;";
  4379. var transitionCSS = 'initial !important;';
  4380. that.$element.css('cssText', ("transform: " + transformCSS + "; transition: " + transitionCSS + ";"));
  4381. }
  4382. function cleanPosition() {
  4383. that.$element[0].style.transform = '';
  4384. that.$element[0].style.webkitTransform = '';
  4385. that.$element[0].style.transition = '';
  4386. that.$element[0].style.webkitTransition = '';
  4387. }
  4388. function getMaxTranslateX() {
  4389. return that.$element.width() + 10;
  4390. }
  4391. function getTranslateX(currentX) {
  4392. return Math.min(Math.max(swiping === 'closing'
  4393. ? swipeStartX - currentX
  4394. : getMaxTranslateX() + swipeStartX - currentX, 0), getMaxTranslateX());
  4395. }
  4396. function onBodyTouchEnd(event) {
  4397. if (swiping) {
  4398. var touchX = event.changedTouches[0].pageX;
  4399. if (that.position === 'right') {
  4400. touchX = $body.width() - touchX;
  4401. }
  4402. var translateRatio = getTranslateX(touchX) / getMaxTranslateX();
  4403. maybeSwiping = false;
  4404. var swipingState = swiping;
  4405. swiping = null;
  4406. if (swipingState === 'opening') {
  4407. if (translateRatio < 0.92) {
  4408. cleanPosition();
  4409. that.open();
  4410. }
  4411. else {
  4412. cleanPosition();
  4413. }
  4414. }
  4415. else {
  4416. if (translateRatio > 0.08) {
  4417. cleanPosition();
  4418. that.close();
  4419. }
  4420. else {
  4421. cleanPosition();
  4422. }
  4423. }
  4424. $.unlockScreen();
  4425. }
  4426. else {
  4427. maybeSwiping = false;
  4428. }
  4429. $body.off({
  4430. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  4431. touchmove: onBodyTouchMove,
  4432. touchend: onBodyTouchEnd,
  4433. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  4434. touchcancel: onBodyTouchMove,
  4435. });
  4436. }
  4437. function onBodyTouchMove(event) {
  4438. var touchX = event.touches[0].pageX;
  4439. if (that.position === 'right') {
  4440. touchX = $body.width() - touchX;
  4441. }
  4442. var touchY = event.touches[0].pageY;
  4443. if (swiping) {
  4444. setPosition(getTranslateX(touchX));
  4445. }
  4446. else if (maybeSwiping) {
  4447. var dXAbs = Math.abs(touchX - touchStartX);
  4448. var dYAbs = Math.abs(touchY - touchStartY);
  4449. var threshold = 8;
  4450. if (dXAbs > threshold && dYAbs <= threshold) {
  4451. swipeStartX = touchX;
  4452. swiping = that.state === 'opened' ? 'closing' : 'opening';
  4453. $.lockScreen();
  4454. setPosition(getTranslateX(touchX));
  4455. }
  4456. else if (dXAbs <= threshold && dYAbs > threshold) {
  4457. onBodyTouchEnd();
  4458. }
  4459. }
  4460. }
  4461. function onBodyTouchStart(event) {
  4462. touchStartX = event.touches[0].pageX;
  4463. if (that.position === 'right') {
  4464. touchStartX = $body.width() - touchStartX;
  4465. }
  4466. touchStartY = event.touches[0].pageY;
  4467. if (that.state !== 'opened') {
  4468. if (touchStartX > swipeAreaWidth ||
  4469. openNavEventHandler !== onBodyTouchStart) {
  4470. return;
  4471. }
  4472. }
  4473. maybeSwiping = true;
  4474. $body.on({
  4475. touchmove: onBodyTouchMove,
  4476. touchend: onBodyTouchEnd,
  4477. touchcancel: onBodyTouchMove,
  4478. });
  4479. }
  4480. function enableSwipeHandling() {
  4481. if (!openNavEventHandler) {
  4482. $body.on('touchstart', onBodyTouchStart);
  4483. openNavEventHandler = onBodyTouchStart;
  4484. }
  4485. }
  4486. if (this.options.swipe) {
  4487. enableSwipeHandling();
  4488. }
  4489. };
  4490. /**
  4491. * 触发组件事件
  4492. * @param name
  4493. */
  4494. Drawer.prototype.triggerEvent = function triggerEvent (name) {
  4495. componentEvent(name, 'drawer', this.$element, this);
  4496. };
  4497. /**
  4498. * 动画结束回调
  4499. */
  4500. Drawer.prototype.transitionEnd = function transitionEnd () {
  4501. if (this.$element.hasClass('mdui-drawer-open')) {
  4502. this.state = 'opened';
  4503. this.triggerEvent('opened');
  4504. }
  4505. else {
  4506. this.state = 'closed';
  4507. this.triggerEvent('closed');
  4508. }
  4509. };
  4510. /**
  4511. * 是否处于打开状态
  4512. */
  4513. Drawer.prototype.isOpen = function isOpen () {
  4514. return this.state === 'opening' || this.state === 'opened';
  4515. };
  4516. /**
  4517. * 打开抽屉栏
  4518. */
  4519. Drawer.prototype.open = function open () {
  4520. var this$1 = this;
  4521. if (this.isOpen()) {
  4522. return;
  4523. }
  4524. this.state = 'opening';
  4525. this.triggerEvent('open');
  4526. if (!this.options.overlay) {
  4527. $('body').addClass(("mdui-drawer-body-" + (this.position)));
  4528. }
  4529. this.$element
  4530. .removeClass('mdui-drawer-close')
  4531. .addClass('mdui-drawer-open')
  4532. .transitionEnd(function () { return this$1.transitionEnd(); });
  4533. if (!this.isDesktop() || this.options.overlay) {
  4534. this.overlay = true;
  4535. $.showOverlay().one('click', function () { return this$1.close(); });
  4536. $.lockScreen();
  4537. }
  4538. };
  4539. /**
  4540. * 关闭抽屉栏
  4541. */
  4542. Drawer.prototype.close = function close () {
  4543. var this$1 = this;
  4544. if (!this.isOpen()) {
  4545. return;
  4546. }
  4547. this.state = 'closing';
  4548. this.triggerEvent('close');
  4549. if (!this.options.overlay) {
  4550. $('body').removeClass(("mdui-drawer-body-" + (this.position)));
  4551. }
  4552. this.$element
  4553. .addClass('mdui-drawer-close')
  4554. .removeClass('mdui-drawer-open')
  4555. .transitionEnd(function () { return this$1.transitionEnd(); });
  4556. if (this.overlay) {
  4557. $.hideOverlay();
  4558. this.overlay = false;
  4559. $.unlockScreen();
  4560. }
  4561. };
  4562. /**
  4563. * 切换抽屉栏打开/关闭状态
  4564. */
  4565. Drawer.prototype.toggle = function toggle () {
  4566. this.isOpen() ? this.close() : this.open();
  4567. };
  4568. /**
  4569. * 返回当前抽屉栏的状态。共包含四种状态:`opening`、`opened`、`closing`、`closed`
  4570. */
  4571. Drawer.prototype.getState = function getState () {
  4572. return this.state;
  4573. };
  4574. mdui.Drawer = Drawer;
  4575. var customAttr$6 = 'mdui-drawer';
  4576. $(function () {
  4577. mdui.mutation(("[" + customAttr$6 + "]"), function () {
  4578. var $element = $(this);
  4579. var options = parseOptions(this, customAttr$6);
  4580. var selector = options.target;
  4581. // @ts-ignore
  4582. delete options.target;
  4583. var $drawer = $(selector).first();
  4584. var instance = new mdui.Drawer($drawer, options);
  4585. $element.on('click', function () { return instance.toggle(); });
  4586. });
  4587. });
  4588. var container = {};
  4589. function queue(name, func) {
  4590. if (isUndefined(container[name])) {
  4591. container[name] = [];
  4592. }
  4593. if (isUndefined(func)) {
  4594. return container[name];
  4595. }
  4596. container[name].push(func);
  4597. }
  4598. /**
  4599. * 从队列中移除第一个函数,并执行该函数
  4600. * @param name 队列满
  4601. */
  4602. function dequeue(name) {
  4603. if (isUndefined(container[name])) {
  4604. return;
  4605. }
  4606. if (!container[name].length) {
  4607. return;
  4608. }
  4609. var func = container[name].shift();
  4610. func();
  4611. }
  4612. var DEFAULT_OPTIONS$6 = {
  4613. history: true,
  4614. overlay: true,
  4615. modal: false,
  4616. closeOnEsc: true,
  4617. closeOnCancel: true,
  4618. closeOnConfirm: true,
  4619. destroyOnClosed: false,
  4620. };
  4621. /**
  4622. * 当前显示的对话框实例
  4623. */
  4624. var currentInst = null;
  4625. /**
  4626. * 队列名
  4627. */
  4628. var queueName = '_mdui_dialog';
  4629. /**
  4630. * 窗口是否已锁定
  4631. */
  4632. var isLockScreen = false;
  4633. /**
  4634. * 遮罩层元素
  4635. */
  4636. var $overlay;
  4637. var Dialog = function Dialog(selector, options) {
  4638. var this$1 = this;
  4639. if ( options === void 0 ) options = {};
  4640. /**
  4641. * 配置参数
  4642. */
  4643. this.options = extend({}, DEFAULT_OPTIONS$6);
  4644. /**
  4645. * 当前 dialog 的状态
  4646. */
  4647. this.state = 'closed';
  4648. /**
  4649. * dialog 元素是否是动态添加的
  4650. */
  4651. this.append = false;
  4652. this.$element = $(selector).first();
  4653. // 如果对话框元素没有在当前文档中,则需要添加
  4654. if (!contains(document.body, this.$element[0])) {
  4655. this.append = true;
  4656. $('body').append(this.$element);
  4657. }
  4658. extend(this.options, options);
  4659. // 绑定取消按钮事件
  4660. this.$element.find('[mdui-dialog-cancel]').each(function (_, cancel) {
  4661. $(cancel).on('click', function () {
  4662. this$1.triggerEvent('cancel');
  4663. if (this$1.options.closeOnCancel) {
  4664. this$1.close();
  4665. }
  4666. });
  4667. });
  4668. // 绑定确认按钮事件
  4669. this.$element.find('[mdui-dialog-confirm]').each(function (_, confirm) {
  4670. $(confirm).on('click', function () {
  4671. this$1.triggerEvent('confirm');
  4672. if (this$1.options.closeOnConfirm) {
  4673. this$1.close();
  4674. }
  4675. });
  4676. });
  4677. // 绑定关闭按钮事件
  4678. this.$element.find('[mdui-dialog-close]').each(function (_, close) {
  4679. $(close).on('click', function () { return this$1.close(); });
  4680. });
  4681. };
  4682. /**
  4683. * 触发组件事件
  4684. * @param name
  4685. */
  4686. Dialog.prototype.triggerEvent = function triggerEvent (name) {
  4687. componentEvent(name, 'dialog', this.$element, this);
  4688. };
  4689. /**
  4690. * 窗口宽度变化,或对话框内容变化时,调整对话框位置和对话框内的滚动条
  4691. */
  4692. Dialog.prototype.readjust = function readjust () {
  4693. if (!currentInst) {
  4694. return;
  4695. }
  4696. var $element = currentInst.$element;
  4697. var $title = $element.children('.mdui-dialog-title');
  4698. var $content = $element.children('.mdui-dialog-content');
  4699. var $actions = $element.children('.mdui-dialog-actions');
  4700. // 调整 dialog 的 top 和 height 值
  4701. $element.height('');
  4702. $content.height('');
  4703. var elementHeight = $element.height();
  4704. $element.css({
  4705. top: ((($window.height() - elementHeight) / 2) + "px"),
  4706. height: (elementHeight + "px"),
  4707. });
  4708. // 调整 mdui-dialog-content 的高度
  4709. $content.innerHeight(elementHeight -
  4710. ($title.innerHeight() || 0) -
  4711. ($actions.innerHeight() || 0));
  4712. };
  4713. /**
  4714. * hashchange 事件触发时关闭对话框
  4715. */
  4716. Dialog.prototype.hashchangeEvent = function hashchangeEvent () {
  4717. if (window.location.hash.substring(1).indexOf('mdui-dialog') < 0) {
  4718. currentInst.close(true);
  4719. }
  4720. };
  4721. /**
  4722. * 点击遮罩层关闭对话框
  4723. * @param event
  4724. */
  4725. Dialog.prototype.overlayClick = function overlayClick (event) {
  4726. if ($(event.target).hasClass('mdui-overlay') &&
  4727. currentInst) {
  4728. currentInst.close();
  4729. }
  4730. };
  4731. /**
  4732. * 动画结束回调
  4733. */
  4734. Dialog.prototype.transitionEnd = function transitionEnd () {
  4735. if (this.$element.hasClass('mdui-dialog-open')) {
  4736. this.state = 'opened';
  4737. this.triggerEvent('opened');
  4738. }
  4739. else {
  4740. this.state = 'closed';
  4741. this.triggerEvent('closed');
  4742. this.$element.hide();
  4743. // 所有对话框都关闭,且当前没有打开的对话框时,解锁屏幕
  4744. if (!queue(queueName).length && !currentInst && isLockScreen) {
  4745. $.unlockScreen();
  4746. isLockScreen = false;
  4747. }
  4748. $window.off('resize', $.throttle(this.readjust, 100));
  4749. if (this.options.destroyOnClosed) {
  4750. this.destroy();
  4751. }
  4752. }
  4753. };
  4754. /**
  4755. * 打开指定对话框
  4756. */
  4757. Dialog.prototype.doOpen = function doOpen () {
  4758. var this$1 = this;
  4759. currentInst = this;
  4760. if (!isLockScreen) {
  4761. $.lockScreen();
  4762. isLockScreen = true;
  4763. }
  4764. this.$element.show();
  4765. this.readjust();
  4766. $window.on('resize', $.throttle(this.readjust, 100));
  4767. // 打开消息框
  4768. this.state = 'opening';
  4769. this.triggerEvent('open');
  4770. this.$element
  4771. .addClass('mdui-dialog-open')
  4772. .transitionEnd(function () { return this$1.transitionEnd(); });
  4773. // 不存在遮罩层元素时,添加遮罩层
  4774. if (!$overlay) {
  4775. $overlay = $.showOverlay(5100);
  4776. }
  4777. // 点击遮罩层时是否关闭对话框
  4778. if (this.options.modal) {
  4779. $overlay.off('click', this.overlayClick);
  4780. }
  4781. else {
  4782. $overlay.on('click', this.overlayClick);
  4783. }
  4784. // 是否显示遮罩层,不显示时,把遮罩层背景透明
  4785. $overlay.css('opacity', this.options.overlay ? '' : 0);
  4786. if (this.options.history) {
  4787. // 如果 hash 中原来就有 mdui-dialog,先删除,避免后退历史纪录后仍然有 mdui-dialog 导致无法关闭
  4788. // 包括 mdui-dialog 和 &mdui-dialog 和 ?mdui-dialog
  4789. var hash = window.location.hash.substring(1);
  4790. if (hash.indexOf('mdui-dialog') > -1) {
  4791. hash = hash.replace(/[&?]?mdui-dialog/g, '');
  4792. }
  4793. // 后退按钮关闭对话框
  4794. if (hash) {
  4795. window.location.hash = "" + hash + (hash.indexOf('?') > -1 ? '&' : '?') + "mdui-dialog";
  4796. }
  4797. else {
  4798. window.location.hash = 'mdui-dialog';
  4799. }
  4800. $window.on('hashchange', this.hashchangeEvent);
  4801. }
  4802. };
  4803. /**
  4804. * 当前对话框是否为打开状态
  4805. */
  4806. Dialog.prototype.isOpen = function isOpen () {
  4807. return this.state === 'opening' || this.state === 'opened';
  4808. };
  4809. /**
  4810. * 打开对话框
  4811. */
  4812. Dialog.prototype.open = function open () {
  4813. var this$1 = this;
  4814. if (this.isOpen()) {
  4815. return;
  4816. }
  4817. // 如果当前有正在打开或已经打开的对话框,或队列不为空,则先加入队列,等旧对话框开始关闭时再打开
  4818. if ((currentInst &&
  4819. (currentInst.state === 'opening' || currentInst.state === 'opened')) ||
  4820. queue(queueName).length) {
  4821. queue(queueName, function () { return this$1.doOpen(); });
  4822. return;
  4823. }
  4824. this.doOpen();
  4825. };
  4826. /**
  4827. * 关闭对话框
  4828. */
  4829. Dialog.prototype.close = function close (historyBack) {
  4830. var this$1 = this;
  4831. if ( historyBack === void 0 ) historyBack = false;
  4832. // historyBack 是否需要后退历史纪录,默认为 `false`。该参数仅内部使用
  4833. // 为 `false` 时是通过 js 关闭,需要后退一个历史记录
  4834. // 为 `true` 时是通过后退按钮关闭,不需要后退历史记录
  4835. // setTimeout 的作用是:
  4836. // 当同时关闭一个对话框,并打开另一个对话框时,使打开对话框的操作先执行,以使需要打开的对话框先加入队列
  4837. setTimeout(function () {
  4838. if (!this$1.isOpen()) {
  4839. return;
  4840. }
  4841. currentInst = null;
  4842. this$1.state = 'closing';
  4843. this$1.triggerEvent('close');
  4844. // 所有对话框都关闭,且当前没有打开的对话框时,隐藏遮罩
  4845. if (!queue(queueName).length && $overlay) {
  4846. $.hideOverlay();
  4847. $overlay = null;
  4848. // 若仍存在遮罩,恢复遮罩的 z-index
  4849. $('.mdui-overlay').css('z-index', 2000);
  4850. }
  4851. this$1.$element
  4852. .removeClass('mdui-dialog-open')
  4853. .transitionEnd(function () { return this$1.transitionEnd(); });
  4854. if (this$1.options.history && !queue(queueName).length) {
  4855. if (!historyBack) {
  4856. window.history.back();
  4857. }
  4858. $window.off('hashchange', this$1.hashchangeEvent);
  4859. }
  4860. // 关闭旧对话框,打开新对话框。
  4861. // 加一点延迟,仅仅为了视觉效果更好。不加延时也不影响功能
  4862. setTimeout(function () {
  4863. dequeue(queueName);
  4864. }, 100);
  4865. });
  4866. };
  4867. /**
  4868. * 切换对话框打开/关闭状态
  4869. */
  4870. Dialog.prototype.toggle = function toggle () {
  4871. this.isOpen() ? this.close() : this.open();
  4872. };
  4873. /**
  4874. * 获取对话框状态。共包含四种状态:`opening`、`opened`、`closing`、`closed`
  4875. */
  4876. Dialog.prototype.getState = function getState () {
  4877. return this.state;
  4878. };
  4879. /**
  4880. * 销毁对话框
  4881. */
  4882. Dialog.prototype.destroy = function destroy () {
  4883. if (this.append) {
  4884. this.$element.remove();
  4885. }
  4886. if (!queue(queueName).length && !currentInst) {
  4887. if ($overlay) {
  4888. $.hideOverlay();
  4889. $overlay = null;
  4890. }
  4891. if (isLockScreen) {
  4892. $.unlockScreen();
  4893. isLockScreen = false;
  4894. }
  4895. }
  4896. };
  4897. /**
  4898. * 对话框内容变化时,需要调用该方法来调整对话框位置和滚动条高度
  4899. */
  4900. Dialog.prototype.handleUpdate = function handleUpdate () {
  4901. this.readjust();
  4902. };
  4903. // esc 按下时关闭对话框
  4904. $document.on('keydown', function (event) {
  4905. if (currentInst &&
  4906. currentInst.options.closeOnEsc &&
  4907. currentInst.state === 'opened' &&
  4908. event.keyCode === 27) {
  4909. currentInst.close();
  4910. }
  4911. });
  4912. mdui.Dialog = Dialog;
  4913. var customAttr$7 = 'mdui-dialog';
  4914. var dataName$1 = '_mdui_dialog';
  4915. $(function () {
  4916. $document.on('click', ("[" + customAttr$7 + "]"), function () {
  4917. var options = parseOptions(this, customAttr$7);
  4918. var selector = options.target;
  4919. // @ts-ignore
  4920. delete options.target;
  4921. var $dialog = $(selector).first();
  4922. var instance = $dialog.data(dataName$1);
  4923. if (!instance) {
  4924. instance = new mdui.Dialog($dialog, options);
  4925. $dialog.data(dataName$1, instance);
  4926. }
  4927. instance.open();
  4928. });
  4929. });
  4930. var DEFAULT_BUTTON = {
  4931. text: '',
  4932. bold: false,
  4933. close: true,
  4934. // eslint-disable-next-line @typescript-eslint/no-empty-function
  4935. onClick: function () { },
  4936. };
  4937. var DEFAULT_OPTIONS$7 = {
  4938. title: '',
  4939. content: '',
  4940. buttons: [],
  4941. stackedButtons: false,
  4942. cssClass: '',
  4943. history: true,
  4944. overlay: true,
  4945. modal: false,
  4946. closeOnEsc: true,
  4947. destroyOnClosed: true,
  4948. // eslint-disable-next-line @typescript-eslint/no-empty-function
  4949. onOpen: function () { },
  4950. // eslint-disable-next-line @typescript-eslint/no-empty-function
  4951. onOpened: function () { },
  4952. // eslint-disable-next-line @typescript-eslint/no-empty-function
  4953. onClose: function () { },
  4954. // eslint-disable-next-line @typescript-eslint/no-empty-function
  4955. onClosed: function () { },
  4956. };
  4957. mdui.dialog = function (options) {
  4958. var _a, _b;
  4959. // 合并配置参数
  4960. options = extend({}, DEFAULT_OPTIONS$7, options);
  4961. each(options.buttons, function (i, button) {
  4962. options.buttons[i] = extend({}, DEFAULT_BUTTON, button);
  4963. });
  4964. // 按钮的 HTML
  4965. var buttonsHTML = '';
  4966. if ((_a = options.buttons) === null || _a === void 0 ? void 0 : _a.length) {
  4967. buttonsHTML = "<div class=\"mdui-dialog-actions" + (options.stackedButtons ? ' mdui-dialog-actions-stacked' : '') + "\">";
  4968. each(options.buttons, function (_, button) {
  4969. buttonsHTML +=
  4970. '<a href="javascript:void(0)" ' +
  4971. "class=\"mdui-btn mdui-ripple mdui-text-color-primary " + (button.bold ? 'mdui-btn-bold' : '') + "\">" + (button.text) + "</a>";
  4972. });
  4973. buttonsHTML += '</div>';
  4974. }
  4975. // Dialog 的 HTML
  4976. var HTML = "<div class=\"mdui-dialog " + (options.cssClass) + "\">" +
  4977. (options.title
  4978. ? ("<div class=\"mdui-dialog-title\">" + (options.title) + "</div>")
  4979. : '') +
  4980. (options.content
  4981. ? ("<div class=\"mdui-dialog-content\">" + (options.content) + "</div>")
  4982. : '') +
  4983. buttonsHTML +
  4984. '</div>';
  4985. // 实例化 Dialog
  4986. var instance = new mdui.Dialog(HTML, {
  4987. history: options.history,
  4988. overlay: options.overlay,
  4989. modal: options.modal,
  4990. closeOnEsc: options.closeOnEsc,
  4991. destroyOnClosed: options.destroyOnClosed,
  4992. });
  4993. // 绑定按钮事件
  4994. if ((_b = options.buttons) === null || _b === void 0 ? void 0 : _b.length) {
  4995. instance.$element
  4996. .find('.mdui-dialog-actions .mdui-btn')
  4997. .each(function (index, button) {
  4998. $(button).on('click', function () {
  4999. options.buttons[index].onClick(instance);
  5000. if (options.buttons[index].close) {
  5001. instance.close();
  5002. }
  5003. });
  5004. });
  5005. }
  5006. // 绑定打开关闭事件
  5007. instance.$element
  5008. .on('open.mdui.dialog', function () {
  5009. options.onOpen(instance);
  5010. })
  5011. .on('opened.mdui.dialog', function () {
  5012. options.onOpened(instance);
  5013. })
  5014. .on('close.mdui.dialog', function () {
  5015. options.onClose(instance);
  5016. })
  5017. .on('closed.mdui.dialog', function () {
  5018. options.onClosed(instance);
  5019. });
  5020. instance.open();
  5021. return instance;
  5022. };
  5023. var DEFAULT_OPTIONS$8 = {
  5024. confirmText: 'ok',
  5025. history: true,
  5026. modal: false,
  5027. closeOnEsc: true,
  5028. closeOnConfirm: true,
  5029. };
  5030. mdui.alert = function (text, title, onConfirm, options) {
  5031. if (isFunction(title)) {
  5032. options = onConfirm;
  5033. onConfirm = title;
  5034. title = '';
  5035. }
  5036. if (isUndefined(onConfirm)) {
  5037. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5038. onConfirm = function () { };
  5039. }
  5040. if (isUndefined(options)) {
  5041. options = {};
  5042. }
  5043. options = extend({}, DEFAULT_OPTIONS$8, options);
  5044. return mdui.dialog({
  5045. title: title,
  5046. content: text,
  5047. buttons: [
  5048. {
  5049. text: options.confirmText,
  5050. bold: false,
  5051. close: options.closeOnConfirm,
  5052. onClick: onConfirm,
  5053. } ],
  5054. cssClass: 'mdui-dialog-alert',
  5055. history: options.history,
  5056. modal: options.modal,
  5057. closeOnEsc: options.closeOnEsc,
  5058. });
  5059. };
  5060. var DEFAULT_OPTIONS$9 = {
  5061. confirmText: 'ok',
  5062. cancelText: 'cancel',
  5063. history: true,
  5064. modal: false,
  5065. closeOnEsc: true,
  5066. closeOnCancel: true,
  5067. closeOnConfirm: true,
  5068. };
  5069. mdui.confirm = function (text, title, onConfirm, onCancel, options) {
  5070. if (isFunction(title)) {
  5071. options = onCancel;
  5072. onCancel = onConfirm;
  5073. onConfirm = title;
  5074. title = '';
  5075. }
  5076. if (isUndefined(onConfirm)) {
  5077. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5078. onConfirm = function () { };
  5079. }
  5080. if (isUndefined(onCancel)) {
  5081. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5082. onCancel = function () { };
  5083. }
  5084. if (isUndefined(options)) {
  5085. options = {};
  5086. }
  5087. options = extend({}, DEFAULT_OPTIONS$9, options);
  5088. return mdui.dialog({
  5089. title: title,
  5090. content: text,
  5091. buttons: [
  5092. {
  5093. text: options.cancelText,
  5094. bold: false,
  5095. close: options.closeOnCancel,
  5096. onClick: onCancel,
  5097. },
  5098. {
  5099. text: options.confirmText,
  5100. bold: false,
  5101. close: options.closeOnConfirm,
  5102. onClick: onConfirm,
  5103. } ],
  5104. cssClass: 'mdui-dialog-confirm',
  5105. history: options.history,
  5106. modal: options.modal,
  5107. closeOnEsc: options.closeOnEsc,
  5108. });
  5109. };
  5110. var DEFAULT_OPTIONS$a = {
  5111. confirmText: 'ok',
  5112. cancelText: 'cancel',
  5113. history: true,
  5114. modal: false,
  5115. closeOnEsc: true,
  5116. closeOnCancel: true,
  5117. closeOnConfirm: true,
  5118. type: 'text',
  5119. maxlength: 0,
  5120. defaultValue: '',
  5121. confirmOnEnter: false,
  5122. };
  5123. mdui.prompt = function (label, title, onConfirm, onCancel, options) {
  5124. if (isFunction(title)) {
  5125. options = onCancel;
  5126. onCancel = onConfirm;
  5127. onConfirm = title;
  5128. title = '';
  5129. }
  5130. if (isUndefined(onConfirm)) {
  5131. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5132. onConfirm = function () { };
  5133. }
  5134. if (isUndefined(onCancel)) {
  5135. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5136. onCancel = function () { };
  5137. }
  5138. if (isUndefined(options)) {
  5139. options = {};
  5140. }
  5141. options = extend({}, DEFAULT_OPTIONS$a, options);
  5142. var content = '<div class="mdui-textfield">' +
  5143. (label ? ("<label class=\"mdui-textfield-label\">" + label + "</label>") : '') +
  5144. (options.type === 'text'
  5145. ? ("<input class=\"mdui-textfield-input\" type=\"text\" value=\"" + (options.defaultValue) + "\" " + (options.maxlength ? 'maxlength="' + options.maxlength + '"' : '') + "/>")
  5146. : '') +
  5147. (options.type === 'textarea'
  5148. ? ("<textarea class=\"mdui-textfield-input\" " + (options.maxlength ? 'maxlength="' + options.maxlength + '"' : '') + ">" + (options.defaultValue) + "</textarea>")
  5149. : '') +
  5150. '</div>';
  5151. var onCancelClick = function (dialog) {
  5152. var value = dialog.$element.find('.mdui-textfield-input').val();
  5153. onCancel(value, dialog);
  5154. };
  5155. var onConfirmClick = function (dialog) {
  5156. var value = dialog.$element.find('.mdui-textfield-input').val();
  5157. onConfirm(value, dialog);
  5158. };
  5159. return mdui.dialog({
  5160. title: title,
  5161. content: content,
  5162. buttons: [
  5163. {
  5164. text: options.cancelText,
  5165. bold: false,
  5166. close: options.closeOnCancel,
  5167. onClick: onCancelClick,
  5168. },
  5169. {
  5170. text: options.confirmText,
  5171. bold: false,
  5172. close: options.closeOnConfirm,
  5173. onClick: onConfirmClick,
  5174. } ],
  5175. cssClass: 'mdui-dialog-prompt',
  5176. history: options.history,
  5177. modal: options.modal,
  5178. closeOnEsc: options.closeOnEsc,
  5179. onOpen: function (dialog) {
  5180. // 初始化输入框
  5181. var $input = dialog.$element.find('.mdui-textfield-input');
  5182. mdui.updateTextFields($input);
  5183. // 聚焦到输入框
  5184. $input[0].focus();
  5185. // 捕捉文本框回车键,在单行文本框的情况下触发回调
  5186. if (options.type !== 'textarea' && options.confirmOnEnter === true) {
  5187. $input.on('keydown', function (event) {
  5188. if (event.keyCode === 13) {
  5189. var value = dialog.$element.find('.mdui-textfield-input').val();
  5190. onConfirm(value, dialog);
  5191. if (options.closeOnConfirm) {
  5192. dialog.close();
  5193. }
  5194. return false;
  5195. }
  5196. return;
  5197. });
  5198. }
  5199. // 如果是多行输入框,监听输入框的 input 事件,更新对话框高度
  5200. if (options.type === 'textarea') {
  5201. $input.on('input', function () { return dialog.handleUpdate(); });
  5202. }
  5203. // 有字符数限制时,加载完文本框后 DOM 会变化,需要更新对话框高度
  5204. if (options.maxlength) {
  5205. dialog.handleUpdate();
  5206. }
  5207. },
  5208. });
  5209. };
  5210. var DEFAULT_OPTIONS$b = {
  5211. position: 'auto',
  5212. delay: 0,
  5213. content: '',
  5214. };
  5215. var Tooltip = function Tooltip(selector, options) {
  5216. if ( options === void 0 ) options = {};
  5217. /**
  5218. * 配置参数
  5219. */
  5220. this.options = extend({}, DEFAULT_OPTIONS$b);
  5221. /**
  5222. * 当前 tooltip 的状态
  5223. */
  5224. this.state = 'closed';
  5225. /**
  5226. * setTimeout 的返回值
  5227. */
  5228. this.timeoutId = null;
  5229. this.$target = $(selector).first();
  5230. extend(this.options, options);
  5231. // 创建 Tooltip HTML
  5232. this.$element = $(("<div class=\"mdui-tooltip\" id=\"" + ($.guid()) + "\">" + (this.options.content) + "</div>")).appendTo(document.body);
  5233. // 绑定事件。元素处于 disabled 状态时无法触发鼠标事件,为了统一,把 touch 事件也禁用
  5234. // eslint-disable-next-line @typescript-eslint/no-this-alias
  5235. var that = this;
  5236. this.$target
  5237. .on('touchstart mouseenter', function (event) {
  5238. if (that.isDisabled(this)) {
  5239. return;
  5240. }
  5241. if (!isAllow(event)) {
  5242. return;
  5243. }
  5244. register(event);
  5245. that.open();
  5246. })
  5247. .on('touchend mouseleave', function (event) {
  5248. if (that.isDisabled(this)) {
  5249. return;
  5250. }
  5251. if (!isAllow(event)) {
  5252. return;
  5253. }
  5254. that.close();
  5255. })
  5256. .on(unlockEvent, function (event) {
  5257. if (that.isDisabled(this)) {
  5258. return;
  5259. }
  5260. register(event);
  5261. });
  5262. };
  5263. /**
  5264. * 元素是否已禁用
  5265. * @param element
  5266. */
  5267. Tooltip.prototype.isDisabled = function isDisabled (element) {
  5268. return (element.disabled ||
  5269. $(element).attr('disabled') !== undefined);
  5270. };
  5271. /**
  5272. * 是否是桌面设备
  5273. */
  5274. Tooltip.prototype.isDesktop = function isDesktop () {
  5275. return $window.width() > 1024;
  5276. };
  5277. /**
  5278. * 设置 Tooltip 的位置
  5279. */
  5280. Tooltip.prototype.setPosition = function setPosition () {
  5281. var marginLeft;
  5282. var marginTop;
  5283. // 触发的元素
  5284. var targetProps = this.$target[0].getBoundingClientRect();
  5285. // 触发的元素和 Tooltip 之间的距离
  5286. var targetMargin = this.isDesktop() ? 14 : 24;
  5287. // Tooltip 的宽度和高度
  5288. var tooltipWidth = this.$element[0].offsetWidth;
  5289. var tooltipHeight = this.$element[0].offsetHeight;
  5290. // Tooltip 的方向
  5291. var position = this.options.position;
  5292. // 自动判断位置,加 2px,使 Tooltip 距离窗口边框至少有 2px 的间距
  5293. if (position === 'auto') {
  5294. if (targetProps.top +
  5295. targetProps.height +
  5296. targetMargin +
  5297. tooltipHeight +
  5298. 2 <
  5299. $window.height()) {
  5300. position = 'bottom';
  5301. }
  5302. else if (targetMargin + tooltipHeight + 2 < targetProps.top) {
  5303. position = 'top';
  5304. }
  5305. else if (targetMargin + tooltipWidth + 2 < targetProps.left) {
  5306. position = 'left';
  5307. }
  5308. else if (targetProps.width + targetMargin + tooltipWidth + 2 <
  5309. $window.width() - targetProps.left) {
  5310. position = 'right';
  5311. }
  5312. else {
  5313. position = 'bottom';
  5314. }
  5315. }
  5316. // 设置位置
  5317. switch (position) {
  5318. case 'bottom':
  5319. marginLeft = -1 * (tooltipWidth / 2);
  5320. marginTop = targetProps.height / 2 + targetMargin;
  5321. this.$element.transformOrigin('top center');
  5322. break;
  5323. case 'top':
  5324. marginLeft = -1 * (tooltipWidth / 2);
  5325. marginTop =
  5326. -1 * (tooltipHeight + targetProps.height / 2 + targetMargin);
  5327. this.$element.transformOrigin('bottom center');
  5328. break;
  5329. case 'left':
  5330. marginLeft = -1 * (tooltipWidth + targetProps.width / 2 + targetMargin);
  5331. marginTop = -1 * (tooltipHeight / 2);
  5332. this.$element.transformOrigin('center right');
  5333. break;
  5334. case 'right':
  5335. marginLeft = targetProps.width / 2 + targetMargin;
  5336. marginTop = -1 * (tooltipHeight / 2);
  5337. this.$element.transformOrigin('center left');
  5338. break;
  5339. }
  5340. var targetOffset = this.$target.offset();
  5341. this.$element.css({
  5342. top: ((targetOffset.top + targetProps.height / 2) + "px"),
  5343. left: ((targetOffset.left + targetProps.width / 2) + "px"),
  5344. 'margin-left': (marginLeft + "px"),
  5345. 'margin-top': (marginTop + "px"),
  5346. });
  5347. };
  5348. /**
  5349. * 触发组件事件
  5350. * @param name
  5351. */
  5352. Tooltip.prototype.triggerEvent = function triggerEvent (name) {
  5353. componentEvent(name, 'tooltip', this.$target, this);
  5354. };
  5355. /**
  5356. * 动画结束回调
  5357. */
  5358. Tooltip.prototype.transitionEnd = function transitionEnd () {
  5359. if (this.$element.hasClass('mdui-tooltip-open')) {
  5360. this.state = 'opened';
  5361. this.triggerEvent('opened');
  5362. }
  5363. else {
  5364. this.state = 'closed';
  5365. this.triggerEvent('closed');
  5366. }
  5367. };
  5368. /**
  5369. * 当前 tooltip 是否为打开状态
  5370. */
  5371. Tooltip.prototype.isOpen = function isOpen () {
  5372. return this.state === 'opening' || this.state === 'opened';
  5373. };
  5374. /**
  5375. * 执行打开 tooltip
  5376. */
  5377. Tooltip.prototype.doOpen = function doOpen () {
  5378. var this$1 = this;
  5379. this.state = 'opening';
  5380. this.triggerEvent('open');
  5381. this.$element
  5382. .addClass('mdui-tooltip-open')
  5383. .transitionEnd(function () { return this$1.transitionEnd(); });
  5384. };
  5385. /**
  5386. * 打开 Tooltip
  5387. * @param options 允许每次打开时设置不同的参数
  5388. */
  5389. Tooltip.prototype.open = function open (options) {
  5390. var this$1 = this;
  5391. if (this.isOpen()) {
  5392. return;
  5393. }
  5394. var oldOptions = extend({}, this.options);
  5395. if (options) {
  5396. extend(this.options, options);
  5397. }
  5398. // tooltip 的内容有更新
  5399. if (oldOptions.content !== this.options.content) {
  5400. this.$element.html(this.options.content);
  5401. }
  5402. this.setPosition();
  5403. if (this.options.delay) {
  5404. this.timeoutId = setTimeout(function () { return this$1.doOpen(); }, this.options.delay);
  5405. }
  5406. else {
  5407. this.timeoutId = null;
  5408. this.doOpen();
  5409. }
  5410. };
  5411. /**
  5412. * 关闭 Tooltip
  5413. */
  5414. Tooltip.prototype.close = function close () {
  5415. var this$1 = this;
  5416. if (this.timeoutId) {
  5417. clearTimeout(this.timeoutId);
  5418. this.timeoutId = null;
  5419. }
  5420. if (!this.isOpen()) {
  5421. return;
  5422. }
  5423. this.state = 'closing';
  5424. this.triggerEvent('close');
  5425. this.$element
  5426. .removeClass('mdui-tooltip-open')
  5427. .transitionEnd(function () { return this$1.transitionEnd(); });
  5428. };
  5429. /**
  5430. * 切换 Tooltip 的打开状态
  5431. */
  5432. Tooltip.prototype.toggle = function toggle () {
  5433. this.isOpen() ? this.close() : this.open();
  5434. };
  5435. /**
  5436. * 获取 Tooltip 状态。共包含四种状态:`opening`、`opened`、`closing`、`closed`
  5437. */
  5438. Tooltip.prototype.getState = function getState () {
  5439. return this.state;
  5440. };
  5441. mdui.Tooltip = Tooltip;
  5442. var customAttr$8 = 'mdui-tooltip';
  5443. var dataName$2 = '_mdui_tooltip';
  5444. $(function () {
  5445. // mouseenter 不能冒泡,所以这里用 mouseover 代替
  5446. $document.on('touchstart mouseover', ("[" + customAttr$8 + "]"), function () {
  5447. var $target = $(this);
  5448. var instance = $target.data(dataName$2);
  5449. if (!instance) {
  5450. instance = new mdui.Tooltip(this, parseOptions(this, customAttr$8));
  5451. $target.data(dataName$2, instance);
  5452. }
  5453. });
  5454. });
  5455. var DEFAULT_OPTIONS$c = {
  5456. message: '',
  5457. timeout: 4000,
  5458. position: 'bottom',
  5459. buttonText: '',
  5460. buttonColor: '',
  5461. closeOnButtonClick: true,
  5462. closeOnOutsideClick: true,
  5463. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5464. onClick: function () { },
  5465. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5466. onButtonClick: function () { },
  5467. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5468. onOpen: function () { },
  5469. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5470. onOpened: function () { },
  5471. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5472. onClose: function () { },
  5473. // eslint-disable-next-line @typescript-eslint/no-empty-function
  5474. onClosed: function () { },
  5475. };
  5476. /**
  5477. * 当前打开着的 Snackbar
  5478. */
  5479. var currentInst$1 = null;
  5480. /**
  5481. * 队列名
  5482. */
  5483. var queueName$1 = '_mdui_snackbar';
  5484. var Snackbar = function Snackbar(options) {
  5485. /**
  5486. * 配置参数
  5487. */
  5488. this.options = extend({}, DEFAULT_OPTIONS$c);
  5489. /**
  5490. * 当前 Snackbar 的状态
  5491. */
  5492. this.state = 'closed';
  5493. /**
  5494. * setTimeout 的 ID
  5495. */
  5496. this.timeoutId = null;
  5497. extend(this.options, options);
  5498. // 按钮颜色
  5499. var buttonColorStyle = '';
  5500. var buttonColorClass = '';
  5501. if (this.options.buttonColor.indexOf('#') === 0 ||
  5502. this.options.buttonColor.indexOf('rgb') === 0) {
  5503. buttonColorStyle = "style=\"color:" + (this.options.buttonColor) + "\"";
  5504. }
  5505. else if (this.options.buttonColor !== '') {
  5506. buttonColorClass = "mdui-text-color-" + (this.options.buttonColor);
  5507. }
  5508. // 添加 HTML
  5509. this.$element = $('<div class="mdui-snackbar">' +
  5510. "<div class=\"mdui-snackbar-text\">" + (this.options.message) + "</div>" +
  5511. (this.options.buttonText
  5512. ? ("<a href=\"javascript:void(0)\" class=\"mdui-snackbar-action mdui-btn mdui-ripple mdui-ripple-white " + buttonColorClass + "\" " + buttonColorStyle + ">" + (this.options.buttonText) + "</a>")
  5513. : '') +
  5514. '</div>').appendTo(document.body);
  5515. // 设置位置
  5516. this.setPosition('close');
  5517. this.$element.reflow().addClass(("mdui-snackbar-" + (this.options.position)));
  5518. };
  5519. /**
  5520. * 点击 Snackbar 外面的区域关闭
  5521. * @param event
  5522. */
  5523. Snackbar.prototype.closeOnOutsideClick = function closeOnOutsideClick (event) {
  5524. var $target = $(event.target);
  5525. if (!$target.hasClass('mdui-snackbar') &&
  5526. !$target.parents('.mdui-snackbar').length) {
  5527. currentInst$1.close();
  5528. }
  5529. };
  5530. /**
  5531. * 设置 Snackbar 的位置
  5532. * @param state
  5533. */
  5534. Snackbar.prototype.setPosition = function setPosition (state) {
  5535. var snackbarHeight = this.$element[0].clientHeight;
  5536. var position = this.options.position;
  5537. var translateX;
  5538. var translateY;
  5539. // translateX
  5540. if (position === 'bottom' || position === 'top') {
  5541. translateX = '-50%';
  5542. }
  5543. else {
  5544. translateX = '0';
  5545. }
  5546. // translateY
  5547. if (state === 'open') {
  5548. translateY = '0';
  5549. }
  5550. else {
  5551. if (position === 'bottom') {
  5552. translateY = snackbarHeight;
  5553. }
  5554. if (position === 'top') {
  5555. translateY = -snackbarHeight;
  5556. }
  5557. if (position === 'left-top' || position === 'right-top') {
  5558. translateY = -snackbarHeight - 24;
  5559. }
  5560. if (position === 'left-bottom' || position === 'right-bottom') {
  5561. translateY = snackbarHeight + 24;
  5562. }
  5563. }
  5564. this.$element.transform(("translate(" + translateX + "," + translateY + "px"));
  5565. };
  5566. /**
  5567. * 打开 Snackbar
  5568. */
  5569. Snackbar.prototype.open = function open () {
  5570. var this$1 = this;
  5571. if (this.state === 'opening' || this.state === 'opened') {
  5572. return;
  5573. }
  5574. // 如果当前有正在显示的 Snackbar,则先加入队列,等旧 Snackbar 关闭后再打开
  5575. if (currentInst$1) {
  5576. queue(queueName$1, function () { return this$1.open(); });
  5577. return;
  5578. }
  5579. currentInst$1 = this;
  5580. // 开始打开
  5581. this.state = 'opening';
  5582. this.options.onOpen(this);
  5583. this.setPosition('open');
  5584. this.$element.transitionEnd(function () {
  5585. if (this$1.state !== 'opening') {
  5586. return;
  5587. }
  5588. this$1.state = 'opened';
  5589. this$1.options.onOpened(this$1);
  5590. // 有按钮时绑定事件
  5591. if (this$1.options.buttonText) {
  5592. this$1.$element.find('.mdui-snackbar-action').on('click', function () {
  5593. this$1.options.onButtonClick(this$1);
  5594. if (this$1.options.closeOnButtonClick) {
  5595. this$1.close();
  5596. }
  5597. });
  5598. }
  5599. // 点击 snackbar 的事件
  5600. this$1.$element.on('click', function (event) {
  5601. if (!$(event.target).hasClass('mdui-snackbar-action')) {
  5602. this$1.options.onClick(this$1);
  5603. }
  5604. });
  5605. // 点击 Snackbar 外面的区域关闭
  5606. if (this$1.options.closeOnOutsideClick) {
  5607. $document.on(startEvent, this$1.closeOnOutsideClick);
  5608. }
  5609. // 超时后自动关闭
  5610. if (this$1.options.timeout) {
  5611. this$1.timeoutId = setTimeout(function () { return this$1.close(); }, this$1.options.timeout);
  5612. }
  5613. });
  5614. };
  5615. /**
  5616. * 关闭 Snackbar
  5617. */
  5618. Snackbar.prototype.close = function close () {
  5619. var this$1 = this;
  5620. if (this.state === 'closing' || this.state === 'closed') {
  5621. return;
  5622. }
  5623. if (this.timeoutId) {
  5624. clearTimeout(this.timeoutId);
  5625. }
  5626. if (this.options.closeOnOutsideClick) {
  5627. $document.off(startEvent, this.closeOnOutsideClick);
  5628. }
  5629. this.state = 'closing';
  5630. this.options.onClose(this);
  5631. this.setPosition('close');
  5632. this.$element.transitionEnd(function () {
  5633. if (this$1.state !== 'closing') {
  5634. return;
  5635. }
  5636. currentInst$1 = null;
  5637. this$1.state = 'closed';
  5638. this$1.options.onClosed(this$1);
  5639. this$1.$element.remove();
  5640. dequeue(queueName$1);
  5641. });
  5642. };
  5643. mdui.snackbar = function (message, options) {
  5644. if ( options === void 0 ) options = {};
  5645. if (isString(message)) {
  5646. options.message = message;
  5647. }
  5648. else {
  5649. options = message;
  5650. }
  5651. var instance = new Snackbar(options);
  5652. instance.open();
  5653. return instance;
  5654. };
  5655. $(function () {
  5656. // 切换导航项
  5657. $document.on('click', '.mdui-bottom-nav>a', function () {
  5658. var $item = $(this);
  5659. var $bottomNav = $item.parent();
  5660. $bottomNav.children('a').each(function (index, item) {
  5661. var isThis = $item.is(item);
  5662. if (isThis) {
  5663. componentEvent('change', 'bottomNav', $bottomNav[0], undefined, {
  5664. index: index,
  5665. });
  5666. }
  5667. isThis
  5668. ? $(item).addClass('mdui-bottom-nav-active')
  5669. : $(item).removeClass('mdui-bottom-nav-active');
  5670. });
  5671. });
  5672. // 滚动时隐藏 mdui-bottom-nav-scroll-hide
  5673. mdui.mutation('.mdui-bottom-nav-scroll-hide', function () {
  5674. new mdui.Headroom(this, {
  5675. pinnedClass: 'mdui-headroom-pinned-down',
  5676. unpinnedClass: 'mdui-headroom-unpinned-down',
  5677. });
  5678. });
  5679. });
  5680. /**
  5681. * layer 的 HTML 结构
  5682. * @param index
  5683. */
  5684. function layerHTML(index) {
  5685. if ( index === void 0 ) index = false;
  5686. return ("<div class=\"mdui-spinner-layer " + (index ? ("mdui-spinner-layer-" + index) : '') + "\">" +
  5687. '<div class="mdui-spinner-circle-clipper mdui-spinner-left">' +
  5688. '<div class="mdui-spinner-circle"></div>' +
  5689. '</div>' +
  5690. '<div class="mdui-spinner-gap-patch">' +
  5691. '<div class="mdui-spinner-circle"></div>' +
  5692. '</div>' +
  5693. '<div class="mdui-spinner-circle-clipper mdui-spinner-right">' +
  5694. '<div class="mdui-spinner-circle"></div>' +
  5695. '</div>' +
  5696. '</div>');
  5697. }
  5698. /**
  5699. * 填充 HTML
  5700. * @param spinner
  5701. */
  5702. function fillHTML(spinner) {
  5703. var $spinner = $(spinner);
  5704. var layer = $spinner.hasClass('mdui-spinner-colorful')
  5705. ? layerHTML(1) + layerHTML(2) + layerHTML(3) + layerHTML(4)
  5706. : layerHTML();
  5707. $spinner.html(layer);
  5708. }
  5709. $(function () {
  5710. // 页面加载完后自动填充 HTML 结构
  5711. mdui.mutation('.mdui-spinner', function () {
  5712. fillHTML(this);
  5713. });
  5714. });
  5715. mdui.updateSpinners = function (selector) {
  5716. var $elements = isUndefined(selector) ? $('.mdui-spinner') : $(selector);
  5717. $elements.each(function () {
  5718. fillHTML(this);
  5719. });
  5720. };
  5721. var DEFAULT_OPTIONS$d = {
  5722. position: 'auto',
  5723. align: 'auto',
  5724. gutter: 16,
  5725. fixed: false,
  5726. covered: 'auto',
  5727. subMenuTrigger: 'hover',
  5728. subMenuDelay: 200,
  5729. };
  5730. var Menu = function Menu(anchorSelector, menuSelector, options) {
  5731. var this$1 = this;
  5732. if ( options === void 0 ) options = {};
  5733. /**
  5734. * 配置参数
  5735. */
  5736. this.options = extend({}, DEFAULT_OPTIONS$d);
  5737. /**
  5738. * 当前菜单状态
  5739. */
  5740. this.state = 'closed';
  5741. this.$anchor = $(anchorSelector).first();
  5742. this.$element = $(menuSelector).first();
  5743. // 触发菜单的元素 和 菜单必须是同级的元素,否则菜单可能不能定位
  5744. if (!this.$anchor.parent().is(this.$element.parent())) {
  5745. throw new Error('anchorSelector and menuSelector must be siblings');
  5746. }
  5747. extend(this.options, options);
  5748. // 是否是级联菜单
  5749. this.isCascade = this.$element.hasClass('mdui-menu-cascade');
  5750. // covered 参数处理
  5751. this.isCovered =
  5752. this.options.covered === 'auto' ? !this.isCascade : this.options.covered;
  5753. // 点击触发菜单切换
  5754. this.$anchor.on('click', function () { return this$1.toggle(); });
  5755. // 点击菜单外面区域关闭菜单
  5756. $document.on('click touchstart', function (event) {
  5757. var $target = $(event.target);
  5758. if (this$1.isOpen() &&
  5759. !$target.is(this$1.$element) &&
  5760. !contains(this$1.$element[0], $target[0]) &&
  5761. !$target.is(this$1.$anchor) &&
  5762. !contains(this$1.$anchor[0], $target[0])) {
  5763. this$1.close();
  5764. }
  5765. });
  5766. // 点击不含子菜单的菜单条目关闭菜单
  5767. // eslint-disable-next-line @typescript-eslint/no-this-alias
  5768. var that = this;
  5769. $document.on('click', '.mdui-menu-item', function () {
  5770. var $item = $(this);
  5771. if (!$item.find('.mdui-menu').length &&
  5772. $item.attr('disabled') === undefined) {
  5773. that.close();
  5774. }
  5775. });
  5776. // 绑定点击或鼠标移入含子菜单的条目的事件
  5777. this.bindSubMenuEvent();
  5778. // 窗口大小变化时,重新调整菜单位置
  5779. $window.on('resize', $.throttle(function () { return this$1.readjust(); }, 100));
  5780. };
  5781. /**
  5782. * 是否为打开状态
  5783. */
  5784. Menu.prototype.isOpen = function isOpen () {
  5785. return this.state === 'opening' || this.state === 'opened';
  5786. };
  5787. /**
  5788. * 触发组件事件
  5789. * @param name
  5790. */
  5791. Menu.prototype.triggerEvent = function triggerEvent (name) {
  5792. componentEvent(name, 'menu', this.$element, this);
  5793. };
  5794. /**
  5795. * 调整主菜单位置
  5796. */
  5797. Menu.prototype.readjust = function readjust () {
  5798. var menuLeft;
  5799. var menuTop;
  5800. // 菜单位置和方向
  5801. var position;
  5802. var align;
  5803. // window 窗口的宽度和高度
  5804. var windowHeight = $window.height();
  5805. var windowWidth = $window.width();
  5806. // 配置参数
  5807. var gutter = this.options.gutter;
  5808. var isCovered = this.isCovered;
  5809. var isFixed = this.options.fixed;
  5810. // 动画方向参数
  5811. var transformOriginX;
  5812. var transformOriginY;
  5813. // 菜单的原始宽度和高度
  5814. var menuWidth = this.$element.width();
  5815. var menuHeight = this.$element.height();
  5816. // 触发菜单的元素在窗口中的位置
  5817. var anchorRect = this.$anchor[0].getBoundingClientRect();
  5818. var anchorTop = anchorRect.top;
  5819. var anchorLeft = anchorRect.left;
  5820. var anchorHeight = anchorRect.height;
  5821. var anchorWidth = anchorRect.width;
  5822. var anchorBottom = windowHeight - anchorTop - anchorHeight;
  5823. var anchorRight = windowWidth - anchorLeft - anchorWidth;
  5824. // 触发元素相对其拥有定位属性的父元素的位置
  5825. var anchorOffsetTop = this.$anchor[0].offsetTop;
  5826. var anchorOffsetLeft = this.$anchor[0].offsetLeft;
  5827. // 自动判断菜单位置
  5828. if (this.options.position === 'auto') {
  5829. if (anchorBottom + (isCovered ? anchorHeight : 0) > menuHeight + gutter) {
  5830. // 判断下方是否放得下菜单
  5831. position = 'bottom';
  5832. }
  5833. else if (anchorTop + (isCovered ? anchorHeight : 0) >
  5834. menuHeight + gutter) {
  5835. // 判断上方是否放得下菜单
  5836. position = 'top';
  5837. }
  5838. else {
  5839. // 上下都放不下,居中显示
  5840. position = 'center';
  5841. }
  5842. }
  5843. else {
  5844. position = this.options.position;
  5845. }
  5846. // 自动判断菜单对齐方式
  5847. if (this.options.align === 'auto') {
  5848. if (anchorRight + anchorWidth > menuWidth + gutter) {
  5849. // 判断右侧是否放得下菜单
  5850. align = 'left';
  5851. }
  5852. else if (anchorLeft + anchorWidth > menuWidth + gutter) {
  5853. // 判断左侧是否放得下菜单
  5854. align = 'right';
  5855. }
  5856. else {
  5857. // 左右都放不下,居中显示
  5858. align = 'center';
  5859. }
  5860. }
  5861. else {
  5862. align = this.options.align;
  5863. }
  5864. // 设置菜单位置
  5865. if (position === 'bottom') {
  5866. transformOriginY = '0';
  5867. menuTop =
  5868. (isCovered ? 0 : anchorHeight) +
  5869. (isFixed ? anchorTop : anchorOffsetTop);
  5870. }
  5871. else if (position === 'top') {
  5872. transformOriginY = '100%';
  5873. menuTop =
  5874. (isCovered ? anchorHeight : 0) +
  5875. (isFixed ? anchorTop - menuHeight : anchorOffsetTop - menuHeight);
  5876. }
  5877. else {
  5878. transformOriginY = '50%';
  5879. // =====================在窗口中居中
  5880. // 显示的菜单的高度,简单菜单高度不超过窗口高度,若超过了则在菜单内部显示滚动条
  5881. // 级联菜单内部不允许出现滚动条
  5882. var menuHeightTemp = menuHeight;
  5883. // 简单菜单比窗口高时,限制菜单高度
  5884. if (!this.isCascade) {
  5885. if (menuHeight + gutter * 2 > windowHeight) {
  5886. menuHeightTemp = windowHeight - gutter * 2;
  5887. this.$element.height(menuHeightTemp);
  5888. }
  5889. }
  5890. menuTop =
  5891. (windowHeight - menuHeightTemp) / 2 +
  5892. (isFixed ? 0 : anchorOffsetTop - anchorTop);
  5893. }
  5894. this.$element.css('top', (menuTop + "px"));
  5895. // 设置菜单对齐方式
  5896. if (align === 'left') {
  5897. transformOriginX = '0';
  5898. menuLeft = isFixed ? anchorLeft : anchorOffsetLeft;
  5899. }
  5900. else if (align === 'right') {
  5901. transformOriginX = '100%';
  5902. menuLeft = isFixed
  5903. ? anchorLeft + anchorWidth - menuWidth
  5904. : anchorOffsetLeft + anchorWidth - menuWidth;
  5905. }
  5906. else {
  5907. transformOriginX = '50%';
  5908. //=======================在窗口中居中
  5909. // 显示的菜单的宽度,菜单宽度不能超过窗口宽度
  5910. var menuWidthTemp = menuWidth;
  5911. // 菜单比窗口宽,限制菜单宽度
  5912. if (menuWidth + gutter * 2 > windowWidth) {
  5913. menuWidthTemp = windowWidth - gutter * 2;
  5914. this.$element.width(menuWidthTemp);
  5915. }
  5916. menuLeft =
  5917. (windowWidth - menuWidthTemp) / 2 +
  5918. (isFixed ? 0 : anchorOffsetLeft - anchorLeft);
  5919. }
  5920. this.$element.css('left', (menuLeft + "px"));
  5921. // 设置菜单动画方向
  5922. this.$element.transformOrigin((transformOriginX + " " + transformOriginY));
  5923. };
  5924. /**
  5925. * 调整子菜单的位置
  5926. * @param $submenu
  5927. */
  5928. Menu.prototype.readjustSubmenu = function readjustSubmenu ($submenu) {
  5929. var $item = $submenu.parent('.mdui-menu-item');
  5930. var submenuTop;
  5931. var submenuLeft;
  5932. // 子菜单位置和方向
  5933. var position;
  5934. var align;
  5935. // window 窗口的宽度和高度
  5936. var windowHeight = $window.height();
  5937. var windowWidth = $window.width();
  5938. // 动画方向参数
  5939. var transformOriginX;
  5940. var transformOriginY;
  5941. // 子菜单的原始宽度和高度
  5942. var submenuWidth = $submenu.width();
  5943. var submenuHeight = $submenu.height();
  5944. // 触发子菜单的菜单项的宽度高度
  5945. var itemRect = $item[0].getBoundingClientRect();
  5946. var itemWidth = itemRect.width;
  5947. var itemHeight = itemRect.height;
  5948. var itemLeft = itemRect.left;
  5949. var itemTop = itemRect.top;
  5950. // 判断菜单上下位置
  5951. if (windowHeight - itemTop > submenuHeight) {
  5952. // 判断下方是否放得下菜单
  5953. position = 'bottom';
  5954. }
  5955. else if (itemTop + itemHeight > submenuHeight) {
  5956. // 判断上方是否放得下菜单
  5957. position = 'top';
  5958. }
  5959. else {
  5960. // 默认放在下方
  5961. position = 'bottom';
  5962. }
  5963. // 判断菜单左右位置
  5964. if (windowWidth - itemLeft - itemWidth > submenuWidth) {
  5965. // 判断右侧是否放得下菜单
  5966. align = 'left';
  5967. }
  5968. else if (itemLeft > submenuWidth) {
  5969. // 判断左侧是否放得下菜单
  5970. align = 'right';
  5971. }
  5972. else {
  5973. // 默认放在右侧
  5974. align = 'left';
  5975. }
  5976. // 设置菜单位置
  5977. if (position === 'bottom') {
  5978. transformOriginY = '0';
  5979. submenuTop = '0';
  5980. }
  5981. else if (position === 'top') {
  5982. transformOriginY = '100%';
  5983. submenuTop = -submenuHeight + itemHeight;
  5984. }
  5985. $submenu.css('top', (submenuTop + "px"));
  5986. // 设置菜单对齐方式
  5987. if (align === 'left') {
  5988. transformOriginX = '0';
  5989. submenuLeft = itemWidth;
  5990. }
  5991. else if (align === 'right') {
  5992. transformOriginX = '100%';
  5993. submenuLeft = -submenuWidth;
  5994. }
  5995. $submenu.css('left', (submenuLeft + "px"));
  5996. // 设置菜单动画方向
  5997. $submenu.transformOrigin((transformOriginX + " " + transformOriginY));
  5998. };
  5999. /**
  6000. * 打开子菜单
  6001. * @param $submenu
  6002. */
  6003. Menu.prototype.openSubMenu = function openSubMenu ($submenu) {
  6004. this.readjustSubmenu($submenu);
  6005. $submenu
  6006. .addClass('mdui-menu-open')
  6007. .parent('.mdui-menu-item')
  6008. .addClass('mdui-menu-item-active');
  6009. };
  6010. /**
  6011. * 关闭子菜单,及其嵌套的子菜单
  6012. * @param $submenu
  6013. */
  6014. Menu.prototype.closeSubMenu = function closeSubMenu ($submenu) {
  6015. // 关闭子菜单
  6016. $submenu
  6017. .removeClass('mdui-menu-open')
  6018. .addClass('mdui-menu-closing')
  6019. .transitionEnd(function () { return $submenu.removeClass('mdui-menu-closing'); })
  6020. // 移除激活状态的样式
  6021. .parent('.mdui-menu-item')
  6022. .removeClass('mdui-menu-item-active');
  6023. // 循环关闭嵌套的子菜单
  6024. $submenu.find('.mdui-menu').each(function (_, menu) {
  6025. var $subSubmenu = $(menu);
  6026. $subSubmenu
  6027. .removeClass('mdui-menu-open')
  6028. .addClass('mdui-menu-closing')
  6029. .transitionEnd(function () { return $subSubmenu.removeClass('mdui-menu-closing'); })
  6030. .parent('.mdui-menu-item')
  6031. .removeClass('mdui-menu-item-active');
  6032. });
  6033. };
  6034. /**
  6035. * 切换子菜单状态
  6036. * @param $submenu
  6037. */
  6038. Menu.prototype.toggleSubMenu = function toggleSubMenu ($submenu) {
  6039. $submenu.hasClass('mdui-menu-open')
  6040. ? this.closeSubMenu($submenu)
  6041. : this.openSubMenu($submenu);
  6042. };
  6043. /**
  6044. * 绑定子菜单事件
  6045. */
  6046. Menu.prototype.bindSubMenuEvent = function bindSubMenuEvent () {
  6047. // eslint-disable-next-line @typescript-eslint/no-this-alias
  6048. var that = this;
  6049. // 点击打开子菜单
  6050. this.$element.on('click', '.mdui-menu-item', function (event) {
  6051. var $item = $(this);
  6052. var $target = $(event.target);
  6053. // 禁用状态菜单不操作
  6054. if ($item.attr('disabled') !== undefined) {
  6055. return;
  6056. }
  6057. // 没有点击在子菜单的菜单项上时,不操作(点在了子菜单的空白区域、或分隔线上)
  6058. if ($target.is('.mdui-menu') || $target.is('.mdui-divider')) {
  6059. return;
  6060. }
  6061. // 阻止冒泡,点击菜单项时只在最后一级的 mdui-menu-item 上生效,不向上冒泡
  6062. if (!$target.parents('.mdui-menu-item').first().is($item)) {
  6063. return;
  6064. }
  6065. // 当前菜单的子菜单
  6066. var $submenu = $item.children('.mdui-menu');
  6067. // 先关闭除当前子菜单外的所有同级子菜单
  6068. $item
  6069. .parent('.mdui-menu')
  6070. .children('.mdui-menu-item')
  6071. .each(function (_, item) {
  6072. var $tmpSubmenu = $(item).children('.mdui-menu');
  6073. if ($tmpSubmenu.length &&
  6074. (!$submenu.length || !$tmpSubmenu.is($submenu))) {
  6075. that.closeSubMenu($tmpSubmenu);
  6076. }
  6077. });
  6078. // 切换当前子菜单
  6079. if ($submenu.length) {
  6080. that.toggleSubMenu($submenu);
  6081. }
  6082. });
  6083. if (this.options.subMenuTrigger === 'hover') {
  6084. // 临时存储 setTimeout 对象
  6085. var timeout = null;
  6086. var timeoutOpen = null;
  6087. this.$element.on('mouseover mouseout', '.mdui-menu-item', function (event) {
  6088. var $item = $(this);
  6089. var eventType = event.type;
  6090. var $relatedTarget = $(event.relatedTarget);
  6091. // 禁用状态的菜单不操作
  6092. if ($item.attr('disabled') !== undefined) {
  6093. return;
  6094. }
  6095. // 用 mouseover 模拟 mouseenter
  6096. if (eventType === 'mouseover') {
  6097. if (!$item.is($relatedTarget) &&
  6098. contains($item[0], $relatedTarget[0])) {
  6099. return;
  6100. }
  6101. }
  6102. // 用 mouseout 模拟 mouseleave
  6103. else if (eventType === 'mouseout') {
  6104. if ($item.is($relatedTarget) ||
  6105. contains($item[0], $relatedTarget[0])) {
  6106. return;
  6107. }
  6108. }
  6109. // 当前菜单项下的子菜单,未必存在
  6110. var $submenu = $item.children('.mdui-menu');
  6111. // 鼠标移入菜单项时,显示菜单项下的子菜单
  6112. if (eventType === 'mouseover') {
  6113. if ($submenu.length) {
  6114. // 当前子菜单准备打开时,如果当前子菜单正准备着关闭,不用再关闭了
  6115. var tmpClose = $submenu.data('timeoutClose.mdui.menu');
  6116. if (tmpClose) {
  6117. clearTimeout(tmpClose);
  6118. }
  6119. // 如果当前子菜单已经打开,不操作
  6120. if ($submenu.hasClass('mdui-menu-open')) {
  6121. return;
  6122. }
  6123. // 当前子菜单准备打开时,其他准备打开的子菜单不用再打开了
  6124. clearTimeout(timeoutOpen);
  6125. // 准备打开当前子菜单
  6126. timeout = timeoutOpen = setTimeout(function () { return that.openSubMenu($submenu); }, that.options.subMenuDelay);
  6127. $submenu.data('timeoutOpen.mdui.menu', timeout);
  6128. }
  6129. }
  6130. // 鼠标移出菜单项时,关闭菜单项下的子菜单
  6131. else if (eventType === 'mouseout') {
  6132. if ($submenu.length) {
  6133. // 鼠标移出菜单项时,如果当前菜单项下的子菜单正准备打开,不用再打开了
  6134. var tmpOpen = $submenu.data('timeoutOpen.mdui.menu');
  6135. if (tmpOpen) {
  6136. clearTimeout(tmpOpen);
  6137. }
  6138. // 准备关闭当前子菜单
  6139. timeout = setTimeout(function () { return that.closeSubMenu($submenu); }, that.options.subMenuDelay);
  6140. $submenu.data('timeoutClose.mdui.menu', timeout);
  6141. }
  6142. }
  6143. });
  6144. }
  6145. };
  6146. /**
  6147. * 动画结束回调
  6148. */
  6149. Menu.prototype.transitionEnd = function transitionEnd () {
  6150. this.$element.removeClass('mdui-menu-closing');
  6151. if (this.state === 'opening') {
  6152. this.state = 'opened';
  6153. this.triggerEvent('opened');
  6154. }
  6155. if (this.state === 'closing') {
  6156. this.state = 'closed';
  6157. this.triggerEvent('closed');
  6158. // 关闭后,恢复菜单样式到默认状态,并恢复 fixed 定位
  6159. this.$element.css({
  6160. top: '',
  6161. left: '',
  6162. width: '',
  6163. position: 'fixed',
  6164. });
  6165. }
  6166. };
  6167. /**
  6168. * 切换菜单状态
  6169. */
  6170. Menu.prototype.toggle = function toggle () {
  6171. this.isOpen() ? this.close() : this.open();
  6172. };
  6173. /**
  6174. * 打开菜单
  6175. */
  6176. Menu.prototype.open = function open () {
  6177. var this$1 = this;
  6178. if (this.isOpen()) {
  6179. return;
  6180. }
  6181. this.state = 'opening';
  6182. this.triggerEvent('open');
  6183. this.readjust();
  6184. this.$element
  6185. // 菜单隐藏状态使用使用 fixed 定位。
  6186. .css('position', this.options.fixed ? 'fixed' : 'absolute')
  6187. .addClass('mdui-menu-open')
  6188. .transitionEnd(function () { return this$1.transitionEnd(); });
  6189. };
  6190. /**
  6191. * 关闭菜单
  6192. */
  6193. Menu.prototype.close = function close () {
  6194. var this$1 = this;
  6195. if (!this.isOpen()) {
  6196. return;
  6197. }
  6198. this.state = 'closing';
  6199. this.triggerEvent('close');
  6200. // 菜单开始关闭时,关闭所有子菜单
  6201. this.$element.find('.mdui-menu').each(function (_, submenu) {
  6202. this$1.closeSubMenu($(submenu));
  6203. });
  6204. this.$element
  6205. .removeClass('mdui-menu-open')
  6206. .addClass('mdui-menu-closing')
  6207. .transitionEnd(function () { return this$1.transitionEnd(); });
  6208. };
  6209. mdui.Menu = Menu;
  6210. var customAttr$9 = 'mdui-menu';
  6211. var dataName$3 = '_mdui_menu';
  6212. $(function () {
  6213. $document.on('click', ("[" + customAttr$9 + "]"), function () {
  6214. var $this = $(this);
  6215. var instance = $this.data(dataName$3);
  6216. if (!instance) {
  6217. var options = parseOptions(this, customAttr$9);
  6218. var menuSelector = options.target;
  6219. // @ts-ignore
  6220. delete options.target;
  6221. instance = new mdui.Menu($this, menuSelector, options);
  6222. $this.data(dataName$3, instance);
  6223. instance.toggle();
  6224. }
  6225. });
  6226. });
  6227. return mdui;
  6228. })));
  6229. //# sourceMappingURL=mdui.js.map