ui-bootstrap-tpls-1.3.3.js 255 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347
  1. /*
  2. * angular-ui-bootstrap
  3. * http://angular-ui.github.io/bootstrap/
  4. * Version: 1.3.3 - 2016-05-22
  5. * License: MIT
  6. */angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dateparser","ui.bootstrap.isClass","ui.bootstrap.datepicker","ui.bootstrap.position","ui.bootstrap.datepickerPopup","ui.bootstrap.debounce","ui.bootstrap.dropdown","ui.bootstrap.stackedMap","ui.bootstrap.modal","ui.bootstrap.paging","ui.bootstrap.pager","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]);
  7. angular.module("ui.bootstrap.tpls", ["uib/template/accordion/accordion-group.html","uib/template/accordion/accordion.html","uib/template/alert/alert.html","uib/template/carousel/carousel.html","uib/template/carousel/slide.html","uib/template/datepicker/datepicker.html","uib/template/datepicker/day.html","uib/template/datepicker/month.html","uib/template/datepicker/year.html","uib/template/datepickerPopup/popup.html","uib/template/modal/backdrop.html","uib/template/modal/window.html","uib/template/pager/pager.html","uib/template/pagination/pagination.html","uib/template/tooltip/tooltip-html-popup.html","uib/template/tooltip/tooltip-popup.html","uib/template/tooltip/tooltip-template-popup.html","uib/template/popover/popover-html.html","uib/template/popover/popover-template.html","uib/template/popover/popover.html","uib/template/progressbar/bar.html","uib/template/progressbar/progress.html","uib/template/progressbar/progressbar.html","uib/template/rating/rating.html","uib/template/tabs/tab.html","uib/template/tabs/tabset.html","uib/template/timepicker/timepicker.html","uib/template/typeahead/typeahead-match.html","uib/template/typeahead/typeahead-popup.html"]);
  8. angular.module('ui.bootstrap.collapse', [])
  9. .directive('uibCollapse', ['$animate', '$q', '$parse', '$injector', function($animate, $q, $parse, $injector) {
  10. var $animateCss = $injector.has('$animateCss') ? $injector.get('$animateCss') : null;
  11. return {
  12. link: function(scope, element, attrs) {
  13. var expandingExpr = $parse(attrs.expanding),
  14. expandedExpr = $parse(attrs.expanded),
  15. collapsingExpr = $parse(attrs.collapsing),
  16. collapsedExpr = $parse(attrs.collapsed);
  17. if (!scope.$eval(attrs.uibCollapse)) {
  18. element.addClass('in')
  19. .addClass('collapse')
  20. .attr('aria-expanded', true)
  21. .attr('aria-hidden', false)
  22. .css({height: 'auto'});
  23. }
  24. function expand() {
  25. if (element.hasClass('collapse') && element.hasClass('in')) {
  26. return;
  27. }
  28. $q.resolve(expandingExpr(scope))
  29. .then(function() {
  30. element.removeClass('collapse')
  31. .addClass('collapsing')
  32. .attr('aria-expanded', true)
  33. .attr('aria-hidden', false);
  34. if ($animateCss) {
  35. $animateCss(element, {
  36. addClass: 'in',
  37. easing: 'ease',
  38. to: { height: element[0].scrollHeight + 'px' }
  39. }).start()['finally'](expandDone);
  40. } else {
  41. $animate.addClass(element, 'in', {
  42. to: { height: element[0].scrollHeight + 'px' }
  43. }).then(expandDone);
  44. }
  45. });
  46. }
  47. function expandDone() {
  48. element.removeClass('collapsing')
  49. .addClass('collapse')
  50. .css({height: 'auto'});
  51. expandedExpr(scope);
  52. }
  53. function collapse() {
  54. if (!element.hasClass('collapse') && !element.hasClass('in')) {
  55. return collapseDone();
  56. }
  57. $q.resolve(collapsingExpr(scope))
  58. .then(function() {
  59. element
  60. // IMPORTANT: The height must be set before adding "collapsing" class.
  61. // Otherwise, the browser attempts to animate from height 0 (in
  62. // collapsing class) to the given height here.
  63. .css({height: element[0].scrollHeight + 'px'})
  64. // initially all panel collapse have the collapse class, this removal
  65. // prevents the animation from jumping to collapsed state
  66. .removeClass('collapse')
  67. .addClass('collapsing')
  68. .attr('aria-expanded', false)
  69. .attr('aria-hidden', true);
  70. if ($animateCss) {
  71. $animateCss(element, {
  72. removeClass: 'in',
  73. to: {height: '0'}
  74. }).start()['finally'](collapseDone);
  75. } else {
  76. $animate.removeClass(element, 'in', {
  77. to: {height: '0'}
  78. }).then(collapseDone);
  79. }
  80. });
  81. }
  82. function collapseDone() {
  83. element.css({height: '0'}); // Required so that collapse works when animation is disabled
  84. element.removeClass('collapsing')
  85. .addClass('collapse');
  86. collapsedExpr(scope);
  87. }
  88. scope.$watch(attrs.uibCollapse, function(shouldCollapse) {
  89. if (shouldCollapse) {
  90. collapse();
  91. } else {
  92. expand();
  93. }
  94. });
  95. }
  96. };
  97. }]);
  98. angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
  99. .constant('uibAccordionConfig', {
  100. closeOthers: true
  101. })
  102. .controller('UibAccordionController', ['$scope', '$attrs', 'uibAccordionConfig', function($scope, $attrs, accordionConfig) {
  103. // This array keeps track of the accordion groups
  104. this.groups = [];
  105. // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
  106. this.closeOthers = function(openGroup) {
  107. var closeOthers = angular.isDefined($attrs.closeOthers) ?
  108. $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
  109. if (closeOthers) {
  110. angular.forEach(this.groups, function(group) {
  111. if (group !== openGroup) {
  112. group.isOpen = false;
  113. }
  114. });
  115. }
  116. };
  117. // This is called from the accordion-group directive to add itself to the accordion
  118. this.addGroup = function(groupScope) {
  119. var that = this;
  120. this.groups.push(groupScope);
  121. groupScope.$on('$destroy', function(event) {
  122. that.removeGroup(groupScope);
  123. });
  124. };
  125. // This is called from the accordion-group directive when to remove itself
  126. this.removeGroup = function(group) {
  127. var index = this.groups.indexOf(group);
  128. if (index !== -1) {
  129. this.groups.splice(index, 1);
  130. }
  131. };
  132. }])
  133. // The accordion directive simply sets up the directive controller
  134. // and adds an accordion CSS class to itself element.
  135. .directive('uibAccordion', function() {
  136. return {
  137. controller: 'UibAccordionController',
  138. controllerAs: 'accordion',
  139. transclude: true,
  140. templateUrl: function(element, attrs) {
  141. return attrs.templateUrl || 'uib/template/accordion/accordion.html';
  142. }
  143. };
  144. })
  145. // The accordion-group directive indicates a block of html that will expand and collapse in an accordion
  146. .directive('uibAccordionGroup', function() {
  147. return {
  148. require: '^uibAccordion', // We need this directive to be inside an accordion
  149. transclude: true, // It transcludes the contents of the directive into the template
  150. replace: true, // The element containing the directive will be replaced with the template
  151. templateUrl: function(element, attrs) {
  152. return attrs.templateUrl || 'uib/template/accordion/accordion-group.html';
  153. },
  154. scope: {
  155. heading: '@', // Interpolate the heading attribute onto this scope
  156. panelClass: '@?', // Ditto with panelClass
  157. isOpen: '=?',
  158. isDisabled: '=?'
  159. },
  160. controller: function() {
  161. this.setHeading = function(element) {
  162. this.heading = element;
  163. };
  164. },
  165. link: function(scope, element, attrs, accordionCtrl) {
  166. accordionCtrl.addGroup(scope);
  167. scope.openClass = attrs.openClass || 'panel-open';
  168. scope.panelClass = attrs.panelClass || 'panel-default';
  169. scope.$watch('isOpen', function(value) {
  170. element.toggleClass(scope.openClass, !!value);
  171. if (value) {
  172. accordionCtrl.closeOthers(scope);
  173. }
  174. });
  175. scope.toggleOpen = function($event) {
  176. if (!scope.isDisabled) {
  177. if (!$event || $event.which === 32) {
  178. scope.isOpen = !scope.isOpen;
  179. }
  180. }
  181. };
  182. var id = 'accordiongroup-' + scope.$id + '-' + Math.floor(Math.random() * 10000);
  183. scope.headingId = id + '-tab';
  184. scope.panelId = id + '-panel';
  185. }
  186. };
  187. })
  188. // Use accordion-heading below an accordion-group to provide a heading containing HTML
  189. .directive('uibAccordionHeading', function() {
  190. return {
  191. transclude: true, // Grab the contents to be used as the heading
  192. template: '', // In effect remove this element!
  193. replace: true,
  194. require: '^uibAccordionGroup',
  195. link: function(scope, element, attrs, accordionGroupCtrl, transclude) {
  196. // Pass the heading to the accordion-group controller
  197. // so that it can be transcluded into the right place in the template
  198. // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
  199. accordionGroupCtrl.setHeading(transclude(scope, angular.noop));
  200. }
  201. };
  202. })
  203. // Use in the accordion-group template to indicate where you want the heading to be transcluded
  204. // You must provide the property on the accordion-group controller that will hold the transcluded element
  205. .directive('uibAccordionTransclude', function() {
  206. return {
  207. require: '^uibAccordionGroup',
  208. link: function(scope, element, attrs, controller) {
  209. scope.$watch(function() { return controller[attrs.uibAccordionTransclude]; }, function(heading) {
  210. if (heading) {
  211. var elem = angular.element(element[0].querySelector(getHeaderSelectors()));
  212. elem.html('');
  213. elem.append(heading);
  214. }
  215. });
  216. }
  217. };
  218. function getHeaderSelectors() {
  219. return 'uib-accordion-header,' +
  220. 'data-uib-accordion-header,' +
  221. 'x-uib-accordion-header,' +
  222. 'uib\\:accordion-header,' +
  223. '[uib-accordion-header],' +
  224. '[data-uib-accordion-header],' +
  225. '[x-uib-accordion-header]';
  226. }
  227. });
  228. angular.module('ui.bootstrap.alert', [])
  229. .controller('UibAlertController', ['$scope', '$attrs', '$interpolate', '$timeout', function($scope, $attrs, $interpolate, $timeout) {
  230. $scope.closeable = !!$attrs.close;
  231. var dismissOnTimeout = angular.isDefined($attrs.dismissOnTimeout) ?
  232. $interpolate($attrs.dismissOnTimeout)($scope.$parent) : null;
  233. if (dismissOnTimeout) {
  234. $timeout(function() {
  235. $scope.close();
  236. }, parseInt(dismissOnTimeout, 10));
  237. }
  238. }])
  239. .directive('uibAlert', function() {
  240. return {
  241. controller: 'UibAlertController',
  242. controllerAs: 'alert',
  243. templateUrl: function(element, attrs) {
  244. return attrs.templateUrl || 'uib/template/alert/alert.html';
  245. },
  246. transclude: true,
  247. replace: true,
  248. scope: {
  249. type: '@',
  250. close: '&'
  251. }
  252. };
  253. });
  254. angular.module('ui.bootstrap.buttons', [])
  255. .constant('uibButtonConfig', {
  256. activeClass: 'active',
  257. toggleEvent: 'click'
  258. })
  259. .controller('UibButtonsController', ['uibButtonConfig', function(buttonConfig) {
  260. this.activeClass = buttonConfig.activeClass || 'active';
  261. this.toggleEvent = buttonConfig.toggleEvent || 'click';
  262. }])
  263. .directive('uibBtnRadio', ['$parse', function($parse) {
  264. return {
  265. require: ['uibBtnRadio', 'ngModel'],
  266. controller: 'UibButtonsController',
  267. controllerAs: 'buttons',
  268. link: function(scope, element, attrs, ctrls) {
  269. var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
  270. var uncheckableExpr = $parse(attrs.uibUncheckable);
  271. element.find('input').css({display: 'none'});
  272. //model -> UI
  273. ngModelCtrl.$render = function() {
  274. element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.uibBtnRadio)));
  275. };
  276. //ui->model
  277. element.on(buttonsCtrl.toggleEvent, function() {
  278. if (attrs.disabled) {
  279. return;
  280. }
  281. var isActive = element.hasClass(buttonsCtrl.activeClass);
  282. if (!isActive || angular.isDefined(attrs.uncheckable)) {
  283. scope.$apply(function() {
  284. ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.uibBtnRadio));
  285. ngModelCtrl.$render();
  286. });
  287. }
  288. });
  289. if (attrs.uibUncheckable) {
  290. scope.$watch(uncheckableExpr, function(uncheckable) {
  291. attrs.$set('uncheckable', uncheckable ? '' : undefined);
  292. });
  293. }
  294. }
  295. };
  296. }])
  297. .directive('uibBtnCheckbox', function() {
  298. return {
  299. require: ['uibBtnCheckbox', 'ngModel'],
  300. controller: 'UibButtonsController',
  301. controllerAs: 'button',
  302. link: function(scope, element, attrs, ctrls) {
  303. var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
  304. element.find('input').css({display: 'none'});
  305. function getTrueValue() {
  306. return getCheckboxValue(attrs.btnCheckboxTrue, true);
  307. }
  308. function getFalseValue() {
  309. return getCheckboxValue(attrs.btnCheckboxFalse, false);
  310. }
  311. function getCheckboxValue(attribute, defaultValue) {
  312. return angular.isDefined(attribute) ? scope.$eval(attribute) : defaultValue;
  313. }
  314. //model -> UI
  315. ngModelCtrl.$render = function() {
  316. element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
  317. };
  318. //ui->model
  319. element.on(buttonsCtrl.toggleEvent, function() {
  320. if (attrs.disabled) {
  321. return;
  322. }
  323. scope.$apply(function() {
  324. ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue());
  325. ngModelCtrl.$render();
  326. });
  327. });
  328. }
  329. };
  330. });
  331. angular.module('ui.bootstrap.carousel', [])
  332. .controller('UibCarouselController', ['$scope', '$element', '$interval', '$timeout', '$animate', function($scope, $element, $interval, $timeout, $animate) {
  333. var self = this,
  334. slides = self.slides = $scope.slides = [],
  335. SLIDE_DIRECTION = 'uib-slideDirection',
  336. currentIndex = $scope.active,
  337. currentInterval, isPlaying, bufferedTransitions = [];
  338. var destroyed = false;
  339. self.addSlide = function(slide, element) {
  340. slides.push({
  341. slide: slide,
  342. element: element
  343. });
  344. slides.sort(function(a, b) {
  345. return +a.slide.index - +b.slide.index;
  346. });
  347. //if this is the first slide or the slide is set to active, select it
  348. if (slide.index === $scope.active || slides.length === 1 && !angular.isNumber($scope.active)) {
  349. if ($scope.$currentTransition) {
  350. $scope.$currentTransition = null;
  351. }
  352. currentIndex = slide.index;
  353. $scope.active = slide.index;
  354. setActive(currentIndex);
  355. self.select(slides[findSlideIndex(slide)]);
  356. if (slides.length === 1) {
  357. $scope.play();
  358. }
  359. }
  360. };
  361. self.getCurrentIndex = function() {
  362. for (var i = 0; i < slides.length; i++) {
  363. if (slides[i].slide.index === currentIndex) {
  364. return i;
  365. }
  366. }
  367. };
  368. self.next = $scope.next = function() {
  369. var newIndex = (self.getCurrentIndex() + 1) % slides.length;
  370. if (newIndex === 0 && $scope.noWrap()) {
  371. $scope.pause();
  372. return;
  373. }
  374. return self.select(slides[newIndex], 'next');
  375. };
  376. self.prev = $scope.prev = function() {
  377. var newIndex = self.getCurrentIndex() - 1 < 0 ? slides.length - 1 : self.getCurrentIndex() - 1;
  378. if ($scope.noWrap() && newIndex === slides.length - 1) {
  379. $scope.pause();
  380. return;
  381. }
  382. return self.select(slides[newIndex], 'prev');
  383. };
  384. self.removeSlide = function(slide) {
  385. var index = findSlideIndex(slide);
  386. var bufferedIndex = bufferedTransitions.indexOf(slides[index]);
  387. if (bufferedIndex !== -1) {
  388. bufferedTransitions.splice(bufferedIndex, 1);
  389. }
  390. //get the index of the slide inside the carousel
  391. slides.splice(index, 1);
  392. if (slides.length > 0 && currentIndex === index) {
  393. if (index >= slides.length) {
  394. currentIndex = slides.length - 1;
  395. $scope.active = currentIndex;
  396. setActive(currentIndex);
  397. self.select(slides[slides.length - 1]);
  398. } else {
  399. currentIndex = index;
  400. $scope.active = currentIndex;
  401. setActive(currentIndex);
  402. self.select(slides[index]);
  403. }
  404. } else if (currentIndex > index) {
  405. currentIndex--;
  406. $scope.active = currentIndex;
  407. }
  408. //clean the active value when no more slide
  409. if (slides.length === 0) {
  410. currentIndex = null;
  411. $scope.active = null;
  412. clearBufferedTransitions();
  413. }
  414. };
  415. /* direction: "prev" or "next" */
  416. self.select = $scope.select = function(nextSlide, direction) {
  417. var nextIndex = findSlideIndex(nextSlide.slide);
  418. //Decide direction if it's not given
  419. if (direction === undefined) {
  420. direction = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
  421. }
  422. //Prevent this user-triggered transition from occurring if there is already one in progress
  423. if (nextSlide.slide.index !== currentIndex &&
  424. !$scope.$currentTransition) {
  425. goNext(nextSlide.slide, nextIndex, direction);
  426. } else if (nextSlide && nextSlide.slide.index !== currentIndex && $scope.$currentTransition) {
  427. bufferedTransitions.push(slides[nextIndex]);
  428. }
  429. };
  430. /* Allow outside people to call indexOf on slides array */
  431. $scope.indexOfSlide = function(slide) {
  432. return +slide.slide.index;
  433. };
  434. $scope.isActive = function(slide) {
  435. return $scope.active === slide.slide.index;
  436. };
  437. $scope.isPrevDisabled = function() {
  438. return $scope.active === 0 && $scope.noWrap();
  439. };
  440. $scope.isNextDisabled = function() {
  441. return $scope.active === slides.length - 1 && $scope.noWrap();
  442. };
  443. $scope.pause = function() {
  444. if (!$scope.noPause) {
  445. isPlaying = false;
  446. resetTimer();
  447. }
  448. };
  449. $scope.play = function() {
  450. if (!isPlaying) {
  451. isPlaying = true;
  452. restartTimer();
  453. }
  454. };
  455. $scope.$on('$destroy', function() {
  456. destroyed = true;
  457. resetTimer();
  458. });
  459. $scope.$watch('noTransition', function(noTransition) {
  460. $animate.enabled($element, !noTransition);
  461. });
  462. $scope.$watch('interval', restartTimer);
  463. $scope.$watchCollection('slides', resetTransition);
  464. $scope.$watch('active', function(index) {
  465. if (angular.isNumber(index) && currentIndex !== index) {
  466. for (var i = 0; i < slides.length; i++) {
  467. if (slides[i].slide.index === index) {
  468. index = i;
  469. break;
  470. }
  471. }
  472. var slide = slides[index];
  473. if (slide) {
  474. setActive(index);
  475. self.select(slides[index]);
  476. currentIndex = index;
  477. }
  478. }
  479. });
  480. function clearBufferedTransitions() {
  481. while (bufferedTransitions.length) {
  482. bufferedTransitions.shift();
  483. }
  484. }
  485. function getSlideByIndex(index) {
  486. for (var i = 0, l = slides.length; i < l; ++i) {
  487. if (slides[i].index === index) {
  488. return slides[i];
  489. }
  490. }
  491. }
  492. function setActive(index) {
  493. for (var i = 0; i < slides.length; i++) {
  494. slides[i].slide.active = i === index;
  495. }
  496. }
  497. function goNext(slide, index, direction) {
  498. if (destroyed) {
  499. return;
  500. }
  501. angular.extend(slide, {direction: direction});
  502. angular.extend(slides[currentIndex].slide || {}, {direction: direction});
  503. if ($animate.enabled($element) && !$scope.$currentTransition &&
  504. slides[index].element && self.slides.length > 1) {
  505. slides[index].element.data(SLIDE_DIRECTION, slide.direction);
  506. var currentIdx = self.getCurrentIndex();
  507. if (angular.isNumber(currentIdx) && slides[currentIdx].element) {
  508. slides[currentIdx].element.data(SLIDE_DIRECTION, slide.direction);
  509. }
  510. $scope.$currentTransition = true;
  511. $animate.on('addClass', slides[index].element, function(element, phase) {
  512. if (phase === 'close') {
  513. $scope.$currentTransition = null;
  514. $animate.off('addClass', element);
  515. if (bufferedTransitions.length) {
  516. var nextSlide = bufferedTransitions.pop().slide;
  517. var nextIndex = nextSlide.index;
  518. var nextDirection = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
  519. clearBufferedTransitions();
  520. goNext(nextSlide, nextIndex, nextDirection);
  521. }
  522. }
  523. });
  524. }
  525. $scope.active = slide.index;
  526. currentIndex = slide.index;
  527. setActive(index);
  528. //every time you change slides, reset the timer
  529. restartTimer();
  530. }
  531. function findSlideIndex(slide) {
  532. for (var i = 0; i < slides.length; i++) {
  533. if (slides[i].slide === slide) {
  534. return i;
  535. }
  536. }
  537. }
  538. function resetTimer() {
  539. if (currentInterval) {
  540. $interval.cancel(currentInterval);
  541. currentInterval = null;
  542. }
  543. }
  544. function resetTransition(slides) {
  545. if (!slides.length) {
  546. $scope.$currentTransition = null;
  547. clearBufferedTransitions();
  548. }
  549. }
  550. function restartTimer() {
  551. resetTimer();
  552. var interval = +$scope.interval;
  553. if (!isNaN(interval) && interval > 0) {
  554. currentInterval = $interval(timerFn, interval);
  555. }
  556. }
  557. function timerFn() {
  558. var interval = +$scope.interval;
  559. if (isPlaying && !isNaN(interval) && interval > 0 && slides.length) {
  560. $scope.next();
  561. } else {
  562. $scope.pause();
  563. }
  564. }
  565. }])
  566. .directive('uibCarousel', function() {
  567. return {
  568. transclude: true,
  569. replace: true,
  570. controller: 'UibCarouselController',
  571. controllerAs: 'carousel',
  572. templateUrl: function(element, attrs) {
  573. return attrs.templateUrl || 'uib/template/carousel/carousel.html';
  574. },
  575. scope: {
  576. active: '=',
  577. interval: '=',
  578. noTransition: '=',
  579. noPause: '=',
  580. noWrap: '&'
  581. }
  582. };
  583. })
  584. .directive('uibSlide', function() {
  585. return {
  586. require: '^uibCarousel',
  587. transclude: true,
  588. replace: true,
  589. templateUrl: function(element, attrs) {
  590. return attrs.templateUrl || 'uib/template/carousel/slide.html';
  591. },
  592. scope: {
  593. actual: '=?',
  594. index: '=?'
  595. },
  596. link: function (scope, element, attrs, carouselCtrl) {
  597. carouselCtrl.addSlide(scope, element);
  598. //when the scope is destroyed then remove the slide from the current slides array
  599. scope.$on('$destroy', function() {
  600. carouselCtrl.removeSlide(scope);
  601. });
  602. }
  603. };
  604. })
  605. .animation('.item', ['$animateCss',
  606. function($animateCss) {
  607. var SLIDE_DIRECTION = 'uib-slideDirection';
  608. function removeClass(element, className, callback) {
  609. element.removeClass(className);
  610. if (callback) {
  611. callback();
  612. }
  613. }
  614. return {
  615. beforeAddClass: function(element, className, done) {
  616. if (className === 'active') {
  617. var stopped = false;
  618. var direction = element.data(SLIDE_DIRECTION);
  619. var directionClass = direction === 'next' ? 'left' : 'right';
  620. var removeClassFn = removeClass.bind(this, element,
  621. directionClass + ' ' + direction, done);
  622. element.addClass(direction);
  623. $animateCss(element, {addClass: directionClass})
  624. .start()
  625. .done(removeClassFn);
  626. return function() {
  627. stopped = true;
  628. };
  629. }
  630. done();
  631. },
  632. beforeRemoveClass: function (element, className, done) {
  633. if (className === 'active') {
  634. var stopped = false;
  635. var direction = element.data(SLIDE_DIRECTION);
  636. var directionClass = direction === 'next' ? 'left' : 'right';
  637. var removeClassFn = removeClass.bind(this, element, directionClass, done);
  638. $animateCss(element, {addClass: directionClass})
  639. .start()
  640. .done(removeClassFn);
  641. return function() {
  642. stopped = true;
  643. };
  644. }
  645. done();
  646. }
  647. };
  648. }]);
  649. angular.module('ui.bootstrap.dateparser', [])
  650. .service('uibDateParser', ['$log', '$locale', 'dateFilter', 'orderByFilter', function($log, $locale, dateFilter, orderByFilter) {
  651. // Pulled from https://github.com/mbostock/d3/blob/master/src/format/requote.js
  652. var SPECIAL_CHARACTERS_REGEXP = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
  653. var localeId;
  654. var formatCodeToRegex;
  655. this.init = function() {
  656. localeId = $locale.id;
  657. this.parsers = {};
  658. this.formatters = {};
  659. formatCodeToRegex = [
  660. {
  661. key: 'yyyy',
  662. regex: '\\d{4}',
  663. apply: function(value) { this.year = +value; },
  664. formatter: function(date) {
  665. var _date = new Date();
  666. _date.setFullYear(Math.abs(date.getFullYear()));
  667. return dateFilter(_date, 'yyyy');
  668. }
  669. },
  670. {
  671. key: 'yy',
  672. regex: '\\d{2}',
  673. apply: function(value) { value = +value; this.year = value < 69 ? value + 2000 : value + 1900; },
  674. formatter: function(date) {
  675. var _date = new Date();
  676. _date.setFullYear(Math.abs(date.getFullYear()));
  677. return dateFilter(_date, 'yy');
  678. }
  679. },
  680. {
  681. key: 'y',
  682. regex: '\\d{1,4}',
  683. apply: function(value) { this.year = +value; },
  684. formatter: function(date) {
  685. var _date = new Date();
  686. _date.setFullYear(Math.abs(date.getFullYear()));
  687. return dateFilter(_date, 'y');
  688. }
  689. },
  690. {
  691. key: 'M!',
  692. regex: '0?[1-9]|1[0-2]',
  693. apply: function(value) { this.month = value - 1; },
  694. formatter: function(date) {
  695. var value = date.getMonth();
  696. if (/^[0-9]$/.test(value)) {
  697. return dateFilter(date, 'MM');
  698. }
  699. return dateFilter(date, 'M');
  700. }
  701. },
  702. {
  703. key: 'MMMM',
  704. regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
  705. apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); },
  706. formatter: function(date) { return dateFilter(date, 'MMMM'); }
  707. },
  708. {
  709. key: 'MMM',
  710. regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
  711. apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); },
  712. formatter: function(date) { return dateFilter(date, 'MMM'); }
  713. },
  714. {
  715. key: 'MM',
  716. regex: '0[1-9]|1[0-2]',
  717. apply: function(value) { this.month = value - 1; },
  718. formatter: function(date) { return dateFilter(date, 'MM'); }
  719. },
  720. {
  721. key: 'M',
  722. regex: '[1-9]|1[0-2]',
  723. apply: function(value) { this.month = value - 1; },
  724. formatter: function(date) { return dateFilter(date, 'M'); }
  725. },
  726. {
  727. key: 'd!',
  728. regex: '[0-2]?[0-9]{1}|3[0-1]{1}',
  729. apply: function(value) { this.date = +value; },
  730. formatter: function(date) {
  731. var value = date.getDate();
  732. if (/^[1-9]$/.test(value)) {
  733. return dateFilter(date, 'dd');
  734. }
  735. return dateFilter(date, 'd');
  736. }
  737. },
  738. {
  739. key: 'dd',
  740. regex: '[0-2][0-9]{1}|3[0-1]{1}',
  741. apply: function(value) { this.date = +value; },
  742. formatter: function(date) { return dateFilter(date, 'dd'); }
  743. },
  744. {
  745. key: 'd',
  746. regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
  747. apply: function(value) { this.date = +value; },
  748. formatter: function(date) { return dateFilter(date, 'd'); }
  749. },
  750. {
  751. key: 'EEEE',
  752. regex: $locale.DATETIME_FORMATS.DAY.join('|'),
  753. formatter: function(date) { return dateFilter(date, 'EEEE'); }
  754. },
  755. {
  756. key: 'EEE',
  757. regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|'),
  758. formatter: function(date) { return dateFilter(date, 'EEE'); }
  759. },
  760. {
  761. key: 'HH',
  762. regex: '(?:0|1)[0-9]|2[0-3]',
  763. apply: function(value) { this.hours = +value; },
  764. formatter: function(date) { return dateFilter(date, 'HH'); }
  765. },
  766. {
  767. key: 'hh',
  768. regex: '0[0-9]|1[0-2]',
  769. apply: function(value) { this.hours = +value; },
  770. formatter: function(date) { return dateFilter(date, 'hh'); }
  771. },
  772. {
  773. key: 'H',
  774. regex: '1?[0-9]|2[0-3]',
  775. apply: function(value) { this.hours = +value; },
  776. formatter: function(date) { return dateFilter(date, 'H'); }
  777. },
  778. {
  779. key: 'h',
  780. regex: '[0-9]|1[0-2]',
  781. apply: function(value) { this.hours = +value; },
  782. formatter: function(date) { return dateFilter(date, 'h'); }
  783. },
  784. {
  785. key: 'mm',
  786. regex: '[0-5][0-9]',
  787. apply: function(value) { this.minutes = +value; },
  788. formatter: function(date) { return dateFilter(date, 'mm'); }
  789. },
  790. {
  791. key: 'm',
  792. regex: '[0-9]|[1-5][0-9]',
  793. apply: function(value) { this.minutes = +value; },
  794. formatter: function(date) { return dateFilter(date, 'm'); }
  795. },
  796. {
  797. key: 'sss',
  798. regex: '[0-9][0-9][0-9]',
  799. apply: function(value) { this.milliseconds = +value; },
  800. formatter: function(date) { return dateFilter(date, 'sss'); }
  801. },
  802. {
  803. key: 'ss',
  804. regex: '[0-5][0-9]',
  805. apply: function(value) { this.seconds = +value; },
  806. formatter: function(date) { return dateFilter(date, 'ss'); }
  807. },
  808. {
  809. key: 's',
  810. regex: '[0-9]|[1-5][0-9]',
  811. apply: function(value) { this.seconds = +value; },
  812. formatter: function(date) { return dateFilter(date, 's'); }
  813. },
  814. {
  815. key: 'a',
  816. regex: $locale.DATETIME_FORMATS.AMPMS.join('|'),
  817. apply: function(value) {
  818. if (this.hours === 12) {
  819. this.hours = 0;
  820. }
  821. if (value === 'PM') {
  822. this.hours += 12;
  823. }
  824. },
  825. formatter: function(date) { return dateFilter(date, 'a'); }
  826. },
  827. {
  828. key: 'Z',
  829. regex: '[+-]\\d{4}',
  830. apply: function(value) {
  831. var matches = value.match(/([+-])(\d{2})(\d{2})/),
  832. sign = matches[1],
  833. hours = matches[2],
  834. minutes = matches[3];
  835. this.hours += toInt(sign + hours);
  836. this.minutes += toInt(sign + minutes);
  837. },
  838. formatter: function(date) {
  839. return dateFilter(date, 'Z');
  840. }
  841. },
  842. {
  843. key: 'ww',
  844. regex: '[0-4][0-9]|5[0-3]',
  845. formatter: function(date) { return dateFilter(date, 'ww'); }
  846. },
  847. {
  848. key: 'w',
  849. regex: '[0-9]|[1-4][0-9]|5[0-3]',
  850. formatter: function(date) { return dateFilter(date, 'w'); }
  851. },
  852. {
  853. key: 'GGGG',
  854. regex: $locale.DATETIME_FORMATS.ERANAMES.join('|').replace(/\s/g, '\\s'),
  855. formatter: function(date) { return dateFilter(date, 'GGGG'); }
  856. },
  857. {
  858. key: 'GGG',
  859. regex: $locale.DATETIME_FORMATS.ERAS.join('|'),
  860. formatter: function(date) { return dateFilter(date, 'GGG'); }
  861. },
  862. {
  863. key: 'GG',
  864. regex: $locale.DATETIME_FORMATS.ERAS.join('|'),
  865. formatter: function(date) { return dateFilter(date, 'GG'); }
  866. },
  867. {
  868. key: 'G',
  869. regex: $locale.DATETIME_FORMATS.ERAS.join('|'),
  870. formatter: function(date) { return dateFilter(date, 'G'); }
  871. }
  872. ];
  873. };
  874. this.init();
  875. function createParser(format, func) {
  876. var map = [], regex = format.split('');
  877. // check for literal values
  878. var quoteIndex = format.indexOf('\'');
  879. if (quoteIndex > -1) {
  880. var inLiteral = false;
  881. format = format.split('');
  882. for (var i = quoteIndex; i < format.length; i++) {
  883. if (inLiteral) {
  884. if (format[i] === '\'') {
  885. if (i + 1 < format.length && format[i+1] === '\'') { // escaped single quote
  886. format[i+1] = '$';
  887. regex[i+1] = '';
  888. } else { // end of literal
  889. regex[i] = '';
  890. inLiteral = false;
  891. }
  892. }
  893. format[i] = '$';
  894. } else {
  895. if (format[i] === '\'') { // start of literal
  896. format[i] = '$';
  897. regex[i] = '';
  898. inLiteral = true;
  899. }
  900. }
  901. }
  902. format = format.join('');
  903. }
  904. angular.forEach(formatCodeToRegex, function(data) {
  905. var index = format.indexOf(data.key);
  906. if (index > -1) {
  907. format = format.split('');
  908. regex[index] = '(' + data.regex + ')';
  909. format[index] = '$'; // Custom symbol to define consumed part of format
  910. for (var i = index + 1, n = index + data.key.length; i < n; i++) {
  911. regex[i] = '';
  912. format[i] = '$';
  913. }
  914. format = format.join('');
  915. map.push({
  916. index: index,
  917. key: data.key,
  918. apply: data[func],
  919. matcher: data.regex
  920. });
  921. }
  922. });
  923. return {
  924. regex: new RegExp('^' + regex.join('') + '$'),
  925. map: orderByFilter(map, 'index')
  926. };
  927. }
  928. this.filter = function(date, format) {
  929. if (!angular.isDate(date) || isNaN(date) || !format) {
  930. return '';
  931. }
  932. format = $locale.DATETIME_FORMATS[format] || format;
  933. if ($locale.id !== localeId) {
  934. this.init();
  935. }
  936. if (!this.formatters[format]) {
  937. this.formatters[format] = createParser(format, 'formatter');
  938. }
  939. var parser = this.formatters[format],
  940. map = parser.map;
  941. var _format = format;
  942. return map.reduce(function(str, mapper, i) {
  943. var match = _format.match(new RegExp('(.*)' + mapper.key));
  944. if (match && angular.isString(match[1])) {
  945. str += match[1];
  946. _format = _format.replace(match[1] + mapper.key, '');
  947. }
  948. var endStr = i === map.length - 1 ? _format : '';
  949. if (mapper.apply) {
  950. return str + mapper.apply.call(null, date) + endStr;
  951. }
  952. return str + endStr;
  953. }, '');
  954. };
  955. this.parse = function(input, format, baseDate) {
  956. if (!angular.isString(input) || !format) {
  957. return input;
  958. }
  959. format = $locale.DATETIME_FORMATS[format] || format;
  960. format = format.replace(SPECIAL_CHARACTERS_REGEXP, '\\$&');
  961. if ($locale.id !== localeId) {
  962. this.init();
  963. }
  964. if (!this.parsers[format]) {
  965. this.parsers[format] = createParser(format, 'apply');
  966. }
  967. var parser = this.parsers[format],
  968. regex = parser.regex,
  969. map = parser.map,
  970. results = input.match(regex),
  971. tzOffset = false;
  972. if (results && results.length) {
  973. var fields, dt;
  974. if (angular.isDate(baseDate) && !isNaN(baseDate.getTime())) {
  975. fields = {
  976. year: baseDate.getFullYear(),
  977. month: baseDate.getMonth(),
  978. date: baseDate.getDate(),
  979. hours: baseDate.getHours(),
  980. minutes: baseDate.getMinutes(),
  981. seconds: baseDate.getSeconds(),
  982. milliseconds: baseDate.getMilliseconds()
  983. };
  984. } else {
  985. if (baseDate) {
  986. $log.warn('dateparser:', 'baseDate is not a valid date');
  987. }
  988. fields = { year: 1900, month: 0, date: 1, hours: 0, minutes: 0, seconds: 0, milliseconds: 0 };
  989. }
  990. for (var i = 1, n = results.length; i < n; i++) {
  991. var mapper = map[i - 1];
  992. if (mapper.matcher === 'Z') {
  993. tzOffset = true;
  994. }
  995. if (mapper.apply) {
  996. mapper.apply.call(fields, results[i]);
  997. }
  998. }
  999. var datesetter = tzOffset ? Date.prototype.setUTCFullYear :
  1000. Date.prototype.setFullYear;
  1001. var timesetter = tzOffset ? Date.prototype.setUTCHours :
  1002. Date.prototype.setHours;
  1003. if (isValid(fields.year, fields.month, fields.date)) {
  1004. if (angular.isDate(baseDate) && !isNaN(baseDate.getTime()) && !tzOffset) {
  1005. dt = new Date(baseDate);
  1006. datesetter.call(dt, fields.year, fields.month, fields.date);
  1007. timesetter.call(dt, fields.hours, fields.minutes,
  1008. fields.seconds, fields.milliseconds);
  1009. } else {
  1010. dt = new Date(0);
  1011. datesetter.call(dt, fields.year, fields.month, fields.date);
  1012. timesetter.call(dt, fields.hours || 0, fields.minutes || 0,
  1013. fields.seconds || 0, fields.milliseconds || 0);
  1014. }
  1015. }
  1016. return dt;
  1017. }
  1018. };
  1019. // Check if date is valid for specific month (and year for February).
  1020. // Month: 0 = Jan, 1 = Feb, etc
  1021. function isValid(year, month, date) {
  1022. if (date < 1) {
  1023. return false;
  1024. }
  1025. if (month === 1 && date > 28) {
  1026. return date === 29 && (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0);
  1027. }
  1028. if (month === 3 || month === 5 || month === 8 || month === 10) {
  1029. return date < 31;
  1030. }
  1031. return true;
  1032. }
  1033. function toInt(str) {
  1034. return parseInt(str, 10);
  1035. }
  1036. this.toTimezone = toTimezone;
  1037. this.fromTimezone = fromTimezone;
  1038. this.timezoneToOffset = timezoneToOffset;
  1039. this.addDateMinutes = addDateMinutes;
  1040. this.convertTimezoneToLocal = convertTimezoneToLocal;
  1041. function toTimezone(date, timezone) {
  1042. return date && timezone ? convertTimezoneToLocal(date, timezone) : date;
  1043. }
  1044. function fromTimezone(date, timezone) {
  1045. return date && timezone ? convertTimezoneToLocal(date, timezone, true) : date;
  1046. }
  1047. //https://github.com/angular/angular.js/blob/622c42169699ec07fc6daaa19fe6d224e5d2f70e/src/Angular.js#L1207
  1048. function timezoneToOffset(timezone, fallback) {
  1049. timezone = timezone.replace(/:/g, '');
  1050. var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
  1051. return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
  1052. }
  1053. function addDateMinutes(date, minutes) {
  1054. date = new Date(date.getTime());
  1055. date.setMinutes(date.getMinutes() + minutes);
  1056. return date;
  1057. }
  1058. function convertTimezoneToLocal(date, timezone, reverse) {
  1059. reverse = reverse ? -1 : 1;
  1060. var dateTimezoneOffset = date.getTimezoneOffset();
  1061. var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
  1062. return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
  1063. }
  1064. }]);
  1065. // Avoiding use of ng-class as it creates a lot of watchers when a class is to be applied to
  1066. // at most one element.
  1067. angular.module('ui.bootstrap.isClass', [])
  1068. .directive('uibIsClass', [
  1069. '$animate',
  1070. function ($animate) {
  1071. // 11111111 22222222
  1072. var ON_REGEXP = /^\s*([\s\S]+?)\s+on\s+([\s\S]+?)\s*$/;
  1073. // 11111111 22222222
  1074. var IS_REGEXP = /^\s*([\s\S]+?)\s+for\s+([\s\S]+?)\s*$/;
  1075. var dataPerTracked = {};
  1076. return {
  1077. restrict: 'A',
  1078. compile: function(tElement, tAttrs) {
  1079. var linkedScopes = [];
  1080. var instances = [];
  1081. var expToData = {};
  1082. var lastActivated = null;
  1083. var onExpMatches = tAttrs.uibIsClass.match(ON_REGEXP);
  1084. var onExp = onExpMatches[2];
  1085. var expsStr = onExpMatches[1];
  1086. var exps = expsStr.split(',');
  1087. return linkFn;
  1088. function linkFn(scope, element, attrs) {
  1089. linkedScopes.push(scope);
  1090. instances.push({
  1091. scope: scope,
  1092. element: element
  1093. });
  1094. exps.forEach(function(exp, k) {
  1095. addForExp(exp, scope);
  1096. });
  1097. scope.$on('$destroy', removeScope);
  1098. }
  1099. function addForExp(exp, scope) {
  1100. var matches = exp.match(IS_REGEXP);
  1101. var clazz = scope.$eval(matches[1]);
  1102. var compareWithExp = matches[2];
  1103. var data = expToData[exp];
  1104. if (!data) {
  1105. var watchFn = function(compareWithVal) {
  1106. var newActivated = null;
  1107. instances.some(function(instance) {
  1108. var thisVal = instance.scope.$eval(onExp);
  1109. if (thisVal === compareWithVal) {
  1110. newActivated = instance;
  1111. return true;
  1112. }
  1113. });
  1114. if (data.lastActivated !== newActivated) {
  1115. if (data.lastActivated) {
  1116. $animate.removeClass(data.lastActivated.element, clazz);
  1117. }
  1118. if (newActivated) {
  1119. $animate.addClass(newActivated.element, clazz);
  1120. }
  1121. data.lastActivated = newActivated;
  1122. }
  1123. };
  1124. expToData[exp] = data = {
  1125. lastActivated: null,
  1126. scope: scope,
  1127. watchFn: watchFn,
  1128. compareWithExp: compareWithExp,
  1129. watcher: scope.$watch(compareWithExp, watchFn)
  1130. };
  1131. }
  1132. data.watchFn(scope.$eval(compareWithExp));
  1133. }
  1134. function removeScope(e) {
  1135. var removedScope = e.targetScope;
  1136. var index = linkedScopes.indexOf(removedScope);
  1137. linkedScopes.splice(index, 1);
  1138. instances.splice(index, 1);
  1139. if (linkedScopes.length) {
  1140. var newWatchScope = linkedScopes[0];
  1141. angular.forEach(expToData, function(data) {
  1142. if (data.scope === removedScope) {
  1143. data.watcher = newWatchScope.$watch(data.compareWithExp, data.watchFn);
  1144. data.scope = newWatchScope;
  1145. }
  1146. });
  1147. } else {
  1148. expToData = {};
  1149. }
  1150. }
  1151. }
  1152. };
  1153. }]);
  1154. angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootstrap.isClass'])
  1155. .value('$datepickerSuppressError', false)
  1156. .value('$datepickerLiteralWarning', true)
  1157. .constant('uibDatepickerConfig', {
  1158. datepickerMode: 'day',
  1159. formatDay: 'dd',
  1160. formatMonth: 'MMMM',
  1161. formatYear: 'yyyy',
  1162. formatDayHeader: 'EEE',
  1163. formatDayTitle: 'MMMM yyyy',
  1164. formatMonthTitle: 'yyyy',
  1165. maxDate: null,
  1166. maxMode: 'year',
  1167. minDate: null,
  1168. minMode: 'day',
  1169. ngModelOptions: {},
  1170. shortcutPropagation: false,
  1171. showWeeks: true,
  1172. yearColumns: 5,
  1173. yearRows: 4
  1174. })
  1175. .controller('UibDatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$locale', '$log', 'dateFilter', 'uibDatepickerConfig', '$datepickerLiteralWarning', '$datepickerSuppressError', 'uibDateParser',
  1176. function($scope, $attrs, $parse, $interpolate, $locale, $log, dateFilter, datepickerConfig, $datepickerLiteralWarning, $datepickerSuppressError, dateParser) {
  1177. var self = this,
  1178. ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl;
  1179. ngModelOptions = {},
  1180. watchListeners = [],
  1181. optionsUsed = !!$attrs.datepickerOptions;
  1182. if (!$scope.datepickerOptions) {
  1183. $scope.datepickerOptions = {};
  1184. }
  1185. // Modes chain
  1186. this.modes = ['day', 'month', 'year'];
  1187. [
  1188. 'customClass',
  1189. 'dateDisabled',
  1190. 'datepickerMode',
  1191. 'formatDay',
  1192. 'formatDayHeader',
  1193. 'formatDayTitle',
  1194. 'formatMonth',
  1195. 'formatMonthTitle',
  1196. 'formatYear',
  1197. 'maxDate',
  1198. 'maxMode',
  1199. 'minDate',
  1200. 'minMode',
  1201. 'showWeeks',
  1202. 'shortcutPropagation',
  1203. 'startingDay',
  1204. 'yearColumns',
  1205. 'yearRows'
  1206. ].forEach(function(key) {
  1207. switch (key) {
  1208. case 'customClass':
  1209. case 'dateDisabled':
  1210. $scope[key] = $scope.datepickerOptions[key] || angular.noop;
  1211. break;
  1212. case 'datepickerMode':
  1213. $scope.datepickerMode = angular.isDefined($scope.datepickerOptions.datepickerMode) ?
  1214. $scope.datepickerOptions.datepickerMode : datepickerConfig.datepickerMode;
  1215. break;
  1216. case 'formatDay':
  1217. case 'formatDayHeader':
  1218. case 'formatDayTitle':
  1219. case 'formatMonth':
  1220. case 'formatMonthTitle':
  1221. case 'formatYear':
  1222. self[key] = angular.isDefined($scope.datepickerOptions[key]) ?
  1223. $interpolate($scope.datepickerOptions[key])($scope.$parent) :
  1224. datepickerConfig[key];
  1225. break;
  1226. case 'showWeeks':
  1227. case 'shortcutPropagation':
  1228. case 'yearColumns':
  1229. case 'yearRows':
  1230. self[key] = angular.isDefined($scope.datepickerOptions[key]) ?
  1231. $scope.datepickerOptions[key] : datepickerConfig[key];
  1232. break;
  1233. case 'startingDay':
  1234. if (angular.isDefined($scope.datepickerOptions.startingDay)) {
  1235. self.startingDay = $scope.datepickerOptions.startingDay;
  1236. } else if (angular.isNumber(datepickerConfig.startingDay)) {
  1237. self.startingDay = datepickerConfig.startingDay;
  1238. } else {
  1239. self.startingDay = ($locale.DATETIME_FORMATS.FIRSTDAYOFWEEK + 8) % 7;
  1240. }
  1241. break;
  1242. case 'maxDate':
  1243. case 'minDate':
  1244. $scope.$watch('datepickerOptions.' + key, function(value) {
  1245. if (value) {
  1246. if (angular.isDate(value)) {
  1247. self[key] = dateParser.fromTimezone(new Date(value), ngModelOptions.timezone);
  1248. } else {
  1249. if ($datepickerLiteralWarning) {
  1250. $log.warn('Literal date support has been deprecated, please switch to date object usage');
  1251. }
  1252. self[key] = new Date(dateFilter(value, 'medium'));
  1253. }
  1254. } else {
  1255. self[key] = datepickerConfig[key] ?
  1256. dateParser.fromTimezone(new Date(datepickerConfig[key]), ngModelOptions.timezone) :
  1257. null;
  1258. }
  1259. self.refreshView();
  1260. });
  1261. break;
  1262. case 'maxMode':
  1263. case 'minMode':
  1264. if ($scope.datepickerOptions[key]) {
  1265. $scope.$watch(function() { return $scope.datepickerOptions[key]; }, function(value) {
  1266. self[key] = $scope[key] = angular.isDefined(value) ? value : datepickerOptions[key];
  1267. if (key === 'minMode' && self.modes.indexOf($scope.datepickerOptions.datepickerMode) < self.modes.indexOf(self[key]) ||
  1268. key === 'maxMode' && self.modes.indexOf($scope.datepickerOptions.datepickerMode) > self.modes.indexOf(self[key])) {
  1269. $scope.datepickerMode = self[key];
  1270. $scope.datepickerOptions.datepickerMode = self[key];
  1271. }
  1272. });
  1273. } else {
  1274. self[key] = $scope[key] = datepickerConfig[key] || null;
  1275. }
  1276. break;
  1277. }
  1278. });
  1279. $scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000);
  1280. $scope.disabled = angular.isDefined($attrs.disabled) || false;
  1281. if (angular.isDefined($attrs.ngDisabled)) {
  1282. watchListeners.push($scope.$parent.$watch($attrs.ngDisabled, function(disabled) {
  1283. $scope.disabled = disabled;
  1284. self.refreshView();
  1285. }));
  1286. }
  1287. $scope.isActive = function(dateObject) {
  1288. if (self.compare(dateObject.date, self.activeDate) === 0) {
  1289. $scope.activeDateId = dateObject.uid;
  1290. return true;
  1291. }
  1292. return false;
  1293. };
  1294. this.init = function(ngModelCtrl_) {
  1295. ngModelCtrl = ngModelCtrl_;
  1296. ngModelOptions = ngModelCtrl_.$options || datepickerConfig.ngModelOptions;
  1297. if ($scope.datepickerOptions.initDate) {
  1298. self.activeDate = dateParser.fromTimezone($scope.datepickerOptions.initDate, ngModelOptions.timezone) || new Date();
  1299. $scope.$watch('datepickerOptions.initDate', function(initDate) {
  1300. if (initDate && (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue) || ngModelCtrl.$invalid)) {
  1301. self.activeDate = dateParser.fromTimezone(initDate, ngModelOptions.timezone);
  1302. self.refreshView();
  1303. }
  1304. });
  1305. } else {
  1306. self.activeDate = new Date();
  1307. }
  1308. var date = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : new Date();
  1309. this.activeDate = !isNaN(date) ?
  1310. dateParser.fromTimezone(date, ngModelOptions.timezone) :
  1311. dateParser.fromTimezone(new Date(), ngModelOptions.timezone);
  1312. ngModelCtrl.$render = function() {
  1313. self.render();
  1314. };
  1315. };
  1316. this.render = function() {
  1317. if (ngModelCtrl.$viewValue) {
  1318. var date = new Date(ngModelCtrl.$viewValue),
  1319. isValid = !isNaN(date);
  1320. if (isValid) {
  1321. this.activeDate = dateParser.fromTimezone(date, ngModelOptions.timezone);
  1322. } else if (!$datepickerSuppressError) {
  1323. $log.error('Datepicker directive: "ng-model" value must be a Date object');
  1324. }
  1325. }
  1326. this.refreshView();
  1327. };
  1328. this.refreshView = function() {
  1329. if (this.element) {
  1330. $scope.selectedDt = null;
  1331. this._refreshView();
  1332. if ($scope.activeDt) {
  1333. $scope.activeDateId = $scope.activeDt.uid;
  1334. }
  1335. var date = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null;
  1336. date = dateParser.fromTimezone(date, ngModelOptions.timezone);
  1337. ngModelCtrl.$setValidity('dateDisabled', !date ||
  1338. this.element && !this.isDisabled(date));
  1339. }
  1340. };
  1341. this.createDateObject = function(date, format) {
  1342. var model = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null;
  1343. model = dateParser.fromTimezone(model, ngModelOptions.timezone);
  1344. var today = new Date();
  1345. today = dateParser.fromTimezone(today, ngModelOptions.timezone);
  1346. var time = this.compare(date, today);
  1347. var dt = {
  1348. date: date,
  1349. label: dateParser.filter(date, format),
  1350. selected: model && this.compare(date, model) === 0,
  1351. disabled: this.isDisabled(date),
  1352. past: time < 0,
  1353. current: time === 0,
  1354. future: time > 0,
  1355. customClass: this.customClass(date) || null
  1356. };
  1357. if (model && this.compare(date, model) === 0) {
  1358. $scope.selectedDt = dt;
  1359. }
  1360. if (self.activeDate && this.compare(dt.date, self.activeDate) === 0) {
  1361. $scope.activeDt = dt;
  1362. }
  1363. return dt;
  1364. };
  1365. this.isDisabled = function(date) {
  1366. return $scope.disabled ||
  1367. this.minDate && this.compare(date, this.minDate) < 0 ||
  1368. this.maxDate && this.compare(date, this.maxDate) > 0 ||
  1369. $scope.dateDisabled && $scope.dateDisabled({date: date, mode: $scope.datepickerMode});
  1370. };
  1371. this.customClass = function(date) {
  1372. return $scope.customClass({date: date, mode: $scope.datepickerMode});
  1373. };
  1374. // Split array into smaller arrays
  1375. this.split = function(arr, size) {
  1376. var arrays = [];
  1377. while (arr.length > 0) {
  1378. arrays.push(arr.splice(0, size));
  1379. }
  1380. return arrays;
  1381. };
  1382. $scope.select = function(date) {
  1383. if ($scope.datepickerMode === self.minMode) {
  1384. var dt = ngModelCtrl.$viewValue ? dateParser.fromTimezone(new Date(ngModelCtrl.$viewValue), ngModelOptions.timezone) : new Date(0, 0, 0, 0, 0, 0, 0);
  1385. dt.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
  1386. dt = dateParser.toTimezone(dt, ngModelOptions.timezone);
  1387. ngModelCtrl.$setViewValue(dt);
  1388. ngModelCtrl.$render();
  1389. } else {
  1390. self.activeDate = date;
  1391. setMode(self.modes[self.modes.indexOf($scope.datepickerMode) - 1]);
  1392. $scope.$emit('uib:datepicker.mode');
  1393. }
  1394. $scope.$broadcast('uib:datepicker.focus');
  1395. };
  1396. $scope.move = function(direction) {
  1397. var year = self.activeDate.getFullYear() + direction * (self.step.years || 0),
  1398. month = self.activeDate.getMonth() + direction * (self.step.months || 0);
  1399. self.activeDate.setFullYear(year, month, 1);
  1400. self.refreshView();
  1401. };
  1402. $scope.toggleMode = function(direction) {
  1403. direction = direction || 1;
  1404. if ($scope.datepickerMode === self.maxMode && direction === 1 ||
  1405. $scope.datepickerMode === self.minMode && direction === -1) {
  1406. return;
  1407. }
  1408. setMode(self.modes[self.modes.indexOf($scope.datepickerMode) + direction]);
  1409. $scope.$emit('uib:datepicker.mode');
  1410. };
  1411. // Key event mapper
  1412. $scope.keys = { 13: 'enter', 32: 'space', 33: 'pageup', 34: 'pagedown', 35: 'end', 36: 'home', 37: 'left', 38: 'up', 39: 'right', 40: 'down' };
  1413. var focusElement = function() {
  1414. self.element[0].focus();
  1415. };
  1416. // Listen for focus requests from popup directive
  1417. $scope.$on('uib:datepicker.focus', focusElement);
  1418. $scope.keydown = function(evt) {
  1419. var key = $scope.keys[evt.which];
  1420. if (!key || evt.shiftKey || evt.altKey || $scope.disabled) {
  1421. return;
  1422. }
  1423. evt.preventDefault();
  1424. if (!self.shortcutPropagation) {
  1425. evt.stopPropagation();
  1426. }
  1427. if (key === 'enter' || key === 'space') {
  1428. if (self.isDisabled(self.activeDate)) {
  1429. return; // do nothing
  1430. }
  1431. $scope.select(self.activeDate);
  1432. } else if (evt.ctrlKey && (key === 'up' || key === 'down')) {
  1433. $scope.toggleMode(key === 'up' ? 1 : -1);
  1434. } else {
  1435. self.handleKeyDown(key, evt);
  1436. self.refreshView();
  1437. }
  1438. };
  1439. $scope.$on('$destroy', function() {
  1440. //Clear all watch listeners on destroy
  1441. while (watchListeners.length) {
  1442. watchListeners.shift()();
  1443. }
  1444. });
  1445. function setMode(mode) {
  1446. $scope.datepickerMode = mode;
  1447. $scope.datepickerOptions.datepickerMode = mode;
  1448. }
  1449. }])
  1450. .controller('UibDaypickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
  1451. var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  1452. this.step = { months: 1 };
  1453. this.element = $element;
  1454. function getDaysInMonth(year, month) {
  1455. return month === 1 && year % 4 === 0 &&
  1456. (year % 100 !== 0 || year % 400 === 0) ? 29 : DAYS_IN_MONTH[month];
  1457. }
  1458. this.init = function(ctrl) {
  1459. angular.extend(ctrl, this);
  1460. scope.showWeeks = ctrl.showWeeks;
  1461. ctrl.refreshView();
  1462. };
  1463. this.getDates = function(startDate, n) {
  1464. var dates = new Array(n), current = new Date(startDate), i = 0, date;
  1465. while (i < n) {
  1466. date = new Date(current);
  1467. dates[i++] = date;
  1468. current.setDate(current.getDate() + 1);
  1469. }
  1470. return dates;
  1471. };
  1472. this._refreshView = function() {
  1473. var year = this.activeDate.getFullYear(),
  1474. month = this.activeDate.getMonth(),
  1475. firstDayOfMonth = new Date(this.activeDate);
  1476. firstDayOfMonth.setFullYear(year, month, 1);
  1477. var difference = this.startingDay - firstDayOfMonth.getDay(),
  1478. numDisplayedFromPreviousMonth = difference > 0 ?
  1479. 7 - difference : - difference,
  1480. firstDate = new Date(firstDayOfMonth);
  1481. if (numDisplayedFromPreviousMonth > 0) {
  1482. firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
  1483. }
  1484. // 42 is the number of days on a six-week calendar
  1485. var days = this.getDates(firstDate, 42);
  1486. for (var i = 0; i < 42; i ++) {
  1487. days[i] = angular.extend(this.createDateObject(days[i], this.formatDay), {
  1488. secondary: days[i].getMonth() !== month,
  1489. uid: scope.uniqueId + '-' + i
  1490. });
  1491. }
  1492. scope.labels = new Array(7);
  1493. for (var j = 0; j < 7; j++) {
  1494. scope.labels[j] = {
  1495. abbr: dateFilter(days[j].date, this.formatDayHeader),
  1496. full: dateFilter(days[j].date, 'EEEE')
  1497. };
  1498. }
  1499. scope.title = dateFilter(this.activeDate, this.formatDayTitle);
  1500. scope.rows = this.split(days, 7);
  1501. if (scope.showWeeks) {
  1502. scope.weekNumbers = [];
  1503. var thursdayIndex = (4 + 7 - this.startingDay) % 7,
  1504. numWeeks = scope.rows.length;
  1505. for (var curWeek = 0; curWeek < numWeeks; curWeek++) {
  1506. scope.weekNumbers.push(
  1507. getISO8601WeekNumber(scope.rows[curWeek][thursdayIndex].date));
  1508. }
  1509. }
  1510. };
  1511. this.compare = function(date1, date2) {
  1512. var _date1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
  1513. var _date2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
  1514. _date1.setFullYear(date1.getFullYear());
  1515. _date2.setFullYear(date2.getFullYear());
  1516. return _date1 - _date2;
  1517. };
  1518. function getISO8601WeekNumber(date) {
  1519. var checkDate = new Date(date);
  1520. checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday
  1521. var time = checkDate.getTime();
  1522. checkDate.setMonth(0); // Compare with Jan 1
  1523. checkDate.setDate(1);
  1524. return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
  1525. }
  1526. this.handleKeyDown = function(key, evt) {
  1527. var date = this.activeDate.getDate();
  1528. if (key === 'left') {
  1529. date = date - 1;
  1530. } else if (key === 'up') {
  1531. date = date - 7;
  1532. } else if (key === 'right') {
  1533. date = date + 1;
  1534. } else if (key === 'down') {
  1535. date = date + 7;
  1536. } else if (key === 'pageup' || key === 'pagedown') {
  1537. var month = this.activeDate.getMonth() + (key === 'pageup' ? - 1 : 1);
  1538. this.activeDate.setMonth(month, 1);
  1539. date = Math.min(getDaysInMonth(this.activeDate.getFullYear(), this.activeDate.getMonth()), date);
  1540. } else if (key === 'home') {
  1541. date = 1;
  1542. } else if (key === 'end') {
  1543. date = getDaysInMonth(this.activeDate.getFullYear(), this.activeDate.getMonth());
  1544. }
  1545. this.activeDate.setDate(date);
  1546. };
  1547. }])
  1548. .controller('UibMonthpickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
  1549. this.step = { years: 1 };
  1550. this.element = $element;
  1551. this.init = function(ctrl) {
  1552. angular.extend(ctrl, this);
  1553. ctrl.refreshView();
  1554. };
  1555. this._refreshView = function() {
  1556. var months = new Array(12),
  1557. year = this.activeDate.getFullYear(),
  1558. date;
  1559. for (var i = 0; i < 12; i++) {
  1560. date = new Date(this.activeDate);
  1561. date.setFullYear(year, i, 1);
  1562. months[i] = angular.extend(this.createDateObject(date, this.formatMonth), {
  1563. uid: scope.uniqueId + '-' + i
  1564. });
  1565. }
  1566. scope.title = dateFilter(this.activeDate, this.formatMonthTitle);
  1567. scope.rows = this.split(months, 3);
  1568. };
  1569. this.compare = function(date1, date2) {
  1570. var _date1 = new Date(date1.getFullYear(), date1.getMonth());
  1571. var _date2 = new Date(date2.getFullYear(), date2.getMonth());
  1572. _date1.setFullYear(date1.getFullYear());
  1573. _date2.setFullYear(date2.getFullYear());
  1574. return _date1 - _date2;
  1575. };
  1576. this.handleKeyDown = function(key, evt) {
  1577. var date = this.activeDate.getMonth();
  1578. if (key === 'left') {
  1579. date = date - 1;
  1580. } else if (key === 'up') {
  1581. date = date - 3;
  1582. } else if (key === 'right') {
  1583. date = date + 1;
  1584. } else if (key === 'down') {
  1585. date = date + 3;
  1586. } else if (key === 'pageup' || key === 'pagedown') {
  1587. var year = this.activeDate.getFullYear() + (key === 'pageup' ? - 1 : 1);
  1588. this.activeDate.setFullYear(year);
  1589. } else if (key === 'home') {
  1590. date = 0;
  1591. } else if (key === 'end') {
  1592. date = 11;
  1593. }
  1594. this.activeDate.setMonth(date);
  1595. };
  1596. }])
  1597. .controller('UibYearpickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
  1598. var columns, range;
  1599. this.element = $element;
  1600. function getStartingYear(year) {
  1601. return parseInt((year - 1) / range, 10) * range + 1;
  1602. }
  1603. this.yearpickerInit = function() {
  1604. columns = this.yearColumns;
  1605. range = this.yearRows * columns;
  1606. this.step = { years: range };
  1607. };
  1608. this._refreshView = function() {
  1609. var years = new Array(range), date;
  1610. for (var i = 0, start = getStartingYear(this.activeDate.getFullYear()); i < range; i++) {
  1611. date = new Date(this.activeDate);
  1612. date.setFullYear(start + i, 0, 1);
  1613. years[i] = angular.extend(this.createDateObject(date, this.formatYear), {
  1614. uid: scope.uniqueId + '-' + i
  1615. });
  1616. }
  1617. scope.title = [years[0].label, years[range - 1].label].join(' - ');
  1618. scope.rows = this.split(years, columns);
  1619. scope.columns = columns;
  1620. };
  1621. this.compare = function(date1, date2) {
  1622. return date1.getFullYear() - date2.getFullYear();
  1623. };
  1624. this.handleKeyDown = function(key, evt) {
  1625. var date = this.activeDate.getFullYear();
  1626. if (key === 'left') {
  1627. date = date - 1;
  1628. } else if (key === 'up') {
  1629. date = date - columns;
  1630. } else if (key === 'right') {
  1631. date = date + 1;
  1632. } else if (key === 'down') {
  1633. date = date + columns;
  1634. } else if (key === 'pageup' || key === 'pagedown') {
  1635. date += (key === 'pageup' ? - 1 : 1) * range;
  1636. } else if (key === 'home') {
  1637. date = getStartingYear(this.activeDate.getFullYear());
  1638. } else if (key === 'end') {
  1639. date = getStartingYear(this.activeDate.getFullYear()) + range - 1;
  1640. }
  1641. this.activeDate.setFullYear(date);
  1642. };
  1643. }])
  1644. .directive('uibDatepicker', function() {
  1645. return {
  1646. replace: true,
  1647. templateUrl: function(element, attrs) {
  1648. return attrs.templateUrl || 'uib/template/datepicker/datepicker.html';
  1649. },
  1650. scope: {
  1651. datepickerOptions: '=?'
  1652. },
  1653. require: ['uibDatepicker', '^ngModel'],
  1654. controller: 'UibDatepickerController',
  1655. controllerAs: 'datepicker',
  1656. link: function(scope, element, attrs, ctrls) {
  1657. var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
  1658. datepickerCtrl.init(ngModelCtrl);
  1659. }
  1660. };
  1661. })
  1662. .directive('uibDaypicker', function() {
  1663. return {
  1664. replace: true,
  1665. templateUrl: function(element, attrs) {
  1666. return attrs.templateUrl || 'uib/template/datepicker/day.html';
  1667. },
  1668. require: ['^uibDatepicker', 'uibDaypicker'],
  1669. controller: 'UibDaypickerController',
  1670. link: function(scope, element, attrs, ctrls) {
  1671. var datepickerCtrl = ctrls[0],
  1672. daypickerCtrl = ctrls[1];
  1673. daypickerCtrl.init(datepickerCtrl);
  1674. }
  1675. };
  1676. })
  1677. .directive('uibMonthpicker', function() {
  1678. return {
  1679. replace: true,
  1680. templateUrl: function(element, attrs) {
  1681. return attrs.templateUrl || 'uib/template/datepicker/month.html';
  1682. },
  1683. require: ['^uibDatepicker', 'uibMonthpicker'],
  1684. controller: 'UibMonthpickerController',
  1685. link: function(scope, element, attrs, ctrls) {
  1686. var datepickerCtrl = ctrls[0],
  1687. monthpickerCtrl = ctrls[1];
  1688. monthpickerCtrl.init(datepickerCtrl);
  1689. }
  1690. };
  1691. })
  1692. .directive('uibYearpicker', function() {
  1693. return {
  1694. replace: true,
  1695. templateUrl: function(element, attrs) {
  1696. return attrs.templateUrl || 'uib/template/datepicker/year.html';
  1697. },
  1698. require: ['^uibDatepicker', 'uibYearpicker'],
  1699. controller: 'UibYearpickerController',
  1700. link: function(scope, element, attrs, ctrls) {
  1701. var ctrl = ctrls[0];
  1702. angular.extend(ctrl, ctrls[1]);
  1703. ctrl.yearpickerInit();
  1704. ctrl.refreshView();
  1705. }
  1706. };
  1707. });
  1708. angular.module('ui.bootstrap.position', [])
  1709. /**
  1710. * A set of utility methods for working with the DOM.
  1711. * It is meant to be used where we need to absolute-position elements in
  1712. * relation to another element (this is the case for tooltips, popovers,
  1713. * typeahead suggestions etc.).
  1714. */
  1715. .factory('$uibPosition', ['$document', '$window', function($document, $window) {
  1716. /**
  1717. * Used by scrollbarWidth() function to cache scrollbar's width.
  1718. * Do not access this variable directly, use scrollbarWidth() instead.
  1719. */
  1720. var SCROLLBAR_WIDTH;
  1721. /**
  1722. * scrollbar on body and html element in IE and Edge overlay
  1723. * content and should be considered 0 width.
  1724. */
  1725. var BODY_SCROLLBAR_WIDTH;
  1726. var OVERFLOW_REGEX = {
  1727. normal: /(auto|scroll)/,
  1728. hidden: /(auto|scroll|hidden)/
  1729. };
  1730. var PLACEMENT_REGEX = {
  1731. auto: /\s?auto?\s?/i,
  1732. primary: /^(top|bottom|left|right)$/,
  1733. secondary: /^(top|bottom|left|right|center)$/,
  1734. vertical: /^(top|bottom)$/
  1735. };
  1736. var BODY_REGEX = /(HTML|BODY)/;
  1737. return {
  1738. /**
  1739. * Provides a raw DOM element from a jQuery/jQLite element.
  1740. *
  1741. * @param {element} elem - The element to convert.
  1742. *
  1743. * @returns {element} A HTML element.
  1744. */
  1745. getRawNode: function(elem) {
  1746. return elem.nodeName ? elem : elem[0] || elem;
  1747. },
  1748. /**
  1749. * Provides a parsed number for a style property. Strips
  1750. * units and casts invalid numbers to 0.
  1751. *
  1752. * @param {string} value - The style value to parse.
  1753. *
  1754. * @returns {number} A valid number.
  1755. */
  1756. parseStyle: function(value) {
  1757. value = parseFloat(value);
  1758. return isFinite(value) ? value : 0;
  1759. },
  1760. /**
  1761. * Provides the closest positioned ancestor.
  1762. *
  1763. * @param {element} element - The element to get the offest parent for.
  1764. *
  1765. * @returns {element} The closest positioned ancestor.
  1766. */
  1767. offsetParent: function(elem) {
  1768. elem = this.getRawNode(elem);
  1769. var offsetParent = elem.offsetParent || $document[0].documentElement;
  1770. function isStaticPositioned(el) {
  1771. return ($window.getComputedStyle(el).position || 'static') === 'static';
  1772. }
  1773. while (offsetParent && offsetParent !== $document[0].documentElement && isStaticPositioned(offsetParent)) {
  1774. offsetParent = offsetParent.offsetParent;
  1775. }
  1776. return offsetParent || $document[0].documentElement;
  1777. },
  1778. /**
  1779. * Provides the scrollbar width, concept from TWBS measureScrollbar()
  1780. * function in https://github.com/twbs/bootstrap/blob/master/js/modal.js
  1781. * In IE and Edge, scollbar on body and html element overlay and should
  1782. * return a width of 0.
  1783. *
  1784. * @returns {number} The width of the browser scollbar.
  1785. */
  1786. scrollbarWidth: function(isBody) {
  1787. if (isBody) {
  1788. if (angular.isUndefined(BODY_SCROLLBAR_WIDTH)) {
  1789. var bodyElem = $document.find('body');
  1790. bodyElem.addClass('uib-position-body-scrollbar-measure');
  1791. BODY_SCROLLBAR_WIDTH = $window.innerWidth - bodyElem[0].clientWidth;
  1792. BODY_SCROLLBAR_WIDTH = isFinite(BODY_SCROLLBAR_WIDTH) ? BODY_SCROLLBAR_WIDTH : 0;
  1793. bodyElem.removeClass('uib-position-body-scrollbar-measure');
  1794. }
  1795. return BODY_SCROLLBAR_WIDTH;
  1796. }
  1797. if (angular.isUndefined(SCROLLBAR_WIDTH)) {
  1798. var scrollElem = angular.element('<div class="uib-position-scrollbar-measure"></div>');
  1799. $document.find('body').append(scrollElem);
  1800. SCROLLBAR_WIDTH = scrollElem[0].offsetWidth - scrollElem[0].clientWidth;
  1801. SCROLLBAR_WIDTH = isFinite(SCROLLBAR_WIDTH) ? SCROLLBAR_WIDTH : 0;
  1802. scrollElem.remove();
  1803. }
  1804. return SCROLLBAR_WIDTH;
  1805. },
  1806. /**
  1807. * Provides the padding required on an element to replace the scrollbar.
  1808. *
  1809. * @returns {object} An object with the following properties:
  1810. * <ul>
  1811. * <li>**scrollbarWidth**: the width of the scrollbar</li>
  1812. * <li>**widthOverflow**: whether the the width is overflowing</li>
  1813. * <li>**right**: the amount of right padding on the element needed to replace the scrollbar</li>
  1814. * <li>**rightOriginal**: the amount of right padding currently on the element</li>
  1815. * <li>**heightOverflow**: whether the the height is overflowing</li>
  1816. * <li>**bottom**: the amount of bottom padding on the element needed to replace the scrollbar</li>
  1817. * <li>**bottomOriginal**: the amount of bottom padding currently on the element</li>
  1818. * </ul>
  1819. */
  1820. scrollbarPadding: function(elem) {
  1821. elem = this.getRawNode(elem);
  1822. var elemStyle = $window.getComputedStyle(elem);
  1823. var paddingRight = this.parseStyle(elemStyle.paddingRight);
  1824. var paddingBottom = this.parseStyle(elemStyle.paddingBottom);
  1825. var scrollParent = this.scrollParent(elem, false, true);
  1826. var scrollbarWidth = this.scrollbarWidth(scrollParent, BODY_REGEX.test(scrollParent.tagName));
  1827. return {
  1828. scrollbarWidth: scrollbarWidth,
  1829. widthOverflow: scrollParent.scrollWidth > scrollParent.clientWidth,
  1830. right: paddingRight + scrollbarWidth,
  1831. originalRight: paddingRight,
  1832. heightOverflow: scrollParent.scrollHeight > scrollParent.clientHeight,
  1833. bottom: paddingBottom + scrollbarWidth,
  1834. originalBottom: paddingBottom
  1835. };
  1836. },
  1837. /**
  1838. * Checks to see if the element is scrollable.
  1839. *
  1840. * @param {element} elem - The element to check.
  1841. * @param {boolean=} [includeHidden=false] - Should scroll style of 'hidden' be considered,
  1842. * default is false.
  1843. *
  1844. * @returns {boolean} Whether the element is scrollable.
  1845. */
  1846. isScrollable: function(elem, includeHidden) {
  1847. elem = this.getRawNode(elem);
  1848. var overflowRegex = includeHidden ? OVERFLOW_REGEX.hidden : OVERFLOW_REGEX.normal;
  1849. var elemStyle = $window.getComputedStyle(elem);
  1850. return overflowRegex.test(elemStyle.overflow + elemStyle.overflowY + elemStyle.overflowX);
  1851. },
  1852. /**
  1853. * Provides the closest scrollable ancestor.
  1854. * A port of the jQuery UI scrollParent method:
  1855. * https://github.com/jquery/jquery-ui/blob/master/ui/scroll-parent.js
  1856. *
  1857. * @param {element} elem - The element to find the scroll parent of.
  1858. * @param {boolean=} [includeHidden=false] - Should scroll style of 'hidden' be considered,
  1859. * default is false.
  1860. * @param {boolean=} [includeSelf=false] - Should the element being passed be
  1861. * included in the scrollable llokup.
  1862. *
  1863. * @returns {element} A HTML element.
  1864. */
  1865. scrollParent: function(elem, includeHidden, includeSelf) {
  1866. elem = this.getRawNode(elem);
  1867. var overflowRegex = includeHidden ? OVERFLOW_REGEX.hidden : OVERFLOW_REGEX.normal;
  1868. var documentEl = $document[0].documentElement;
  1869. var elemStyle = $window.getComputedStyle(elem);
  1870. if (includeSelf && overflowRegex.test(elemStyle.overflow + elemStyle.overflowY + elemStyle.overflowX)) {
  1871. return elem;
  1872. }
  1873. var excludeStatic = elemStyle.position === 'absolute';
  1874. var scrollParent = elem.parentElement || documentEl;
  1875. if (scrollParent === documentEl || elemStyle.position === 'fixed') {
  1876. return documentEl;
  1877. }
  1878. while (scrollParent.parentElement && scrollParent !== documentEl) {
  1879. var spStyle = $window.getComputedStyle(scrollParent);
  1880. if (excludeStatic && spStyle.position !== 'static') {
  1881. excludeStatic = false;
  1882. }
  1883. if (!excludeStatic && overflowRegex.test(spStyle.overflow + spStyle.overflowY + spStyle.overflowX)) {
  1884. break;
  1885. }
  1886. scrollParent = scrollParent.parentElement;
  1887. }
  1888. return scrollParent;
  1889. },
  1890. /**
  1891. * Provides read-only equivalent of jQuery's position function:
  1892. * http://api.jquery.com/position/ - distance to closest positioned
  1893. * ancestor. Does not account for margins by default like jQuery position.
  1894. *
  1895. * @param {element} elem - The element to caclulate the position on.
  1896. * @param {boolean=} [includeMargins=false] - Should margins be accounted
  1897. * for, default is false.
  1898. *
  1899. * @returns {object} An object with the following properties:
  1900. * <ul>
  1901. * <li>**width**: the width of the element</li>
  1902. * <li>**height**: the height of the element</li>
  1903. * <li>**top**: distance to top edge of offset parent</li>
  1904. * <li>**left**: distance to left edge of offset parent</li>
  1905. * </ul>
  1906. */
  1907. position: function(elem, includeMagins) {
  1908. elem = this.getRawNode(elem);
  1909. var elemOffset = this.offset(elem);
  1910. if (includeMagins) {
  1911. var elemStyle = $window.getComputedStyle(elem);
  1912. elemOffset.top -= this.parseStyle(elemStyle.marginTop);
  1913. elemOffset.left -= this.parseStyle(elemStyle.marginLeft);
  1914. }
  1915. var parent = this.offsetParent(elem);
  1916. var parentOffset = {top: 0, left: 0};
  1917. if (parent !== $document[0].documentElement) {
  1918. parentOffset = this.offset(parent);
  1919. parentOffset.top += parent.clientTop - parent.scrollTop;
  1920. parentOffset.left += parent.clientLeft - parent.scrollLeft;
  1921. }
  1922. return {
  1923. width: Math.round(angular.isNumber(elemOffset.width) ? elemOffset.width : elem.offsetWidth),
  1924. height: Math.round(angular.isNumber(elemOffset.height) ? elemOffset.height : elem.offsetHeight),
  1925. top: Math.round(elemOffset.top - parentOffset.top),
  1926. left: Math.round(elemOffset.left - parentOffset.left)
  1927. };
  1928. },
  1929. /**
  1930. * Provides read-only equivalent of jQuery's offset function:
  1931. * http://api.jquery.com/offset/ - distance to viewport. Does
  1932. * not account for borders, margins, or padding on the body
  1933. * element.
  1934. *
  1935. * @param {element} elem - The element to calculate the offset on.
  1936. *
  1937. * @returns {object} An object with the following properties:
  1938. * <ul>
  1939. * <li>**width**: the width of the element</li>
  1940. * <li>**height**: the height of the element</li>
  1941. * <li>**top**: distance to top edge of viewport</li>
  1942. * <li>**right**: distance to bottom edge of viewport</li>
  1943. * </ul>
  1944. */
  1945. offset: function(elem) {
  1946. elem = this.getRawNode(elem);
  1947. var elemBCR = elem.getBoundingClientRect();
  1948. return {
  1949. width: Math.round(angular.isNumber(elemBCR.width) ? elemBCR.width : elem.offsetWidth),
  1950. height: Math.round(angular.isNumber(elemBCR.height) ? elemBCR.height : elem.offsetHeight),
  1951. top: Math.round(elemBCR.top + ($window.pageYOffset || $document[0].documentElement.scrollTop)),
  1952. left: Math.round(elemBCR.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft))
  1953. };
  1954. },
  1955. /**
  1956. * Provides offset distance to the closest scrollable ancestor
  1957. * or viewport. Accounts for border and scrollbar width.
  1958. *
  1959. * Right and bottom dimensions represent the distance to the
  1960. * respective edge of the viewport element. If the element
  1961. * edge extends beyond the viewport, a negative value will be
  1962. * reported.
  1963. *
  1964. * @param {element} elem - The element to get the viewport offset for.
  1965. * @param {boolean=} [useDocument=false] - Should the viewport be the document element instead
  1966. * of the first scrollable element, default is false.
  1967. * @param {boolean=} [includePadding=true] - Should the padding on the offset parent element
  1968. * be accounted for, default is true.
  1969. *
  1970. * @returns {object} An object with the following properties:
  1971. * <ul>
  1972. * <li>**top**: distance to the top content edge of viewport element</li>
  1973. * <li>**bottom**: distance to the bottom content edge of viewport element</li>
  1974. * <li>**left**: distance to the left content edge of viewport element</li>
  1975. * <li>**right**: distance to the right content edge of viewport element</li>
  1976. * </ul>
  1977. */
  1978. viewportOffset: function(elem, useDocument, includePadding) {
  1979. elem = this.getRawNode(elem);
  1980. includePadding = includePadding !== false ? true : false;
  1981. var elemBCR = elem.getBoundingClientRect();
  1982. var offsetBCR = {top: 0, left: 0, bottom: 0, right: 0};
  1983. var offsetParent = useDocument ? $document[0].documentElement : this.scrollParent(elem);
  1984. var offsetParentBCR = offsetParent.getBoundingClientRect();
  1985. offsetBCR.top = offsetParentBCR.top + offsetParent.clientTop;
  1986. offsetBCR.left = offsetParentBCR.left + offsetParent.clientLeft;
  1987. if (offsetParent === $document[0].documentElement) {
  1988. offsetBCR.top += $window.pageYOffset;
  1989. offsetBCR.left += $window.pageXOffset;
  1990. }
  1991. offsetBCR.bottom = offsetBCR.top + offsetParent.clientHeight;
  1992. offsetBCR.right = offsetBCR.left + offsetParent.clientWidth;
  1993. if (includePadding) {
  1994. var offsetParentStyle = $window.getComputedStyle(offsetParent);
  1995. offsetBCR.top += this.parseStyle(offsetParentStyle.paddingTop);
  1996. offsetBCR.bottom -= this.parseStyle(offsetParentStyle.paddingBottom);
  1997. offsetBCR.left += this.parseStyle(offsetParentStyle.paddingLeft);
  1998. offsetBCR.right -= this.parseStyle(offsetParentStyle.paddingRight);
  1999. }
  2000. return {
  2001. top: Math.round(elemBCR.top - offsetBCR.top),
  2002. bottom: Math.round(offsetBCR.bottom - elemBCR.bottom),
  2003. left: Math.round(elemBCR.left - offsetBCR.left),
  2004. right: Math.round(offsetBCR.right - elemBCR.right)
  2005. };
  2006. },
  2007. /**
  2008. * Provides an array of placement values parsed from a placement string.
  2009. * Along with the 'auto' indicator, supported placement strings are:
  2010. * <ul>
  2011. * <li>top: element on top, horizontally centered on host element.</li>
  2012. * <li>top-left: element on top, left edge aligned with host element left edge.</li>
  2013. * <li>top-right: element on top, lerightft edge aligned with host element right edge.</li>
  2014. * <li>bottom: element on bottom, horizontally centered on host element.</li>
  2015. * <li>bottom-left: element on bottom, left edge aligned with host element left edge.</li>
  2016. * <li>bottom-right: element on bottom, right edge aligned with host element right edge.</li>
  2017. * <li>left: element on left, vertically centered on host element.</li>
  2018. * <li>left-top: element on left, top edge aligned with host element top edge.</li>
  2019. * <li>left-bottom: element on left, bottom edge aligned with host element bottom edge.</li>
  2020. * <li>right: element on right, vertically centered on host element.</li>
  2021. * <li>right-top: element on right, top edge aligned with host element top edge.</li>
  2022. * <li>right-bottom: element on right, bottom edge aligned with host element bottom edge.</li>
  2023. * </ul>
  2024. * A placement string with an 'auto' indicator is expected to be
  2025. * space separated from the placement, i.e: 'auto bottom-left' If
  2026. * the primary and secondary placement values do not match 'top,
  2027. * bottom, left, right' then 'top' will be the primary placement and
  2028. * 'center' will be the secondary placement. If 'auto' is passed, true
  2029. * will be returned as the 3rd value of the array.
  2030. *
  2031. * @param {string} placement - The placement string to parse.
  2032. *
  2033. * @returns {array} An array with the following values
  2034. * <ul>
  2035. * <li>**[0]**: The primary placement.</li>
  2036. * <li>**[1]**: The secondary placement.</li>
  2037. * <li>**[2]**: If auto is passed: true, else undefined.</li>
  2038. * </ul>
  2039. */
  2040. parsePlacement: function(placement) {
  2041. var autoPlace = PLACEMENT_REGEX.auto.test(placement);
  2042. if (autoPlace) {
  2043. placement = placement.replace(PLACEMENT_REGEX.auto, '');
  2044. }
  2045. placement = placement.split('-');
  2046. placement[0] = placement[0] || 'top';
  2047. if (!PLACEMENT_REGEX.primary.test(placement[0])) {
  2048. placement[0] = 'top';
  2049. }
  2050. placement[1] = placement[1] || 'center';
  2051. if (!PLACEMENT_REGEX.secondary.test(placement[1])) {
  2052. placement[1] = 'center';
  2053. }
  2054. if (autoPlace) {
  2055. placement[2] = true;
  2056. } else {
  2057. placement[2] = false;
  2058. }
  2059. return placement;
  2060. },
  2061. /**
  2062. * Provides coordinates for an element to be positioned relative to
  2063. * another element. Passing 'auto' as part of the placement parameter
  2064. * will enable smart placement - where the element fits. i.e:
  2065. * 'auto left-top' will check to see if there is enough space to the left
  2066. * of the hostElem to fit the targetElem, if not place right (same for secondary
  2067. * top placement). Available space is calculated using the viewportOffset
  2068. * function.
  2069. *
  2070. * @param {element} hostElem - The element to position against.
  2071. * @param {element} targetElem - The element to position.
  2072. * @param {string=} [placement=top] - The placement for the targetElem,
  2073. * default is 'top'. 'center' is assumed as secondary placement for
  2074. * 'top', 'left', 'right', and 'bottom' placements. Available placements are:
  2075. * <ul>
  2076. * <li>top</li>
  2077. * <li>top-right</li>
  2078. * <li>top-left</li>
  2079. * <li>bottom</li>
  2080. * <li>bottom-left</li>
  2081. * <li>bottom-right</li>
  2082. * <li>left</li>
  2083. * <li>left-top</li>
  2084. * <li>left-bottom</li>
  2085. * <li>right</li>
  2086. * <li>right-top</li>
  2087. * <li>right-bottom</li>
  2088. * </ul>
  2089. * @param {boolean=} [appendToBody=false] - Should the top and left values returned
  2090. * be calculated from the body element, default is false.
  2091. *
  2092. * @returns {object} An object with the following properties:
  2093. * <ul>
  2094. * <li>**top**: Value for targetElem top.</li>
  2095. * <li>**left**: Value for targetElem left.</li>
  2096. * <li>**placement**: The resolved placement.</li>
  2097. * </ul>
  2098. */
  2099. positionElements: function(hostElem, targetElem, placement, appendToBody) {
  2100. hostElem = this.getRawNode(hostElem);
  2101. targetElem = this.getRawNode(targetElem);
  2102. // need to read from prop to support tests.
  2103. var targetWidth = angular.isDefined(targetElem.offsetWidth) ? targetElem.offsetWidth : targetElem.prop('offsetWidth');
  2104. var targetHeight = angular.isDefined(targetElem.offsetHeight) ? targetElem.offsetHeight : targetElem.prop('offsetHeight');
  2105. placement = this.parsePlacement(placement);
  2106. var hostElemPos = appendToBody ? this.offset(hostElem) : this.position(hostElem);
  2107. var targetElemPos = {top: 0, left: 0, placement: ''};
  2108. if (placement[2]) {
  2109. var viewportOffset = this.viewportOffset(hostElem, appendToBody);
  2110. var targetElemStyle = $window.getComputedStyle(targetElem);
  2111. var adjustedSize = {
  2112. width: targetWidth + Math.round(Math.abs(this.parseStyle(targetElemStyle.marginLeft) + this.parseStyle(targetElemStyle.marginRight))),
  2113. height: targetHeight + Math.round(Math.abs(this.parseStyle(targetElemStyle.marginTop) + this.parseStyle(targetElemStyle.marginBottom)))
  2114. };
  2115. placement[0] = placement[0] === 'top' && adjustedSize.height > viewportOffset.top && adjustedSize.height <= viewportOffset.bottom ? 'bottom' :
  2116. placement[0] === 'bottom' && adjustedSize.height > viewportOffset.bottom && adjustedSize.height <= viewportOffset.top ? 'top' :
  2117. placement[0] === 'left' && adjustedSize.width > viewportOffset.left && adjustedSize.width <= viewportOffset.right ? 'right' :
  2118. placement[0] === 'right' && adjustedSize.width > viewportOffset.right && adjustedSize.width <= viewportOffset.left ? 'left' :
  2119. placement[0];
  2120. placement[1] = placement[1] === 'top' && adjustedSize.height - hostElemPos.height > viewportOffset.bottom && adjustedSize.height - hostElemPos.height <= viewportOffset.top ? 'bottom' :
  2121. placement[1] === 'bottom' && adjustedSize.height - hostElemPos.height > viewportOffset.top && adjustedSize.height - hostElemPos.height <= viewportOffset.bottom ? 'top' :
  2122. placement[1] === 'left' && adjustedSize.width - hostElemPos.width > viewportOffset.right && adjustedSize.width - hostElemPos.width <= viewportOffset.left ? 'right' :
  2123. placement[1] === 'right' && adjustedSize.width - hostElemPos.width > viewportOffset.left && adjustedSize.width - hostElemPos.width <= viewportOffset.right ? 'left' :
  2124. placement[1];
  2125. if (placement[1] === 'center') {
  2126. if (PLACEMENT_REGEX.vertical.test(placement[0])) {
  2127. var xOverflow = hostElemPos.width / 2 - targetWidth / 2;
  2128. if (viewportOffset.left + xOverflow < 0 && adjustedSize.width - hostElemPos.width <= viewportOffset.right) {
  2129. placement[1] = 'left';
  2130. } else if (viewportOffset.right + xOverflow < 0 && adjustedSize.width - hostElemPos.width <= viewportOffset.left) {
  2131. placement[1] = 'right';
  2132. }
  2133. } else {
  2134. var yOverflow = hostElemPos.height / 2 - adjustedSize.height / 2;
  2135. if (viewportOffset.top + yOverflow < 0 && adjustedSize.height - hostElemPos.height <= viewportOffset.bottom) {
  2136. placement[1] = 'top';
  2137. } else if (viewportOffset.bottom + yOverflow < 0 && adjustedSize.height - hostElemPos.height <= viewportOffset.top) {
  2138. placement[1] = 'bottom';
  2139. }
  2140. }
  2141. }
  2142. }
  2143. switch (placement[0]) {
  2144. case 'top':
  2145. targetElemPos.top = hostElemPos.top - targetHeight;
  2146. break;
  2147. case 'bottom':
  2148. targetElemPos.top = hostElemPos.top + hostElemPos.height;
  2149. break;
  2150. case 'left':
  2151. targetElemPos.left = hostElemPos.left - targetWidth;
  2152. break;
  2153. case 'right':
  2154. targetElemPos.left = hostElemPos.left + hostElemPos.width;
  2155. break;
  2156. }
  2157. switch (placement[1]) {
  2158. case 'top':
  2159. targetElemPos.top = hostElemPos.top;
  2160. break;
  2161. case 'bottom':
  2162. targetElemPos.top = hostElemPos.top + hostElemPos.height - targetHeight;
  2163. break;
  2164. case 'left':
  2165. targetElemPos.left = hostElemPos.left;
  2166. break;
  2167. case 'right':
  2168. targetElemPos.left = hostElemPos.left + hostElemPos.width - targetWidth;
  2169. break;
  2170. case 'center':
  2171. if (PLACEMENT_REGEX.vertical.test(placement[0])) {
  2172. targetElemPos.left = hostElemPos.left + hostElemPos.width / 2 - targetWidth / 2;
  2173. } else {
  2174. targetElemPos.top = hostElemPos.top + hostElemPos.height / 2 - targetHeight / 2;
  2175. }
  2176. break;
  2177. }
  2178. targetElemPos.top = Math.round(targetElemPos.top);
  2179. targetElemPos.left = Math.round(targetElemPos.left);
  2180. targetElemPos.placement = placement[1] === 'center' ? placement[0] : placement[0] + '-' + placement[1];
  2181. return targetElemPos;
  2182. },
  2183. /**
  2184. * Provides a way for positioning tooltip & dropdown
  2185. * arrows when using placement options beyond the standard
  2186. * left, right, top, or bottom.
  2187. *
  2188. * @param {element} elem - The tooltip/dropdown element.
  2189. * @param {string} placement - The placement for the elem.
  2190. */
  2191. positionArrow: function(elem, placement) {
  2192. elem = this.getRawNode(elem);
  2193. var innerElem = elem.querySelector('.tooltip-inner, .popover-inner');
  2194. if (!innerElem) {
  2195. return;
  2196. }
  2197. var isTooltip = angular.element(innerElem).hasClass('tooltip-inner');
  2198. var arrowElem = isTooltip ? elem.querySelector('.tooltip-arrow') : elem.querySelector('.arrow');
  2199. if (!arrowElem) {
  2200. return;
  2201. }
  2202. var arrowCss = {
  2203. top: '',
  2204. bottom: '',
  2205. left: '',
  2206. right: ''
  2207. };
  2208. placement = this.parsePlacement(placement);
  2209. if (placement[1] === 'center') {
  2210. // no adjustment necessary - just reset styles
  2211. angular.element(arrowElem).css(arrowCss);
  2212. return;
  2213. }
  2214. var borderProp = 'border-' + placement[0] + '-width';
  2215. var borderWidth = $window.getComputedStyle(arrowElem)[borderProp];
  2216. var borderRadiusProp = 'border-';
  2217. if (PLACEMENT_REGEX.vertical.test(placement[0])) {
  2218. borderRadiusProp += placement[0] + '-' + placement[1];
  2219. } else {
  2220. borderRadiusProp += placement[1] + '-' + placement[0];
  2221. }
  2222. borderRadiusProp += '-radius';
  2223. var borderRadius = $window.getComputedStyle(isTooltip ? innerElem : elem)[borderRadiusProp];
  2224. switch (placement[0]) {
  2225. case 'top':
  2226. arrowCss.bottom = isTooltip ? '0' : '-' + borderWidth;
  2227. break;
  2228. case 'bottom':
  2229. arrowCss.top = isTooltip ? '0' : '-' + borderWidth;
  2230. break;
  2231. case 'left':
  2232. arrowCss.right = isTooltip ? '0' : '-' + borderWidth;
  2233. break;
  2234. case 'right':
  2235. arrowCss.left = isTooltip ? '0' : '-' + borderWidth;
  2236. break;
  2237. }
  2238. arrowCss[placement[1]] = borderRadius;
  2239. angular.element(arrowElem).css(arrowCss);
  2240. }
  2241. };
  2242. }]);
  2243. angular.module('ui.bootstrap.datepickerPopup', ['ui.bootstrap.datepicker', 'ui.bootstrap.position'])
  2244. .value('$datepickerPopupLiteralWarning', true)
  2245. .constant('uibDatepickerPopupConfig', {
  2246. altInputFormats: [],
  2247. appendToBody: false,
  2248. clearText: 'Clear',
  2249. closeOnDateSelection: true,
  2250. closeText: 'Done',
  2251. currentText: 'Today',
  2252. datepickerPopup: 'yyyy-MM-dd',
  2253. datepickerPopupTemplateUrl: 'uib/template/datepickerPopup/popup.html',
  2254. datepickerTemplateUrl: 'uib/template/datepicker/datepicker.html',
  2255. html5Types: {
  2256. date: 'yyyy-MM-dd',
  2257. 'datetime-local': 'yyyy-MM-ddTHH:mm:ss.sss',
  2258. 'month': 'yyyy-MM'
  2259. },
  2260. onOpenFocus: true,
  2261. showButtonBar: true,
  2262. placement: 'auto bottom-left'
  2263. })
  2264. .controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$log', '$parse', '$window', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', 'uibDatepickerConfig', '$datepickerPopupLiteralWarning',
  2265. function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, datepickerConfig, $datepickerPopupLiteralWarning) {
  2266. var cache = {},
  2267. isHtml5DateInput = false;
  2268. var dateFormat, closeOnDateSelection, appendToBody, onOpenFocus,
  2269. datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl, scrollParentEl,
  2270. ngModel, ngModelOptions, $popup, altInputFormats, watchListeners = [],
  2271. timezone;
  2272. this.init = function(_ngModel_) {
  2273. ngModel = _ngModel_;
  2274. ngModelOptions = _ngModel_.$options;
  2275. closeOnDateSelection = angular.isDefined($attrs.closeOnDateSelection) ?
  2276. $scope.$parent.$eval($attrs.closeOnDateSelection) :
  2277. datepickerPopupConfig.closeOnDateSelection;
  2278. appendToBody = angular.isDefined($attrs.datepickerAppendToBody) ?
  2279. $scope.$parent.$eval($attrs.datepickerAppendToBody) :
  2280. datepickerPopupConfig.appendToBody;
  2281. onOpenFocus = angular.isDefined($attrs.onOpenFocus) ?
  2282. $scope.$parent.$eval($attrs.onOpenFocus) : datepickerPopupConfig.onOpenFocus;
  2283. datepickerPopupTemplateUrl = angular.isDefined($attrs.datepickerPopupTemplateUrl) ?
  2284. $attrs.datepickerPopupTemplateUrl :
  2285. datepickerPopupConfig.datepickerPopupTemplateUrl;
  2286. datepickerTemplateUrl = angular.isDefined($attrs.datepickerTemplateUrl) ?
  2287. $attrs.datepickerTemplateUrl : datepickerPopupConfig.datepickerTemplateUrl;
  2288. altInputFormats = angular.isDefined($attrs.altInputFormats) ?
  2289. $scope.$parent.$eval($attrs.altInputFormats) :
  2290. datepickerPopupConfig.altInputFormats;
  2291. $scope.showButtonBar = angular.isDefined($attrs.showButtonBar) ?
  2292. $scope.$parent.$eval($attrs.showButtonBar) :
  2293. datepickerPopupConfig.showButtonBar;
  2294. if (datepickerPopupConfig.html5Types[$attrs.type]) {
  2295. dateFormat = datepickerPopupConfig.html5Types[$attrs.type];
  2296. isHtml5DateInput = true;
  2297. } else {
  2298. dateFormat = $attrs.uibDatepickerPopup || datepickerPopupConfig.datepickerPopup;
  2299. $attrs.$observe('uibDatepickerPopup', function(value, oldValue) {
  2300. var newDateFormat = value || datepickerPopupConfig.datepickerPopup;
  2301. // Invalidate the $modelValue to ensure that formatters re-run
  2302. // FIXME: Refactor when PR is merged: https://github.com/angular/angular.js/pull/10764
  2303. if (newDateFormat !== dateFormat) {
  2304. dateFormat = newDateFormat;
  2305. ngModel.$modelValue = null;
  2306. if (!dateFormat) {
  2307. throw new Error('uibDatepickerPopup must have a date format specified.');
  2308. }
  2309. }
  2310. });
  2311. }
  2312. if (!dateFormat) {
  2313. throw new Error('uibDatepickerPopup must have a date format specified.');
  2314. }
  2315. if (isHtml5DateInput && $attrs.uibDatepickerPopup) {
  2316. throw new Error('HTML5 date input types do not support custom formats.');
  2317. }
  2318. // popup element used to display calendar
  2319. popupEl = angular.element('<div uib-datepicker-popup-wrap><div uib-datepicker></div></div>');
  2320. if (ngModelOptions) {
  2321. timezone = ngModelOptions.timezone;
  2322. $scope.ngModelOptions = angular.copy(ngModelOptions);
  2323. $scope.ngModelOptions.timezone = null;
  2324. if ($scope.ngModelOptions.updateOnDefault === true) {
  2325. $scope.ngModelOptions.updateOn = $scope.ngModelOptions.updateOn ?
  2326. $scope.ngModelOptions.updateOn + ' default' : 'default';
  2327. }
  2328. popupEl.attr('ng-model-options', 'ngModelOptions');
  2329. } else {
  2330. timezone = null;
  2331. }
  2332. popupEl.attr({
  2333. 'ng-model': 'date',
  2334. 'ng-change': 'dateSelection(date)',
  2335. 'template-url': datepickerPopupTemplateUrl
  2336. });
  2337. // datepicker element
  2338. datepickerEl = angular.element(popupEl.children()[0]);
  2339. datepickerEl.attr('template-url', datepickerTemplateUrl);
  2340. if (!$scope.datepickerOptions) {
  2341. $scope.datepickerOptions = {};
  2342. }
  2343. if (isHtml5DateInput) {
  2344. if ($attrs.type === 'month') {
  2345. $scope.datepickerOptions.datepickerMode = 'month';
  2346. $scope.datepickerOptions.minMode = 'month';
  2347. }
  2348. }
  2349. datepickerEl.attr('datepicker-options', 'datepickerOptions');
  2350. if (!isHtml5DateInput) {
  2351. // Internal API to maintain the correct ng-invalid-[key] class
  2352. ngModel.$$parserName = 'date';
  2353. ngModel.$validators.date = validator;
  2354. ngModel.$parsers.unshift(parseDate);
  2355. ngModel.$formatters.push(function(value) {
  2356. if (ngModel.$isEmpty(value)) {
  2357. $scope.date = value;
  2358. return value;
  2359. }
  2360. if (angular.isNumber(value)) {
  2361. value = new Date(value);
  2362. }
  2363. $scope.date = dateParser.fromTimezone(value, timezone);
  2364. return dateParser.filter($scope.date, dateFormat);
  2365. });
  2366. } else {
  2367. ngModel.$formatters.push(function(value) {
  2368. $scope.date = dateParser.fromTimezone(value, timezone);
  2369. return value;
  2370. });
  2371. }
  2372. // Detect changes in the view from the text box
  2373. ngModel.$viewChangeListeners.push(function() {
  2374. $scope.date = parseDateString(ngModel.$viewValue);
  2375. });
  2376. $element.on('keydown', inputKeydownBind);
  2377. $popup = $compile(popupEl)($scope);
  2378. // Prevent jQuery cache memory leak (template is now redundant after linking)
  2379. popupEl.remove();
  2380. if (appendToBody) {
  2381. $document.find('body').append($popup);
  2382. } else {
  2383. $element.after($popup);
  2384. }
  2385. $scope.$on('$destroy', function() {
  2386. if ($scope.isOpen === true) {
  2387. if (!$rootScope.$$phase) {
  2388. $scope.$apply(function() {
  2389. $scope.isOpen = false;
  2390. });
  2391. }
  2392. }
  2393. $popup.remove();
  2394. $element.off('keydown', inputKeydownBind);
  2395. $document.off('click', documentClickBind);
  2396. if (scrollParentEl) {
  2397. scrollParentEl.off('scroll', positionPopup);
  2398. }
  2399. angular.element($window).off('resize', positionPopup);
  2400. //Clear all watch listeners on destroy
  2401. while (watchListeners.length) {
  2402. watchListeners.shift()();
  2403. }
  2404. });
  2405. };
  2406. $scope.getText = function(key) {
  2407. return $scope[key + 'Text'] || datepickerPopupConfig[key + 'Text'];
  2408. };
  2409. $scope.isDisabled = function(date) {
  2410. if (date === 'today') {
  2411. date = dateParser.fromTimezone(new Date(), timezone);
  2412. }
  2413. var dates = {};
  2414. angular.forEach(['minDate', 'maxDate'], function(key) {
  2415. if (!$scope.datepickerOptions[key]) {
  2416. dates[key] = null;
  2417. } else if (angular.isDate($scope.datepickerOptions[key])) {
  2418. dates[key] = dateParser.fromTimezone(new Date($scope.datepickerOptions[key]), timezone);
  2419. } else {
  2420. if ($datepickerPopupLiteralWarning) {
  2421. $log.warn('Literal date support has been deprecated, please switch to date object usage');
  2422. }
  2423. dates[key] = new Date(dateFilter($scope.datepickerOptions[key], 'medium'));
  2424. }
  2425. });
  2426. return $scope.datepickerOptions &&
  2427. dates.minDate && $scope.compare(date, dates.minDate) < 0 ||
  2428. dates.maxDate && $scope.compare(date, dates.maxDate) > 0;
  2429. };
  2430. $scope.compare = function(date1, date2) {
  2431. return new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
  2432. };
  2433. // Inner change
  2434. $scope.dateSelection = function(dt) {
  2435. if (angular.isDefined(dt)) {
  2436. $scope.date = dt;
  2437. }
  2438. var date = $scope.date ? dateParser.filter($scope.date, dateFormat) : null; // Setting to NULL is necessary for form validators to function
  2439. $element.val(date);
  2440. ngModel.$setViewValue(date);
  2441. if (closeOnDateSelection) {
  2442. $scope.isOpen = false;
  2443. $element[0].focus();
  2444. }
  2445. };
  2446. $scope.keydown = function(evt) {
  2447. if (evt.which === 27) {
  2448. evt.stopPropagation();
  2449. $scope.isOpen = false;
  2450. $element[0].focus();
  2451. }
  2452. };
  2453. $scope.select = function(date, evt) {
  2454. evt.stopPropagation();
  2455. if (date === 'today') {
  2456. var today = new Date();
  2457. if (angular.isDate($scope.date)) {
  2458. date = new Date($scope.date);
  2459. date.setFullYear(today.getFullYear(), today.getMonth(), today.getDate());
  2460. } else {
  2461. date = new Date(today.setHours(0, 0, 0, 0));
  2462. }
  2463. }
  2464. $scope.dateSelection(date);
  2465. };
  2466. $scope.close = function(evt) {
  2467. evt.stopPropagation();
  2468. $scope.isOpen = false;
  2469. $element[0].focus();
  2470. };
  2471. $scope.disabled = angular.isDefined($attrs.disabled) || false;
  2472. if ($attrs.ngDisabled) {
  2473. watchListeners.push($scope.$parent.$watch($parse($attrs.ngDisabled), function(disabled) {
  2474. $scope.disabled = disabled;
  2475. }));
  2476. }
  2477. $scope.$watch('isOpen', function(value) {
  2478. if (value) {
  2479. if (!$scope.disabled) {
  2480. $timeout(function() {
  2481. positionPopup();
  2482. if (onOpenFocus) {
  2483. $scope.$broadcast('uib:datepicker.focus');
  2484. }
  2485. $document.on('click', documentClickBind);
  2486. var placement = $attrs.popupPlacement ? $attrs.popupPlacement : datepickerPopupConfig.placement;
  2487. if (appendToBody || $position.parsePlacement(placement)[2]) {
  2488. scrollParentEl = scrollParentEl || angular.element($position.scrollParent($element));
  2489. if (scrollParentEl) {
  2490. scrollParentEl.on('scroll', positionPopup);
  2491. }
  2492. } else {
  2493. scrollParentEl = null;
  2494. }
  2495. angular.element($window).on('resize', positionPopup);
  2496. }, 0, false);
  2497. } else {
  2498. $scope.isOpen = false;
  2499. }
  2500. } else {
  2501. $document.off('click', documentClickBind);
  2502. if (scrollParentEl) {
  2503. scrollParentEl.off('scroll', positionPopup);
  2504. }
  2505. angular.element($window).off('resize', positionPopup);
  2506. }
  2507. });
  2508. function cameltoDash(string) {
  2509. return string.replace(/([A-Z])/g, function($1) { return '-' + $1.toLowerCase(); });
  2510. }
  2511. function parseDateString(viewValue) {
  2512. var date = dateParser.parse(viewValue, dateFormat, $scope.date);
  2513. if (isNaN(date)) {
  2514. for (var i = 0; i < altInputFormats.length; i++) {
  2515. date = dateParser.parse(viewValue, altInputFormats[i], $scope.date);
  2516. if (!isNaN(date)) {
  2517. return date;
  2518. }
  2519. }
  2520. }
  2521. return date;
  2522. }
  2523. function parseDate(viewValue) {
  2524. if (angular.isNumber(viewValue)) {
  2525. // presumably timestamp to date object
  2526. viewValue = new Date(viewValue);
  2527. }
  2528. if (!viewValue) {
  2529. return null;
  2530. }
  2531. if (angular.isDate(viewValue) && !isNaN(viewValue)) {
  2532. return viewValue;
  2533. }
  2534. if (angular.isString(viewValue)) {
  2535. var date = parseDateString(viewValue);
  2536. if (!isNaN(date)) {
  2537. return dateParser.toTimezone(date, timezone);
  2538. }
  2539. }
  2540. return ngModel.$options && ngModel.$options.allowInvalid ? viewValue : undefined;
  2541. }
  2542. function validator(modelValue, viewValue) {
  2543. var value = modelValue || viewValue;
  2544. if (!$attrs.ngRequired && !value) {
  2545. return true;
  2546. }
  2547. if (angular.isNumber(value)) {
  2548. value = new Date(value);
  2549. }
  2550. if (!value) {
  2551. return true;
  2552. }
  2553. if (angular.isDate(value) && !isNaN(value)) {
  2554. return true;
  2555. }
  2556. if (angular.isString(value)) {
  2557. return !isNaN(parseDateString(viewValue));
  2558. }
  2559. return false;
  2560. }
  2561. function documentClickBind(event) {
  2562. if (!$scope.isOpen && $scope.disabled) {
  2563. return;
  2564. }
  2565. var popup = $popup[0];
  2566. var dpContainsTarget = $element[0].contains(event.target);
  2567. // The popup node may not be an element node
  2568. // In some browsers (IE) only element nodes have the 'contains' function
  2569. var popupContainsTarget = popup.contains !== undefined && popup.contains(event.target);
  2570. if ($scope.isOpen && !(dpContainsTarget || popupContainsTarget)) {
  2571. $scope.$apply(function() {
  2572. $scope.isOpen = false;
  2573. });
  2574. }
  2575. }
  2576. function inputKeydownBind(evt) {
  2577. if (evt.which === 27 && $scope.isOpen) {
  2578. evt.preventDefault();
  2579. evt.stopPropagation();
  2580. $scope.$apply(function() {
  2581. $scope.isOpen = false;
  2582. });
  2583. $element[0].focus();
  2584. } else if (evt.which === 40 && !$scope.isOpen) {
  2585. evt.preventDefault();
  2586. evt.stopPropagation();
  2587. $scope.$apply(function() {
  2588. $scope.isOpen = true;
  2589. });
  2590. }
  2591. }
  2592. function positionPopup() {
  2593. if ($scope.isOpen) {
  2594. var dpElement = angular.element($popup[0].querySelector('.uib-datepicker-popup'));
  2595. var placement = $attrs.popupPlacement ? $attrs.popupPlacement : datepickerPopupConfig.placement;
  2596. var position = $position.positionElements($element, dpElement, placement, appendToBody);
  2597. dpElement.css({top: position.top + 'px', left: position.left + 'px'});
  2598. if (dpElement.hasClass('uib-position-measure')) {
  2599. dpElement.removeClass('uib-position-measure');
  2600. }
  2601. }
  2602. }
  2603. $scope.$on('uib:datepicker.mode', function() {
  2604. $timeout(positionPopup, 0, false);
  2605. });
  2606. }])
  2607. .directive('uibDatepickerPopup', function() {
  2608. return {
  2609. require: ['ngModel', 'uibDatepickerPopup'],
  2610. controller: 'UibDatepickerPopupController',
  2611. scope: {
  2612. datepickerOptions: '=?',
  2613. isOpen: '=?',
  2614. currentText: '@',
  2615. clearText: '@',
  2616. closeText: '@'
  2617. },
  2618. link: function(scope, element, attrs, ctrls) {
  2619. var ngModel = ctrls[0],
  2620. ctrl = ctrls[1];
  2621. ctrl.init(ngModel);
  2622. }
  2623. };
  2624. })
  2625. .directive('uibDatepickerPopupWrap', function() {
  2626. return {
  2627. replace: true,
  2628. transclude: true,
  2629. templateUrl: function(element, attrs) {
  2630. return attrs.templateUrl || 'uib/template/datepickerPopup/popup.html';
  2631. }
  2632. };
  2633. });
  2634. angular.module('ui.bootstrap.debounce', [])
  2635. /**
  2636. * A helper, internal service that debounces a function
  2637. */
  2638. .factory('$$debounce', ['$timeout', function($timeout) {
  2639. return function(callback, debounceTime) {
  2640. var timeoutPromise;
  2641. return function() {
  2642. var self = this;
  2643. var args = Array.prototype.slice.call(arguments);
  2644. if (timeoutPromise) {
  2645. $timeout.cancel(timeoutPromise);
  2646. }
  2647. timeoutPromise = $timeout(function() {
  2648. callback.apply(self, args);
  2649. }, debounceTime);
  2650. };
  2651. };
  2652. }]);
  2653. angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
  2654. .constant('uibDropdownConfig', {
  2655. appendToOpenClass: 'uib-dropdown-open',
  2656. openClass: 'open'
  2657. })
  2658. .service('uibDropdownService', ['$document', '$rootScope', function($document, $rootScope) {
  2659. var openScope = null;
  2660. this.open = function(dropdownScope, element) {
  2661. if (!openScope) {
  2662. $document.on('click', closeDropdown);
  2663. element.on('keydown', keybindFilter);
  2664. }
  2665. if (openScope && openScope !== dropdownScope) {
  2666. openScope.isOpen = false;
  2667. }
  2668. openScope = dropdownScope;
  2669. };
  2670. this.close = function(dropdownScope, element) {
  2671. if (openScope === dropdownScope) {
  2672. openScope = null;
  2673. $document.off('click', closeDropdown);
  2674. element.off('keydown', keybindFilter);
  2675. }
  2676. };
  2677. var closeDropdown = function(evt) {
  2678. // This method may still be called during the same mouse event that
  2679. // unbound this event handler. So check openScope before proceeding.
  2680. if (!openScope) { return; }
  2681. if (evt && openScope.getAutoClose() === 'disabled') { return; }
  2682. if (evt && evt.which === 3) { return; }
  2683. var toggleElement = openScope.getToggleElement();
  2684. if (evt && toggleElement && toggleElement[0].contains(evt.target)) {
  2685. return;
  2686. }
  2687. var dropdownElement = openScope.getDropdownElement();
  2688. if (evt && openScope.getAutoClose() === 'outsideClick' &&
  2689. dropdownElement && dropdownElement[0].contains(evt.target)) {
  2690. return;
  2691. }
  2692. openScope.isOpen = false;
  2693. if (!$rootScope.$$phase) {
  2694. openScope.$apply();
  2695. }
  2696. };
  2697. var keybindFilter = function(evt) {
  2698. if (evt.which === 27) {
  2699. evt.stopPropagation();
  2700. openScope.focusToggleElement();
  2701. closeDropdown();
  2702. } else if (openScope.isKeynavEnabled() && [38, 40].indexOf(evt.which) !== -1 && openScope.isOpen) {
  2703. evt.preventDefault();
  2704. evt.stopPropagation();
  2705. openScope.focusDropdownEntry(evt.which);
  2706. }
  2707. };
  2708. }])
  2709. .controller('UibDropdownController', ['$scope', '$element', '$attrs', '$parse', 'uibDropdownConfig', 'uibDropdownService', '$animate', '$uibPosition', '$document', '$compile', '$templateRequest', function($scope, $element, $attrs, $parse, dropdownConfig, uibDropdownService, $animate, $position, $document, $compile, $templateRequest) {
  2710. var self = this,
  2711. scope = $scope.$new(), // create a child scope so we are not polluting original one
  2712. templateScope,
  2713. appendToOpenClass = dropdownConfig.appendToOpenClass,
  2714. openClass = dropdownConfig.openClass,
  2715. getIsOpen,
  2716. setIsOpen = angular.noop,
  2717. toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop,
  2718. appendToBody = false,
  2719. appendTo = null,
  2720. keynavEnabled = false,
  2721. selectedOption = null,
  2722. body = $document.find('body');
  2723. $element.addClass('dropdown');
  2724. this.init = function() {
  2725. if ($attrs.isOpen) {
  2726. getIsOpen = $parse($attrs.isOpen);
  2727. setIsOpen = getIsOpen.assign;
  2728. $scope.$watch(getIsOpen, function(value) {
  2729. scope.isOpen = !!value;
  2730. });
  2731. }
  2732. if (angular.isDefined($attrs.dropdownAppendTo)) {
  2733. var appendToEl = $parse($attrs.dropdownAppendTo)(scope);
  2734. if (appendToEl) {
  2735. appendTo = angular.element(appendToEl);
  2736. }
  2737. }
  2738. appendToBody = angular.isDefined($attrs.dropdownAppendToBody);
  2739. keynavEnabled = angular.isDefined($attrs.keyboardNav);
  2740. if (appendToBody && !appendTo) {
  2741. appendTo = body;
  2742. }
  2743. if (appendTo && self.dropdownMenu) {
  2744. appendTo.append(self.dropdownMenu);
  2745. $element.on('$destroy', function handleDestroyEvent() {
  2746. self.dropdownMenu.remove();
  2747. });
  2748. }
  2749. };
  2750. this.toggle = function(open) {
  2751. scope.isOpen = arguments.length ? !!open : !scope.isOpen;
  2752. if (angular.isFunction(setIsOpen)) {
  2753. setIsOpen(scope, scope.isOpen);
  2754. }
  2755. return scope.isOpen;
  2756. };
  2757. // Allow other directives to watch status
  2758. this.isOpen = function() {
  2759. return scope.isOpen;
  2760. };
  2761. scope.getToggleElement = function() {
  2762. return self.toggleElement;
  2763. };
  2764. scope.getAutoClose = function() {
  2765. return $attrs.autoClose || 'always'; //or 'outsideClick' or 'disabled'
  2766. };
  2767. scope.getElement = function() {
  2768. return $element;
  2769. };
  2770. scope.isKeynavEnabled = function() {
  2771. return keynavEnabled;
  2772. };
  2773. scope.focusDropdownEntry = function(keyCode) {
  2774. var elems = self.dropdownMenu ? //If append to body is used.
  2775. angular.element(self.dropdownMenu).find('a') :
  2776. $element.find('ul').eq(0).find('a');
  2777. switch (keyCode) {
  2778. case 40: {
  2779. if (!angular.isNumber(self.selectedOption)) {
  2780. self.selectedOption = 0;
  2781. } else {
  2782. self.selectedOption = self.selectedOption === elems.length - 1 ?
  2783. self.selectedOption :
  2784. self.selectedOption + 1;
  2785. }
  2786. break;
  2787. }
  2788. case 38: {
  2789. if (!angular.isNumber(self.selectedOption)) {
  2790. self.selectedOption = elems.length - 1;
  2791. } else {
  2792. self.selectedOption = self.selectedOption === 0 ?
  2793. 0 : self.selectedOption - 1;
  2794. }
  2795. break;
  2796. }
  2797. }
  2798. elems[self.selectedOption].focus();
  2799. };
  2800. scope.getDropdownElement = function() {
  2801. return self.dropdownMenu;
  2802. };
  2803. scope.focusToggleElement = function() {
  2804. if (self.toggleElement) {
  2805. self.toggleElement[0].focus();
  2806. }
  2807. };
  2808. scope.$watch('isOpen', function(isOpen, wasOpen) {
  2809. if (appendTo && self.dropdownMenu) {
  2810. var pos = $position.positionElements($element, self.dropdownMenu, 'bottom-left', true),
  2811. css,
  2812. rightalign,
  2813. scrollbarWidth;
  2814. css = {
  2815. top: pos.top + 'px',
  2816. display: isOpen ? 'block' : 'none'
  2817. };
  2818. rightalign = self.dropdownMenu.hasClass('dropdown-menu-right');
  2819. if (!rightalign) {
  2820. css.left = pos.left + 'px';
  2821. css.right = 'auto';
  2822. } else {
  2823. css.left = 'auto';
  2824. scrollbarWidth = $position.scrollbarWidth(true);
  2825. css.right = window.innerWidth - scrollbarWidth -
  2826. (pos.left + $element.prop('offsetWidth')) + 'px';
  2827. }
  2828. // Need to adjust our positioning to be relative to the appendTo container
  2829. // if it's not the body element
  2830. if (!appendToBody) {
  2831. var appendOffset = $position.offset(appendTo);
  2832. css.top = pos.top - appendOffset.top + 'px';
  2833. if (!rightalign) {
  2834. css.left = pos.left - appendOffset.left + 'px';
  2835. } else {
  2836. css.right = window.innerWidth -
  2837. (pos.left - appendOffset.left + $element.prop('offsetWidth')) + 'px';
  2838. }
  2839. }
  2840. self.dropdownMenu.css(css);
  2841. }
  2842. var openContainer = appendTo ? appendTo : $element;
  2843. var hasOpenClass = openContainer.hasClass(appendTo ? appendToOpenClass : openClass);
  2844. if (hasOpenClass === !isOpen) {
  2845. $animate[isOpen ? 'addClass' : 'removeClass'](openContainer, appendTo ? appendToOpenClass : openClass).then(function() {
  2846. if (angular.isDefined(isOpen) && isOpen !== wasOpen) {
  2847. toggleInvoker($scope, { open: !!isOpen });
  2848. }
  2849. });
  2850. }
  2851. if (isOpen) {
  2852. if (self.dropdownMenuTemplateUrl) {
  2853. $templateRequest(self.dropdownMenuTemplateUrl).then(function(tplContent) {
  2854. templateScope = scope.$new();
  2855. $compile(tplContent.trim())(templateScope, function(dropdownElement) {
  2856. var newEl = dropdownElement;
  2857. self.dropdownMenu.replaceWith(newEl);
  2858. self.dropdownMenu = newEl;
  2859. });
  2860. });
  2861. }
  2862. scope.focusToggleElement();
  2863. uibDropdownService.open(scope, $element);
  2864. } else {
  2865. if (self.dropdownMenuTemplateUrl) {
  2866. if (templateScope) {
  2867. templateScope.$destroy();
  2868. }
  2869. var newEl = angular.element('<ul class="dropdown-menu"></ul>');
  2870. self.dropdownMenu.replaceWith(newEl);
  2871. self.dropdownMenu = newEl;
  2872. }
  2873. uibDropdownService.close(scope, $element);
  2874. self.selectedOption = null;
  2875. }
  2876. if (angular.isFunction(setIsOpen)) {
  2877. setIsOpen($scope, isOpen);
  2878. }
  2879. });
  2880. }])
  2881. .directive('uibDropdown', function() {
  2882. return {
  2883. controller: 'UibDropdownController',
  2884. link: function(scope, element, attrs, dropdownCtrl) {
  2885. dropdownCtrl.init();
  2886. }
  2887. };
  2888. })
  2889. .directive('uibDropdownMenu', function() {
  2890. return {
  2891. restrict: 'A',
  2892. require: '?^uibDropdown',
  2893. link: function(scope, element, attrs, dropdownCtrl) {
  2894. if (!dropdownCtrl || angular.isDefined(attrs.dropdownNested)) {
  2895. return;
  2896. }
  2897. element.addClass('dropdown-menu');
  2898. var tplUrl = attrs.templateUrl;
  2899. if (tplUrl) {
  2900. dropdownCtrl.dropdownMenuTemplateUrl = tplUrl;
  2901. }
  2902. if (!dropdownCtrl.dropdownMenu) {
  2903. dropdownCtrl.dropdownMenu = element;
  2904. }
  2905. }
  2906. };
  2907. })
  2908. .directive('uibDropdownToggle', function() {
  2909. return {
  2910. require: '?^uibDropdown',
  2911. link: function(scope, element, attrs, dropdownCtrl) {
  2912. if (!dropdownCtrl) {
  2913. return;
  2914. }
  2915. element.addClass('dropdown-toggle');
  2916. dropdownCtrl.toggleElement = element;
  2917. var toggleDropdown = function(event) {
  2918. event.preventDefault();
  2919. if (!element.hasClass('disabled') && !attrs.disabled) {
  2920. scope.$apply(function() {
  2921. dropdownCtrl.toggle();
  2922. });
  2923. }
  2924. };
  2925. element.bind('click', toggleDropdown);
  2926. // WAI-ARIA
  2927. element.attr({ 'aria-haspopup': true, 'aria-expanded': false });
  2928. scope.$watch(dropdownCtrl.isOpen, function(isOpen) {
  2929. element.attr('aria-expanded', !!isOpen);
  2930. });
  2931. scope.$on('$destroy', function() {
  2932. element.unbind('click', toggleDropdown);
  2933. });
  2934. }
  2935. };
  2936. });
  2937. angular.module('ui.bootstrap.stackedMap', [])
  2938. /**
  2939. * A helper, internal data structure that acts as a map but also allows getting / removing
  2940. * elements in the LIFO order
  2941. */
  2942. .factory('$$stackedMap', function() {
  2943. return {
  2944. createNew: function() {
  2945. var stack = [];
  2946. return {
  2947. add: function(key, value) {
  2948. stack.push({
  2949. key: key,
  2950. value: value
  2951. });
  2952. },
  2953. get: function(key) {
  2954. for (var i = 0; i < stack.length; i++) {
  2955. if (key === stack[i].key) {
  2956. return stack[i];
  2957. }
  2958. }
  2959. },
  2960. keys: function() {
  2961. var keys = [];
  2962. for (var i = 0; i < stack.length; i++) {
  2963. keys.push(stack[i].key);
  2964. }
  2965. return keys;
  2966. },
  2967. top: function() {
  2968. return stack[stack.length - 1];
  2969. },
  2970. remove: function(key) {
  2971. var idx = -1;
  2972. for (var i = 0; i < stack.length; i++) {
  2973. if (key === stack[i].key) {
  2974. idx = i;
  2975. break;
  2976. }
  2977. }
  2978. return stack.splice(idx, 1)[0];
  2979. },
  2980. removeTop: function() {
  2981. return stack.splice(stack.length - 1, 1)[0];
  2982. },
  2983. length: function() {
  2984. return stack.length;
  2985. }
  2986. };
  2987. }
  2988. };
  2989. });
  2990. angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.position'])
  2991. /**
  2992. * A helper, internal data structure that stores all references attached to key
  2993. */
  2994. .factory('$$multiMap', function() {
  2995. return {
  2996. createNew: function() {
  2997. var map = {};
  2998. return {
  2999. entries: function() {
  3000. return Object.keys(map).map(function(key) {
  3001. return {
  3002. key: key,
  3003. value: map[key]
  3004. };
  3005. });
  3006. },
  3007. get: function(key) {
  3008. return map[key];
  3009. },
  3010. hasKey: function(key) {
  3011. return !!map[key];
  3012. },
  3013. keys: function() {
  3014. return Object.keys(map);
  3015. },
  3016. put: function(key, value) {
  3017. if (!map[key]) {
  3018. map[key] = [];
  3019. }
  3020. map[key].push(value);
  3021. },
  3022. remove: function(key, value) {
  3023. var values = map[key];
  3024. if (!values) {
  3025. return;
  3026. }
  3027. var idx = values.indexOf(value);
  3028. if (idx !== -1) {
  3029. values.splice(idx, 1);
  3030. }
  3031. if (!values.length) {
  3032. delete map[key];
  3033. }
  3034. }
  3035. };
  3036. }
  3037. };
  3038. })
  3039. /**
  3040. * Pluggable resolve mechanism for the modal resolve resolution
  3041. * Supports UI Router's $resolve service
  3042. */
  3043. .provider('$uibResolve', function() {
  3044. var resolve = this;
  3045. this.resolver = null;
  3046. this.setResolver = function(resolver) {
  3047. this.resolver = resolver;
  3048. };
  3049. this.$get = ['$injector', '$q', function($injector, $q) {
  3050. var resolver = resolve.resolver ? $injector.get(resolve.resolver) : null;
  3051. return {
  3052. resolve: function(invocables, locals, parent, self) {
  3053. if (resolver) {
  3054. return resolver.resolve(invocables, locals, parent, self);
  3055. }
  3056. var promises = [];
  3057. angular.forEach(invocables, function(value) {
  3058. if (angular.isFunction(value) || angular.isArray(value)) {
  3059. promises.push($q.resolve($injector.invoke(value)));
  3060. } else if (angular.isString(value)) {
  3061. promises.push($q.resolve($injector.get(value)));
  3062. } else {
  3063. promises.push($q.resolve(value));
  3064. }
  3065. });
  3066. return $q.all(promises).then(function(resolves) {
  3067. var resolveObj = {};
  3068. var resolveIter = 0;
  3069. angular.forEach(invocables, function(value, key) {
  3070. resolveObj[key] = resolves[resolveIter++];
  3071. });
  3072. return resolveObj;
  3073. });
  3074. }
  3075. };
  3076. }];
  3077. })
  3078. /**
  3079. * A helper directive for the $modal service. It creates a backdrop element.
  3080. */
  3081. .directive('uibModalBackdrop', ['$animate', '$injector', '$uibModalStack',
  3082. function($animate, $injector, $modalStack) {
  3083. return {
  3084. replace: true,
  3085. templateUrl: 'uib/template/modal/backdrop.html',
  3086. compile: function(tElement, tAttrs) {
  3087. tElement.addClass(tAttrs.backdropClass);
  3088. return linkFn;
  3089. }
  3090. };
  3091. function linkFn(scope, element, attrs) {
  3092. if (attrs.modalInClass) {
  3093. $animate.addClass(element, attrs.modalInClass);
  3094. scope.$on($modalStack.NOW_CLOSING_EVENT, function(e, setIsAsync) {
  3095. var done = setIsAsync();
  3096. if (scope.modalOptions.animation) {
  3097. $animate.removeClass(element, attrs.modalInClass).then(done);
  3098. } else {
  3099. done();
  3100. }
  3101. });
  3102. }
  3103. }
  3104. }])
  3105. .directive('uibModalWindow', ['$uibModalStack', '$q', '$animateCss', '$document',
  3106. function($modalStack, $q, $animateCss, $document) {
  3107. return {
  3108. scope: {
  3109. index: '@'
  3110. },
  3111. replace: true,
  3112. transclude: true,
  3113. templateUrl: function(tElement, tAttrs) {
  3114. return tAttrs.templateUrl || 'uib/template/modal/window.html';
  3115. },
  3116. link: function(scope, element, attrs) {
  3117. element.addClass(attrs.windowClass || '');
  3118. element.addClass(attrs.windowTopClass || '');
  3119. scope.size = attrs.size;
  3120. scope.close = function(evt) {
  3121. var modal = $modalStack.getTop();
  3122. if (modal && modal.value.backdrop &&
  3123. modal.value.backdrop !== 'static' &&
  3124. evt.target === evt.currentTarget) {
  3125. evt.preventDefault();
  3126. evt.stopPropagation();
  3127. $modalStack.dismiss(modal.key, 'backdrop click');
  3128. }
  3129. };
  3130. // moved from template to fix issue #2280
  3131. element.on('click', scope.close);
  3132. // This property is only added to the scope for the purpose of detecting when this directive is rendered.
  3133. // We can detect that by using this property in the template associated with this directive and then use
  3134. // {@link Attribute#$observe} on it. For more details please see {@link TableColumnResize}.
  3135. scope.$isRendered = true;
  3136. // Deferred object that will be resolved when this modal is render.
  3137. var modalRenderDeferObj = $q.defer();
  3138. // Observe function will be called on next digest cycle after compilation, ensuring that the DOM is ready.
  3139. // In order to use this way of finding whether DOM is ready, we need to observe a scope property used in modal's template.
  3140. attrs.$observe('modalRender', function(value) {
  3141. if (value === 'true') {
  3142. modalRenderDeferObj.resolve();
  3143. }
  3144. });
  3145. modalRenderDeferObj.promise.then(function() {
  3146. var animationPromise = null;
  3147. if (attrs.modalInClass) {
  3148. animationPromise = $animateCss(element, {
  3149. addClass: attrs.modalInClass
  3150. }).start();
  3151. scope.$on($modalStack.NOW_CLOSING_EVENT, function(e, setIsAsync) {
  3152. var done = setIsAsync();
  3153. $animateCss(element, {
  3154. removeClass: attrs.modalInClass
  3155. }).start().then(done);
  3156. });
  3157. }
  3158. $q.when(animationPromise).then(function() {
  3159. // Notify {@link $modalStack} that modal is rendered.
  3160. var modal = $modalStack.getTop();
  3161. if (modal) {
  3162. $modalStack.modalRendered(modal.key);
  3163. }
  3164. /**
  3165. * If something within the freshly-opened modal already has focus (perhaps via a
  3166. * directive that causes focus). then no need to try and focus anything.
  3167. */
  3168. if (!($document[0].activeElement && element[0].contains($document[0].activeElement))) {
  3169. var inputWithAutofocus = element[0].querySelector('[autofocus]');
  3170. /**
  3171. * Auto-focusing of a freshly-opened modal element causes any child elements
  3172. * with the autofocus attribute to lose focus. This is an issue on touch
  3173. * based devices which will show and then hide the onscreen keyboard.
  3174. * Attempts to refocus the autofocus element via JavaScript will not reopen
  3175. * the onscreen keyboard. Fixed by updated the focusing logic to only autofocus
  3176. * the modal element if the modal does not contain an autofocus element.
  3177. */
  3178. if (inputWithAutofocus) {
  3179. inputWithAutofocus.focus();
  3180. } else {
  3181. element[0].focus();
  3182. }
  3183. }
  3184. });
  3185. });
  3186. }
  3187. };
  3188. }])
  3189. .directive('uibModalAnimationClass', function() {
  3190. return {
  3191. compile: function(tElement, tAttrs) {
  3192. if (tAttrs.modalAnimation) {
  3193. tElement.addClass(tAttrs.uibModalAnimationClass);
  3194. }
  3195. }
  3196. };
  3197. })
  3198. .directive('uibModalTransclude', function() {
  3199. return {
  3200. link: function(scope, element, attrs, controller, transclude) {
  3201. transclude(scope.$parent, function(clone) {
  3202. element.empty();
  3203. element.append(clone);
  3204. });
  3205. }
  3206. };
  3207. })
  3208. .factory('$uibModalStack', ['$animate', '$animateCss', '$document',
  3209. '$compile', '$rootScope', '$q', '$$multiMap', '$$stackedMap', '$uibPosition',
  3210. function($animate, $animateCss, $document, $compile, $rootScope, $q, $$multiMap, $$stackedMap, $uibPosition) {
  3211. var OPENED_MODAL_CLASS = 'modal-open';
  3212. var backdropDomEl, backdropScope;
  3213. var openedWindows = $$stackedMap.createNew();
  3214. var openedClasses = $$multiMap.createNew();
  3215. var $modalStack = {
  3216. NOW_CLOSING_EVENT: 'modal.stack.now-closing'
  3217. };
  3218. var topModalIndex = 0;
  3219. var previousTopOpenedModal = null;
  3220. //Modal focus behavior
  3221. var tabableSelector = 'a[href], area[href], input:not([disabled]), ' +
  3222. 'button:not([disabled]),select:not([disabled]), textarea:not([disabled]), ' +
  3223. 'iframe, object, embed, *[tabindex], *[contenteditable=true]';
  3224. var scrollbarPadding;
  3225. function isVisible(element) {
  3226. return !!(element.offsetWidth ||
  3227. element.offsetHeight ||
  3228. element.getClientRects().length);
  3229. }
  3230. function backdropIndex() {
  3231. var topBackdropIndex = -1;
  3232. var opened = openedWindows.keys();
  3233. for (var i = 0; i < opened.length; i++) {
  3234. if (openedWindows.get(opened[i]).value.backdrop) {
  3235. topBackdropIndex = i;
  3236. }
  3237. }
  3238. // If any backdrop exist, ensure that it's index is always
  3239. // right below the top modal
  3240. if (topBackdropIndex > -1 && topBackdropIndex < topModalIndex) {
  3241. topBackdropIndex = topModalIndex;
  3242. }
  3243. return topBackdropIndex;
  3244. }
  3245. $rootScope.$watch(backdropIndex, function(newBackdropIndex) {
  3246. if (backdropScope) {
  3247. backdropScope.index = newBackdropIndex;
  3248. }
  3249. });
  3250. function removeModalWindow(modalInstance, elementToReceiveFocus) {
  3251. var modalWindow = openedWindows.get(modalInstance).value;
  3252. var appendToElement = modalWindow.appendTo;
  3253. //clean up the stack
  3254. openedWindows.remove(modalInstance);
  3255. previousTopOpenedModal = openedWindows.top();
  3256. if (previousTopOpenedModal) {
  3257. topModalIndex = parseInt(previousTopOpenedModal.value.modalDomEl.attr('index'), 10);
  3258. }
  3259. removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
  3260. var modalBodyClass = modalWindow.openedClass || OPENED_MODAL_CLASS;
  3261. openedClasses.remove(modalBodyClass, modalInstance);
  3262. var areAnyOpen = openedClasses.hasKey(modalBodyClass);
  3263. appendToElement.toggleClass(modalBodyClass, areAnyOpen);
  3264. if (!areAnyOpen && scrollbarPadding && scrollbarPadding.heightOverflow && scrollbarPadding.scrollbarWidth) {
  3265. if (scrollbarPadding.originalRight) {
  3266. appendToElement.css({paddingRight: scrollbarPadding.originalRight + 'px'});
  3267. } else {
  3268. appendToElement.css({paddingRight: ''});
  3269. }
  3270. scrollbarPadding = null;
  3271. }
  3272. toggleTopWindowClass(true);
  3273. }, modalWindow.closedDeferred);
  3274. checkRemoveBackdrop();
  3275. //move focus to specified element if available, or else to body
  3276. if (elementToReceiveFocus && elementToReceiveFocus.focus) {
  3277. elementToReceiveFocus.focus();
  3278. } else if (appendToElement.focus) {
  3279. appendToElement.focus();
  3280. }
  3281. }
  3282. // Add or remove "windowTopClass" from the top window in the stack
  3283. function toggleTopWindowClass(toggleSwitch) {
  3284. var modalWindow;
  3285. if (openedWindows.length() > 0) {
  3286. modalWindow = openedWindows.top().value;
  3287. modalWindow.modalDomEl.toggleClass(modalWindow.windowTopClass || '', toggleSwitch);
  3288. }
  3289. }
  3290. function checkRemoveBackdrop() {
  3291. //remove backdrop if no longer needed
  3292. if (backdropDomEl && backdropIndex() === -1) {
  3293. var backdropScopeRef = backdropScope;
  3294. removeAfterAnimate(backdropDomEl, backdropScope, function() {
  3295. backdropScopeRef = null;
  3296. });
  3297. backdropDomEl = undefined;
  3298. backdropScope = undefined;
  3299. }
  3300. }
  3301. function removeAfterAnimate(domEl, scope, done, closedDeferred) {
  3302. var asyncDeferred;
  3303. var asyncPromise = null;
  3304. var setIsAsync = function() {
  3305. if (!asyncDeferred) {
  3306. asyncDeferred = $q.defer();
  3307. asyncPromise = asyncDeferred.promise;
  3308. }
  3309. return function asyncDone() {
  3310. asyncDeferred.resolve();
  3311. };
  3312. };
  3313. scope.$broadcast($modalStack.NOW_CLOSING_EVENT, setIsAsync);
  3314. // Note that it's intentional that asyncPromise might be null.
  3315. // That's when setIsAsync has not been called during the
  3316. // NOW_CLOSING_EVENT broadcast.
  3317. return $q.when(asyncPromise).then(afterAnimating);
  3318. function afterAnimating() {
  3319. if (afterAnimating.done) {
  3320. return;
  3321. }
  3322. afterAnimating.done = true;
  3323. $animate.leave(domEl).then(function() {
  3324. domEl.remove();
  3325. if (closedDeferred) {
  3326. closedDeferred.resolve();
  3327. }
  3328. });
  3329. scope.$destroy();
  3330. if (done) {
  3331. done();
  3332. }
  3333. }
  3334. }
  3335. $document.on('keydown', keydownListener);
  3336. $rootScope.$on('$destroy', function() {
  3337. $document.off('keydown', keydownListener);
  3338. });
  3339. function keydownListener(evt) {
  3340. if (evt.isDefaultPrevented()) {
  3341. return evt;
  3342. }
  3343. var modal = openedWindows.top();
  3344. if (modal) {
  3345. switch (evt.which) {
  3346. case 27: {
  3347. if (modal.value.keyboard) {
  3348. evt.preventDefault();
  3349. $rootScope.$apply(function() {
  3350. $modalStack.dismiss(modal.key, 'escape key press');
  3351. });
  3352. }
  3353. break;
  3354. }
  3355. case 9: {
  3356. var list = $modalStack.loadFocusElementList(modal);
  3357. var focusChanged = false;
  3358. if (evt.shiftKey) {
  3359. if ($modalStack.isFocusInFirstItem(evt, list) || $modalStack.isModalFocused(evt, modal)) {
  3360. focusChanged = $modalStack.focusLastFocusableElement(list);
  3361. }
  3362. } else {
  3363. if ($modalStack.isFocusInLastItem(evt, list)) {
  3364. focusChanged = $modalStack.focusFirstFocusableElement(list);
  3365. }
  3366. }
  3367. if (focusChanged) {
  3368. evt.preventDefault();
  3369. evt.stopPropagation();
  3370. }
  3371. break;
  3372. }
  3373. }
  3374. }
  3375. }
  3376. $modalStack.open = function(modalInstance, modal) {
  3377. var modalOpener = $document[0].activeElement,
  3378. modalBodyClass = modal.openedClass || OPENED_MODAL_CLASS;
  3379. toggleTopWindowClass(false);
  3380. // Store the current top first, to determine what index we ought to use
  3381. // for the current top modal
  3382. previousTopOpenedModal = openedWindows.top();
  3383. openedWindows.add(modalInstance, {
  3384. deferred: modal.deferred,
  3385. renderDeferred: modal.renderDeferred,
  3386. closedDeferred: modal.closedDeferred,
  3387. modalScope: modal.scope,
  3388. backdrop: modal.backdrop,
  3389. keyboard: modal.keyboard,
  3390. openedClass: modal.openedClass,
  3391. windowTopClass: modal.windowTopClass,
  3392. animation: modal.animation,
  3393. appendTo: modal.appendTo
  3394. });
  3395. openedClasses.put(modalBodyClass, modalInstance);
  3396. var appendToElement = modal.appendTo,
  3397. currBackdropIndex = backdropIndex();
  3398. if (!appendToElement.length) {
  3399. throw new Error('appendTo element not found. Make sure that the element passed is in DOM.');
  3400. }
  3401. if (currBackdropIndex >= 0 && !backdropDomEl) {
  3402. backdropScope = $rootScope.$new(true);
  3403. backdropScope.modalOptions = modal;
  3404. backdropScope.index = currBackdropIndex;
  3405. backdropDomEl = angular.element('<div uib-modal-backdrop="modal-backdrop"></div>');
  3406. backdropDomEl.attr('backdrop-class', modal.backdropClass);
  3407. if (modal.animation) {
  3408. backdropDomEl.attr('modal-animation', 'true');
  3409. }
  3410. $compile(backdropDomEl)(backdropScope);
  3411. $animate.enter(backdropDomEl, appendToElement);
  3412. scrollbarPadding = $uibPosition.scrollbarPadding(appendToElement);
  3413. if (scrollbarPadding.heightOverflow && scrollbarPadding.scrollbarWidth) {
  3414. appendToElement.css({paddingRight: scrollbarPadding.right + 'px'});
  3415. }
  3416. }
  3417. // Set the top modal index based on the index of the previous top modal
  3418. topModalIndex = previousTopOpenedModal ? parseInt(previousTopOpenedModal.value.modalDomEl.attr('index'), 10) + 1 : 0;
  3419. var angularDomEl = angular.element('<div uib-modal-window="modal-window"></div>');
  3420. angularDomEl.attr({
  3421. 'template-url': modal.windowTemplateUrl,
  3422. 'window-class': modal.windowClass,
  3423. 'window-top-class': modal.windowTopClass,
  3424. 'size': modal.size,
  3425. 'index': topModalIndex,
  3426. 'animate': 'animate'
  3427. }).html(modal.content);
  3428. if (modal.animation) {
  3429. angularDomEl.attr('modal-animation', 'true');
  3430. }
  3431. appendToElement.addClass(modalBodyClass);
  3432. $animate.enter($compile(angularDomEl)(modal.scope), appendToElement);
  3433. openedWindows.top().value.modalDomEl = angularDomEl;
  3434. openedWindows.top().value.modalOpener = modalOpener;
  3435. };
  3436. function broadcastClosing(modalWindow, resultOrReason, closing) {
  3437. return !modalWindow.value.modalScope.$broadcast('modal.closing', resultOrReason, closing).defaultPrevented;
  3438. }
  3439. $modalStack.close = function(modalInstance, result) {
  3440. var modalWindow = openedWindows.get(modalInstance);
  3441. if (modalWindow && broadcastClosing(modalWindow, result, true)) {
  3442. modalWindow.value.modalScope.$$uibDestructionScheduled = true;
  3443. modalWindow.value.deferred.resolve(result);
  3444. removeModalWindow(modalInstance, modalWindow.value.modalOpener);
  3445. return true;
  3446. }
  3447. return !modalWindow;
  3448. };
  3449. $modalStack.dismiss = function(modalInstance, reason) {
  3450. var modalWindow = openedWindows.get(modalInstance);
  3451. if (modalWindow && broadcastClosing(modalWindow, reason, false)) {
  3452. modalWindow.value.modalScope.$$uibDestructionScheduled = true;
  3453. modalWindow.value.deferred.reject(reason);
  3454. removeModalWindow(modalInstance, modalWindow.value.modalOpener);
  3455. return true;
  3456. }
  3457. return !modalWindow;
  3458. };
  3459. $modalStack.dismissAll = function(reason) {
  3460. var topModal = this.getTop();
  3461. while (topModal && this.dismiss(topModal.key, reason)) {
  3462. topModal = this.getTop();
  3463. }
  3464. };
  3465. $modalStack.getTop = function() {
  3466. return openedWindows.top();
  3467. };
  3468. $modalStack.modalRendered = function(modalInstance) {
  3469. var modalWindow = openedWindows.get(modalInstance);
  3470. if (modalWindow) {
  3471. modalWindow.value.renderDeferred.resolve();
  3472. }
  3473. };
  3474. $modalStack.focusFirstFocusableElement = function(list) {
  3475. if (list.length > 0) {
  3476. list[0].focus();
  3477. return true;
  3478. }
  3479. return false;
  3480. };
  3481. $modalStack.focusLastFocusableElement = function(list) {
  3482. if (list.length > 0) {
  3483. list[list.length - 1].focus();
  3484. return true;
  3485. }
  3486. return false;
  3487. };
  3488. $modalStack.isModalFocused = function(evt, modalWindow) {
  3489. if (evt && modalWindow) {
  3490. var modalDomEl = modalWindow.value.modalDomEl;
  3491. if (modalDomEl && modalDomEl.length) {
  3492. return (evt.target || evt.srcElement) === modalDomEl[0];
  3493. }
  3494. }
  3495. return false;
  3496. };
  3497. $modalStack.isFocusInFirstItem = function(evt, list) {
  3498. if (list.length > 0) {
  3499. return (evt.target || evt.srcElement) === list[0];
  3500. }
  3501. return false;
  3502. };
  3503. $modalStack.isFocusInLastItem = function(evt, list) {
  3504. if (list.length > 0) {
  3505. return (evt.target || evt.srcElement) === list[list.length - 1];
  3506. }
  3507. return false;
  3508. };
  3509. $modalStack.loadFocusElementList = function(modalWindow) {
  3510. if (modalWindow) {
  3511. var modalDomE1 = modalWindow.value.modalDomEl;
  3512. if (modalDomE1 && modalDomE1.length) {
  3513. var elements = modalDomE1[0].querySelectorAll(tabableSelector);
  3514. return elements ?
  3515. Array.prototype.filter.call(elements, function(element) {
  3516. return isVisible(element);
  3517. }) : elements;
  3518. }
  3519. }
  3520. };
  3521. return $modalStack;
  3522. }])
  3523. .provider('$uibModal', function() {
  3524. var $modalProvider = {
  3525. options: {
  3526. animation: true,
  3527. backdrop: true, //can also be false or 'static'
  3528. keyboard: true
  3529. },
  3530. $get: ['$rootScope', '$q', '$document', '$templateRequest', '$controller', '$uibResolve', '$uibModalStack',
  3531. function ($rootScope, $q, $document, $templateRequest, $controller, $uibResolve, $modalStack) {
  3532. var $modal = {};
  3533. function getTemplatePromise(options) {
  3534. return options.template ? $q.when(options.template) :
  3535. $templateRequest(angular.isFunction(options.templateUrl) ?
  3536. options.templateUrl() : options.templateUrl);
  3537. }
  3538. var promiseChain = null;
  3539. $modal.getPromiseChain = function() {
  3540. return promiseChain;
  3541. };
  3542. $modal.open = function(modalOptions) {
  3543. var modalResultDeferred = $q.defer();
  3544. var modalOpenedDeferred = $q.defer();
  3545. var modalClosedDeferred = $q.defer();
  3546. var modalRenderDeferred = $q.defer();
  3547. //prepare an instance of a modal to be injected into controllers and returned to a caller
  3548. var modalInstance = {
  3549. result: modalResultDeferred.promise,
  3550. opened: modalOpenedDeferred.promise,
  3551. closed: modalClosedDeferred.promise,
  3552. rendered: modalRenderDeferred.promise,
  3553. close: function (result) {
  3554. return $modalStack.close(modalInstance, result);
  3555. },
  3556. dismiss: function (reason) {
  3557. return $modalStack.dismiss(modalInstance, reason);
  3558. }
  3559. };
  3560. //merge and clean up options
  3561. modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
  3562. modalOptions.resolve = modalOptions.resolve || {};
  3563. modalOptions.appendTo = modalOptions.appendTo || $document.find('body').eq(0);
  3564. //verify options
  3565. if (!modalOptions.template && !modalOptions.templateUrl) {
  3566. throw new Error('One of template or templateUrl options is required.');
  3567. }
  3568. var templateAndResolvePromise =
  3569. $q.all([getTemplatePromise(modalOptions), $uibResolve.resolve(modalOptions.resolve, {}, null, null)]);
  3570. function resolveWithTemplate() {
  3571. return templateAndResolvePromise;
  3572. }
  3573. // Wait for the resolution of the existing promise chain.
  3574. // Then switch to our own combined promise dependency (regardless of how the previous modal fared).
  3575. // Then add to $modalStack and resolve opened.
  3576. // Finally clean up the chain variable if no subsequent modal has overwritten it.
  3577. var samePromise;
  3578. samePromise = promiseChain = $q.all([promiseChain])
  3579. .then(resolveWithTemplate, resolveWithTemplate)
  3580. .then(function resolveSuccess(tplAndVars) {
  3581. var providedScope = modalOptions.scope || $rootScope;
  3582. var modalScope = providedScope.$new();
  3583. modalScope.$close = modalInstance.close;
  3584. modalScope.$dismiss = modalInstance.dismiss;
  3585. modalScope.$on('$destroy', function() {
  3586. if (!modalScope.$$uibDestructionScheduled) {
  3587. modalScope.$dismiss('$uibUnscheduledDestruction');
  3588. }
  3589. });
  3590. var ctrlInstance, ctrlInstantiate, ctrlLocals = {};
  3591. //controllers
  3592. if (modalOptions.controller) {
  3593. ctrlLocals.$scope = modalScope;
  3594. ctrlLocals.$scope.$resolve = {};
  3595. ctrlLocals.$uibModalInstance = modalInstance;
  3596. angular.forEach(tplAndVars[1], function(value, key) {
  3597. ctrlLocals[key] = value;
  3598. ctrlLocals.$scope.$resolve[key] = value;
  3599. });
  3600. // the third param will make the controller instantiate later,private api
  3601. // @see https://github.com/angular/angular.js/blob/master/src/ng/controller.js#L126
  3602. ctrlInstantiate = $controller(modalOptions.controller, ctrlLocals, true, modalOptions.controllerAs);
  3603. if (modalOptions.controllerAs && modalOptions.bindToController) {
  3604. ctrlInstance = ctrlInstantiate.instance;
  3605. ctrlInstance.$close = modalScope.$close;
  3606. ctrlInstance.$dismiss = modalScope.$dismiss;
  3607. angular.extend(ctrlInstance, {
  3608. $resolve: ctrlLocals.$scope.$resolve
  3609. }, providedScope);
  3610. }
  3611. ctrlInstance = ctrlInstantiate();
  3612. if (angular.isFunction(ctrlInstance.$onInit)) {
  3613. ctrlInstance.$onInit();
  3614. }
  3615. }
  3616. $modalStack.open(modalInstance, {
  3617. scope: modalScope,
  3618. deferred: modalResultDeferred,
  3619. renderDeferred: modalRenderDeferred,
  3620. closedDeferred: modalClosedDeferred,
  3621. content: tplAndVars[0],
  3622. animation: modalOptions.animation,
  3623. backdrop: modalOptions.backdrop,
  3624. keyboard: modalOptions.keyboard,
  3625. backdropClass: modalOptions.backdropClass,
  3626. windowTopClass: modalOptions.windowTopClass,
  3627. windowClass: modalOptions.windowClass,
  3628. windowTemplateUrl: modalOptions.windowTemplateUrl,
  3629. size: modalOptions.size,
  3630. openedClass: modalOptions.openedClass,
  3631. appendTo: modalOptions.appendTo
  3632. });
  3633. modalOpenedDeferred.resolve(true);
  3634. }, function resolveError(reason) {
  3635. modalOpenedDeferred.reject(reason);
  3636. modalResultDeferred.reject(reason);
  3637. })['finally'](function() {
  3638. if (promiseChain === samePromise) {
  3639. promiseChain = null;
  3640. }
  3641. });
  3642. return modalInstance;
  3643. };
  3644. return $modal;
  3645. }
  3646. ]
  3647. };
  3648. return $modalProvider;
  3649. });
  3650. angular.module('ui.bootstrap.paging', [])
  3651. /**
  3652. * Helper internal service for generating common controller code between the
  3653. * pager and pagination components
  3654. */
  3655. .factory('uibPaging', ['$parse', function($parse) {
  3656. return {
  3657. create: function(ctrl, $scope, $attrs) {
  3658. ctrl.setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
  3659. ctrl.ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl
  3660. ctrl._watchers = [];
  3661. ctrl.init = function(ngModelCtrl, config) {
  3662. ctrl.ngModelCtrl = ngModelCtrl;
  3663. ctrl.config = config;
  3664. ngModelCtrl.$render = function() {
  3665. ctrl.render();
  3666. };
  3667. if ($attrs.itemsPerPage) {
  3668. ctrl._watchers.push($scope.$parent.$watch($attrs.itemsPerPage, function(value) {
  3669. ctrl.itemsPerPage = parseInt(value, 10);
  3670. $scope.totalPages = ctrl.calculateTotalPages();
  3671. ctrl.updatePage();
  3672. }));
  3673. } else {
  3674. ctrl.itemsPerPage = config.itemsPerPage;
  3675. }
  3676. $scope.$watch('totalItems', function(newTotal, oldTotal) {
  3677. if (angular.isDefined(newTotal) || newTotal !== oldTotal) {
  3678. $scope.totalPages = ctrl.calculateTotalPages();
  3679. ctrl.updatePage();
  3680. }
  3681. });
  3682. };
  3683. ctrl.calculateTotalPages = function() {
  3684. var totalPages = ctrl.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / ctrl.itemsPerPage);
  3685. return Math.max(totalPages || 0, 1);
  3686. };
  3687. ctrl.render = function() {
  3688. $scope.page = parseInt(ctrl.ngModelCtrl.$viewValue, 10) || 1;
  3689. };
  3690. $scope.selectPage = function(page, evt) {
  3691. if (evt) {
  3692. evt.preventDefault();
  3693. }
  3694. var clickAllowed = !$scope.ngDisabled || !evt;
  3695. if (clickAllowed && $scope.page !== page && page > 0 && page <= $scope.totalPages) {
  3696. if (evt && evt.target) {
  3697. evt.target.blur();
  3698. }
  3699. ctrl.ngModelCtrl.$setViewValue(page);
  3700. ctrl.ngModelCtrl.$render();
  3701. }
  3702. };
  3703. $scope.getText = function(key) {
  3704. return $scope[key + 'Text'] || ctrl.config[key + 'Text'];
  3705. };
  3706. $scope.noPrevious = function() {
  3707. return $scope.page === 1;
  3708. };
  3709. $scope.noNext = function() {
  3710. return $scope.page === $scope.totalPages;
  3711. };
  3712. ctrl.updatePage = function() {
  3713. ctrl.setNumPages($scope.$parent, $scope.totalPages); // Readonly variable
  3714. if ($scope.page > $scope.totalPages) {
  3715. $scope.selectPage($scope.totalPages);
  3716. } else {
  3717. ctrl.ngModelCtrl.$render();
  3718. }
  3719. };
  3720. $scope.$on('$destroy', function() {
  3721. while (ctrl._watchers.length) {
  3722. ctrl._watchers.shift()();
  3723. }
  3724. });
  3725. }
  3726. };
  3727. }]);
  3728. angular.module('ui.bootstrap.pager', ['ui.bootstrap.paging'])
  3729. .controller('UibPagerController', ['$scope', '$attrs', 'uibPaging', 'uibPagerConfig', function($scope, $attrs, uibPaging, uibPagerConfig) {
  3730. $scope.align = angular.isDefined($attrs.align) ? $scope.$parent.$eval($attrs.align) : uibPagerConfig.align;
  3731. uibPaging.create(this, $scope, $attrs);
  3732. }])
  3733. .constant('uibPagerConfig', {
  3734. itemsPerPage: 10,
  3735. previousText: '« Previous',
  3736. nextText: 'Next »',
  3737. align: true
  3738. })
  3739. .directive('uibPager', ['uibPagerConfig', function(uibPagerConfig) {
  3740. return {
  3741. scope: {
  3742. totalItems: '=',
  3743. previousText: '@',
  3744. nextText: '@',
  3745. ngDisabled: '='
  3746. },
  3747. require: ['uibPager', '?ngModel'],
  3748. controller: 'UibPagerController',
  3749. controllerAs: 'pager',
  3750. templateUrl: function(element, attrs) {
  3751. return attrs.templateUrl || 'uib/template/pager/pager.html';
  3752. },
  3753. replace: true,
  3754. link: function(scope, element, attrs, ctrls) {
  3755. var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
  3756. if (!ngModelCtrl) {
  3757. return; // do nothing if no ng-model
  3758. }
  3759. paginationCtrl.init(ngModelCtrl, uibPagerConfig);
  3760. }
  3761. };
  3762. }]);
  3763. angular.module('ui.bootstrap.pagination', ['ui.bootstrap.paging'])
  3764. .controller('UibPaginationController', ['$scope', '$attrs', '$parse', 'uibPaging', 'uibPaginationConfig', function($scope, $attrs, $parse, uibPaging, uibPaginationConfig) {
  3765. var ctrl = this;
  3766. // Setup configuration parameters
  3767. var maxSize = angular.isDefined($attrs.maxSize) ? $scope.$parent.$eval($attrs.maxSize) : uibPaginationConfig.maxSize,
  3768. rotate = angular.isDefined($attrs.rotate) ? $scope.$parent.$eval($attrs.rotate) : uibPaginationConfig.rotate,
  3769. forceEllipses = angular.isDefined($attrs.forceEllipses) ? $scope.$parent.$eval($attrs.forceEllipses) : uibPaginationConfig.forceEllipses,
  3770. boundaryLinkNumbers = angular.isDefined($attrs.boundaryLinkNumbers) ? $scope.$parent.$eval($attrs.boundaryLinkNumbers) : uibPaginationConfig.boundaryLinkNumbers,
  3771. pageLabel = angular.isDefined($attrs.pageLabel) ? function(idx) { return $scope.$parent.$eval($attrs.pageLabel, {$page: idx}); } : angular.identity;
  3772. $scope.boundaryLinks = angular.isDefined($attrs.boundaryLinks) ? $scope.$parent.$eval($attrs.boundaryLinks) : uibPaginationConfig.boundaryLinks;
  3773. $scope.directionLinks = angular.isDefined($attrs.directionLinks) ? $scope.$parent.$eval($attrs.directionLinks) : uibPaginationConfig.directionLinks;
  3774. uibPaging.create(this, $scope, $attrs);
  3775. if ($attrs.maxSize) {
  3776. ctrl._watchers.push($scope.$parent.$watch($parse($attrs.maxSize), function(value) {
  3777. maxSize = parseInt(value, 10);
  3778. ctrl.render();
  3779. }));
  3780. }
  3781. // Create page object used in template
  3782. function makePage(number, text, isActive) {
  3783. return {
  3784. number: number,
  3785. text: text,
  3786. active: isActive
  3787. };
  3788. }
  3789. function getPages(currentPage, totalPages) {
  3790. var pages = [];
  3791. // Default page limits
  3792. var startPage = 1, endPage = totalPages;
  3793. var isMaxSized = angular.isDefined(maxSize) && maxSize < totalPages;
  3794. // recompute if maxSize
  3795. if (isMaxSized) {
  3796. if (rotate) {
  3797. // Current page is displayed in the middle of the visible ones
  3798. startPage = Math.max(currentPage - Math.floor(maxSize / 2), 1);
  3799. endPage = startPage + maxSize - 1;
  3800. // Adjust if limit is exceeded
  3801. if (endPage > totalPages) {
  3802. endPage = totalPages;
  3803. startPage = endPage - maxSize + 1;
  3804. }
  3805. } else {
  3806. // Visible pages are paginated with maxSize
  3807. startPage = (Math.ceil(currentPage / maxSize) - 1) * maxSize + 1;
  3808. // Adjust last page if limit is exceeded
  3809. endPage = Math.min(startPage + maxSize - 1, totalPages);
  3810. }
  3811. }
  3812. // Add page number links
  3813. for (var number = startPage; number <= endPage; number++) {
  3814. var page = makePage(number, pageLabel(number), number === currentPage);
  3815. pages.push(page);
  3816. }
  3817. // Add links to move between page sets
  3818. if (isMaxSized && maxSize > 0 && (!rotate || forceEllipses || boundaryLinkNumbers)) {
  3819. if (startPage > 1) {
  3820. if (!boundaryLinkNumbers || startPage > 3) { //need ellipsis for all options unless range is too close to beginning
  3821. var previousPageSet = makePage(startPage - 1, '...', false);
  3822. pages.unshift(previousPageSet);
  3823. }
  3824. if (boundaryLinkNumbers) {
  3825. if (startPage === 3) { //need to replace ellipsis when the buttons would be sequential
  3826. var secondPageLink = makePage(2, '2', false);
  3827. pages.unshift(secondPageLink);
  3828. }
  3829. //add the first page
  3830. var firstPageLink = makePage(1, '1', false);
  3831. pages.unshift(firstPageLink);
  3832. }
  3833. }
  3834. if (endPage < totalPages) {
  3835. if (!boundaryLinkNumbers || endPage < totalPages - 2) { //need ellipsis for all options unless range is too close to end
  3836. var nextPageSet = makePage(endPage + 1, '...', false);
  3837. pages.push(nextPageSet);
  3838. }
  3839. if (boundaryLinkNumbers) {
  3840. if (endPage === totalPages - 2) { //need to replace ellipsis when the buttons would be sequential
  3841. var secondToLastPageLink = makePage(totalPages - 1, totalPages - 1, false);
  3842. pages.push(secondToLastPageLink);
  3843. }
  3844. //add the last page
  3845. var lastPageLink = makePage(totalPages, totalPages, false);
  3846. pages.push(lastPageLink);
  3847. }
  3848. }
  3849. }
  3850. return pages;
  3851. }
  3852. var originalRender = this.render;
  3853. this.render = function() {
  3854. originalRender();
  3855. if ($scope.page > 0 && $scope.page <= $scope.totalPages) {
  3856. $scope.pages = getPages($scope.page, $scope.totalPages);
  3857. }
  3858. };
  3859. }])
  3860. .constant('uibPaginationConfig', {
  3861. itemsPerPage: 10,
  3862. boundaryLinks: false,
  3863. boundaryLinkNumbers: false,
  3864. directionLinks: true,
  3865. firstText: 'First',
  3866. previousText: 'Previous',
  3867. nextText: 'Next',
  3868. lastText: 'Last',
  3869. rotate: true,
  3870. forceEllipses: false
  3871. })
  3872. .directive('uibPagination', ['$parse', 'uibPaginationConfig', function($parse, uibPaginationConfig) {
  3873. return {
  3874. scope: {
  3875. totalItems: '=',
  3876. firstText: '@',
  3877. previousText: '@',
  3878. nextText: '@',
  3879. lastText: '@',
  3880. ngDisabled:'='
  3881. },
  3882. require: ['uibPagination', '?ngModel'],
  3883. controller: 'UibPaginationController',
  3884. controllerAs: 'pagination',
  3885. templateUrl: function(element, attrs) {
  3886. return attrs.templateUrl || 'uib/template/pagination/pagination.html';
  3887. },
  3888. replace: true,
  3889. link: function(scope, element, attrs, ctrls) {
  3890. var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
  3891. if (!ngModelCtrl) {
  3892. return; // do nothing if no ng-model
  3893. }
  3894. paginationCtrl.init(ngModelCtrl, uibPaginationConfig);
  3895. }
  3896. };
  3897. }]);
  3898. /**
  3899. * The following features are still outstanding: animation as a
  3900. * function, placement as a function, inside, support for more triggers than
  3901. * just mouse enter/leave, html tooltips, and selector delegation.
  3902. */
  3903. angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.stackedMap'])
  3904. /**
  3905. * The $tooltip service creates tooltip- and popover-like directives as well as
  3906. * houses global options for them.
  3907. */
  3908. .provider('$uibTooltip', function() {
  3909. // The default options tooltip and popover.
  3910. var defaultOptions = {
  3911. placement: 'top',
  3912. placementClassPrefix: '',
  3913. animation: true,
  3914. popupDelay: 0,
  3915. popupCloseDelay: 0,
  3916. useContentExp: false
  3917. };
  3918. // Default hide triggers for each show trigger
  3919. var triggerMap = {
  3920. 'mouseenter': 'mouseleave',
  3921. 'click': 'click',
  3922. 'outsideClick': 'outsideClick',
  3923. 'focus': 'blur',
  3924. 'none': ''
  3925. };
  3926. // The options specified to the provider globally.
  3927. var globalOptions = {};
  3928. /**
  3929. * `options({})` allows global configuration of all tooltips in the
  3930. * application.
  3931. *
  3932. * var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) {
  3933. * // place tooltips left instead of top by default
  3934. * $tooltipProvider.options( { placement: 'left' } );
  3935. * });
  3936. */
  3937. this.options = function(value) {
  3938. angular.extend(globalOptions, value);
  3939. };
  3940. /**
  3941. * This allows you to extend the set of trigger mappings available. E.g.:
  3942. *
  3943. * $tooltipProvider.setTriggers( { 'openTrigger': 'closeTrigger' } );
  3944. */
  3945. this.setTriggers = function setTriggers(triggers) {
  3946. angular.extend(triggerMap, triggers);
  3947. };
  3948. /**
  3949. * This is a helper function for translating camel-case to snake_case.
  3950. */
  3951. function snake_case(name) {
  3952. var regexp = /[A-Z]/g;
  3953. var separator = '-';
  3954. return name.replace(regexp, function(letter, pos) {
  3955. return (pos ? separator : '') + letter.toLowerCase();
  3956. });
  3957. }
  3958. /**
  3959. * Returns the actual instance of the $tooltip service.
  3960. * TODO support multiple triggers
  3961. */
  3962. this.$get = ['$window', '$compile', '$timeout', '$document', '$uibPosition', '$interpolate', '$rootScope', '$parse', '$$stackedMap', function($window, $compile, $timeout, $document, $position, $interpolate, $rootScope, $parse, $$stackedMap) {
  3963. var openedTooltips = $$stackedMap.createNew();
  3964. $document.on('keypress', keypressListener);
  3965. $rootScope.$on('$destroy', function() {
  3966. $document.off('keypress', keypressListener);
  3967. });
  3968. function keypressListener(e) {
  3969. if (e.which === 27) {
  3970. var last = openedTooltips.top();
  3971. if (last) {
  3972. last.value.close();
  3973. openedTooltips.removeTop();
  3974. last = null;
  3975. }
  3976. }
  3977. }
  3978. return function $tooltip(ttType, prefix, defaultTriggerShow, options) {
  3979. options = angular.extend({}, defaultOptions, globalOptions, options);
  3980. /**
  3981. * Returns an object of show and hide triggers.
  3982. *
  3983. * If a trigger is supplied,
  3984. * it is used to show the tooltip; otherwise, it will use the `trigger`
  3985. * option passed to the `$tooltipProvider.options` method; else it will
  3986. * default to the trigger supplied to this directive factory.
  3987. *
  3988. * The hide trigger is based on the show trigger. If the `trigger` option
  3989. * was passed to the `$tooltipProvider.options` method, it will use the
  3990. * mapped trigger from `triggerMap` or the passed trigger if the map is
  3991. * undefined; otherwise, it uses the `triggerMap` value of the show
  3992. * trigger; else it will just use the show trigger.
  3993. */
  3994. function getTriggers(trigger) {
  3995. var show = (trigger || options.trigger || defaultTriggerShow).split(' ');
  3996. var hide = show.map(function(trigger) {
  3997. return triggerMap[trigger] || trigger;
  3998. });
  3999. return {
  4000. show: show,
  4001. hide: hide
  4002. };
  4003. }
  4004. var directiveName = snake_case(ttType);
  4005. var startSym = $interpolate.startSymbol();
  4006. var endSym = $interpolate.endSymbol();
  4007. var template =
  4008. '<div '+ directiveName + '-popup ' +
  4009. 'uib-title="' + startSym + 'title' + endSym + '" ' +
  4010. (options.useContentExp ?
  4011. 'content-exp="contentExp()" ' :
  4012. 'content="' + startSym + 'content' + endSym + '" ') +
  4013. 'placement="' + startSym + 'placement' + endSym + '" ' +
  4014. 'popup-class="' + startSym + 'popupClass' + endSym + '" ' +
  4015. 'animation="animation" ' +
  4016. 'is-open="isOpen" ' +
  4017. 'origin-scope="origScope" ' +
  4018. 'class="uib-position-measure"' +
  4019. '>' +
  4020. '</div>';
  4021. return {
  4022. compile: function(tElem, tAttrs) {
  4023. var tooltipLinker = $compile(template);
  4024. return function link(scope, element, attrs, tooltipCtrl) {
  4025. var tooltip;
  4026. var tooltipLinkedScope;
  4027. var transitionTimeout;
  4028. var showTimeout;
  4029. var hideTimeout;
  4030. var positionTimeout;
  4031. var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
  4032. var triggers = getTriggers(undefined);
  4033. var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
  4034. var ttScope = scope.$new(true);
  4035. var repositionScheduled = false;
  4036. var isOpenParse = angular.isDefined(attrs[prefix + 'IsOpen']) ? $parse(attrs[prefix + 'IsOpen']) : false;
  4037. var contentParse = options.useContentExp ? $parse(attrs[ttType]) : false;
  4038. var observers = [];
  4039. var lastPlacement;
  4040. var positionTooltip = function() {
  4041. // check if tooltip exists and is not empty
  4042. if (!tooltip || !tooltip.html()) { return; }
  4043. if (!positionTimeout) {
  4044. positionTimeout = $timeout(function() {
  4045. var ttPosition = $position.positionElements(element, tooltip, ttScope.placement, appendToBody);
  4046. tooltip.css({ top: ttPosition.top + 'px', left: ttPosition.left + 'px' });
  4047. if (!tooltip.hasClass(ttPosition.placement.split('-')[0])) {
  4048. tooltip.removeClass(lastPlacement.split('-')[0]);
  4049. tooltip.addClass(ttPosition.placement.split('-')[0]);
  4050. }
  4051. if (!tooltip.hasClass(options.placementClassPrefix + ttPosition.placement)) {
  4052. tooltip.removeClass(options.placementClassPrefix + lastPlacement);
  4053. tooltip.addClass(options.placementClassPrefix + ttPosition.placement);
  4054. }
  4055. // first time through tt element will have the
  4056. // uib-position-measure class or if the placement
  4057. // has changed we need to position the arrow.
  4058. if (tooltip.hasClass('uib-position-measure')) {
  4059. $position.positionArrow(tooltip, ttPosition.placement);
  4060. tooltip.removeClass('uib-position-measure');
  4061. } else if (lastPlacement !== ttPosition.placement) {
  4062. $position.positionArrow(tooltip, ttPosition.placement);
  4063. }
  4064. lastPlacement = ttPosition.placement;
  4065. positionTimeout = null;
  4066. }, 0, false);
  4067. }
  4068. };
  4069. // Set up the correct scope to allow transclusion later
  4070. ttScope.origScope = scope;
  4071. // By default, the tooltip is not open.
  4072. // TODO add ability to start tooltip opened
  4073. ttScope.isOpen = false;
  4074. openedTooltips.add(ttScope, {
  4075. close: hide
  4076. });
  4077. function toggleTooltipBind() {
  4078. if (!ttScope.isOpen) {
  4079. showTooltipBind();
  4080. } else {
  4081. hideTooltipBind();
  4082. }
  4083. }
  4084. // Show the tooltip with delay if specified, otherwise show it immediately
  4085. function showTooltipBind() {
  4086. if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
  4087. return;
  4088. }
  4089. cancelHide();
  4090. prepareTooltip();
  4091. if (ttScope.popupDelay) {
  4092. // Do nothing if the tooltip was already scheduled to pop-up.
  4093. // This happens if show is triggered multiple times before any hide is triggered.
  4094. if (!showTimeout) {
  4095. showTimeout = $timeout(show, ttScope.popupDelay, false);
  4096. }
  4097. } else {
  4098. show();
  4099. }
  4100. }
  4101. function hideTooltipBind() {
  4102. cancelShow();
  4103. if (ttScope.popupCloseDelay) {
  4104. if (!hideTimeout) {
  4105. hideTimeout = $timeout(hide, ttScope.popupCloseDelay, false);
  4106. }
  4107. } else {
  4108. hide();
  4109. }
  4110. }
  4111. // Show the tooltip popup element.
  4112. function show() {
  4113. cancelShow();
  4114. cancelHide();
  4115. // Don't show empty tooltips.
  4116. if (!ttScope.content) {
  4117. return angular.noop;
  4118. }
  4119. createTooltip();
  4120. // And show the tooltip.
  4121. ttScope.$evalAsync(function() {
  4122. ttScope.isOpen = true;
  4123. assignIsOpen(true);
  4124. positionTooltip();
  4125. });
  4126. }
  4127. function cancelShow() {
  4128. if (showTimeout) {
  4129. $timeout.cancel(showTimeout);
  4130. showTimeout = null;
  4131. }
  4132. if (positionTimeout) {
  4133. $timeout.cancel(positionTimeout);
  4134. positionTimeout = null;
  4135. }
  4136. }
  4137. // Hide the tooltip popup element.
  4138. function hide() {
  4139. if (!ttScope) {
  4140. return;
  4141. }
  4142. // First things first: we don't show it anymore.
  4143. ttScope.$evalAsync(function() {
  4144. if (ttScope) {
  4145. ttScope.isOpen = false;
  4146. assignIsOpen(false);
  4147. // And now we remove it from the DOM. However, if we have animation, we
  4148. // need to wait for it to expire beforehand.
  4149. // FIXME: this is a placeholder for a port of the transitions library.
  4150. // The fade transition in TWBS is 150ms.
  4151. if (ttScope.animation) {
  4152. if (!transitionTimeout) {
  4153. transitionTimeout = $timeout(removeTooltip, 150, false);
  4154. }
  4155. } else {
  4156. removeTooltip();
  4157. }
  4158. }
  4159. });
  4160. }
  4161. function cancelHide() {
  4162. if (hideTimeout) {
  4163. $timeout.cancel(hideTimeout);
  4164. hideTimeout = null;
  4165. }
  4166. if (transitionTimeout) {
  4167. $timeout.cancel(transitionTimeout);
  4168. transitionTimeout = null;
  4169. }
  4170. }
  4171. function createTooltip() {
  4172. // There can only be one tooltip element per directive shown at once.
  4173. if (tooltip) {
  4174. return;
  4175. }
  4176. tooltipLinkedScope = ttScope.$new();
  4177. tooltip = tooltipLinker(tooltipLinkedScope, function(tooltip) {
  4178. if (appendToBody) {
  4179. $document.find('body').append(tooltip);
  4180. } else {
  4181. element.after(tooltip);
  4182. }
  4183. });
  4184. prepObservers();
  4185. }
  4186. function removeTooltip() {
  4187. cancelShow();
  4188. cancelHide();
  4189. unregisterObservers();
  4190. if (tooltip) {
  4191. tooltip.remove();
  4192. tooltip = null;
  4193. }
  4194. if (tooltipLinkedScope) {
  4195. tooltipLinkedScope.$destroy();
  4196. tooltipLinkedScope = null;
  4197. }
  4198. }
  4199. /**
  4200. * Set the initial scope values. Once
  4201. * the tooltip is created, the observers
  4202. * will be added to keep things in sync.
  4203. */
  4204. function prepareTooltip() {
  4205. ttScope.title = attrs[prefix + 'Title'];
  4206. if (contentParse) {
  4207. ttScope.content = contentParse(scope);
  4208. } else {
  4209. ttScope.content = attrs[ttType];
  4210. }
  4211. ttScope.popupClass = attrs[prefix + 'Class'];
  4212. ttScope.placement = angular.isDefined(attrs[prefix + 'Placement']) ? attrs[prefix + 'Placement'] : options.placement;
  4213. var placement = $position.parsePlacement(ttScope.placement);
  4214. lastPlacement = placement[1] ? placement[0] + '-' + placement[1] : placement[0];
  4215. var delay = parseInt(attrs[prefix + 'PopupDelay'], 10);
  4216. var closeDelay = parseInt(attrs[prefix + 'PopupCloseDelay'], 10);
  4217. ttScope.popupDelay = !isNaN(delay) ? delay : options.popupDelay;
  4218. ttScope.popupCloseDelay = !isNaN(closeDelay) ? closeDelay : options.popupCloseDelay;
  4219. }
  4220. function assignIsOpen(isOpen) {
  4221. if (isOpenParse && angular.isFunction(isOpenParse.assign)) {
  4222. isOpenParse.assign(scope, isOpen);
  4223. }
  4224. }
  4225. ttScope.contentExp = function() {
  4226. return ttScope.content;
  4227. };
  4228. /**
  4229. * Observe the relevant attributes.
  4230. */
  4231. attrs.$observe('disabled', function(val) {
  4232. if (val) {
  4233. cancelShow();
  4234. }
  4235. if (val && ttScope.isOpen) {
  4236. hide();
  4237. }
  4238. });
  4239. if (isOpenParse) {
  4240. scope.$watch(isOpenParse, function(val) {
  4241. if (ttScope && !val === ttScope.isOpen) {
  4242. toggleTooltipBind();
  4243. }
  4244. });
  4245. }
  4246. function prepObservers() {
  4247. observers.length = 0;
  4248. if (contentParse) {
  4249. observers.push(
  4250. scope.$watch(contentParse, function(val) {
  4251. ttScope.content = val;
  4252. if (!val && ttScope.isOpen) {
  4253. hide();
  4254. }
  4255. })
  4256. );
  4257. observers.push(
  4258. tooltipLinkedScope.$watch(function() {
  4259. if (!repositionScheduled) {
  4260. repositionScheduled = true;
  4261. tooltipLinkedScope.$$postDigest(function() {
  4262. repositionScheduled = false;
  4263. if (ttScope && ttScope.isOpen) {
  4264. positionTooltip();
  4265. }
  4266. });
  4267. }
  4268. })
  4269. );
  4270. } else {
  4271. observers.push(
  4272. attrs.$observe(ttType, function(val) {
  4273. ttScope.content = val;
  4274. if (!val && ttScope.isOpen) {
  4275. hide();
  4276. } else {
  4277. positionTooltip();
  4278. }
  4279. })
  4280. );
  4281. }
  4282. observers.push(
  4283. attrs.$observe(prefix + 'Title', function(val) {
  4284. ttScope.title = val;
  4285. if (ttScope.isOpen) {
  4286. positionTooltip();
  4287. }
  4288. })
  4289. );
  4290. observers.push(
  4291. attrs.$observe(prefix + 'Placement', function(val) {
  4292. ttScope.placement = val ? val : options.placement;
  4293. if (ttScope.isOpen) {
  4294. positionTooltip();
  4295. }
  4296. })
  4297. );
  4298. }
  4299. function unregisterObservers() {
  4300. if (observers.length) {
  4301. angular.forEach(observers, function(observer) {
  4302. observer();
  4303. });
  4304. observers.length = 0;
  4305. }
  4306. }
  4307. // hide tooltips/popovers for outsideClick trigger
  4308. function bodyHideTooltipBind(e) {
  4309. if (!ttScope || !ttScope.isOpen || !tooltip) {
  4310. return;
  4311. }
  4312. // make sure the tooltip/popover link or tool tooltip/popover itself were not clicked
  4313. if (!element[0].contains(e.target) && !tooltip[0].contains(e.target)) {
  4314. hideTooltipBind();
  4315. }
  4316. }
  4317. var unregisterTriggers = function() {
  4318. triggers.show.forEach(function(trigger) {
  4319. if (trigger === 'outsideClick') {
  4320. element.off('click', toggleTooltipBind);
  4321. } else {
  4322. element.off(trigger, showTooltipBind);
  4323. element.off(trigger, toggleTooltipBind);
  4324. }
  4325. });
  4326. triggers.hide.forEach(function(trigger) {
  4327. if (trigger === 'outsideClick') {
  4328. $document.off('click', bodyHideTooltipBind);
  4329. } else {
  4330. element.off(trigger, hideTooltipBind);
  4331. }
  4332. });
  4333. };
  4334. function prepTriggers() {
  4335. var val = attrs[prefix + 'Trigger'];
  4336. unregisterTriggers();
  4337. triggers = getTriggers(val);
  4338. if (triggers.show !== 'none') {
  4339. triggers.show.forEach(function(trigger, idx) {
  4340. if (trigger === 'outsideClick') {
  4341. element.on('click', toggleTooltipBind);
  4342. $document.on('click', bodyHideTooltipBind);
  4343. } else if (trigger === triggers.hide[idx]) {
  4344. element.on(trigger, toggleTooltipBind);
  4345. } else if (trigger) {
  4346. element.on(trigger, showTooltipBind);
  4347. element.on(triggers.hide[idx], hideTooltipBind);
  4348. }
  4349. element.on('keypress', function(e) {
  4350. if (e.which === 27) {
  4351. hideTooltipBind();
  4352. }
  4353. });
  4354. });
  4355. }
  4356. }
  4357. prepTriggers();
  4358. var animation = scope.$eval(attrs[prefix + 'Animation']);
  4359. ttScope.animation = angular.isDefined(animation) ? !!animation : options.animation;
  4360. var appendToBodyVal;
  4361. var appendKey = prefix + 'AppendToBody';
  4362. if (appendKey in attrs && attrs[appendKey] === undefined) {
  4363. appendToBodyVal = true;
  4364. } else {
  4365. appendToBodyVal = scope.$eval(attrs[appendKey]);
  4366. }
  4367. appendToBody = angular.isDefined(appendToBodyVal) ? appendToBodyVal : appendToBody;
  4368. // Make sure tooltip is destroyed and removed.
  4369. scope.$on('$destroy', function onDestroyTooltip() {
  4370. unregisterTriggers();
  4371. removeTooltip();
  4372. openedTooltips.remove(ttScope);
  4373. ttScope = null;
  4374. });
  4375. };
  4376. }
  4377. };
  4378. };
  4379. }];
  4380. })
  4381. // This is mostly ngInclude code but with a custom scope
  4382. .directive('uibTooltipTemplateTransclude', [
  4383. '$animate', '$sce', '$compile', '$templateRequest',
  4384. function ($animate, $sce, $compile, $templateRequest) {
  4385. return {
  4386. link: function(scope, elem, attrs) {
  4387. var origScope = scope.$eval(attrs.tooltipTemplateTranscludeScope);
  4388. var changeCounter = 0,
  4389. currentScope,
  4390. previousElement,
  4391. currentElement;
  4392. var cleanupLastIncludeContent = function() {
  4393. if (previousElement) {
  4394. previousElement.remove();
  4395. previousElement = null;
  4396. }
  4397. if (currentScope) {
  4398. currentScope.$destroy();
  4399. currentScope = null;
  4400. }
  4401. if (currentElement) {
  4402. $animate.leave(currentElement).then(function() {
  4403. previousElement = null;
  4404. });
  4405. previousElement = currentElement;
  4406. currentElement = null;
  4407. }
  4408. };
  4409. scope.$watch($sce.parseAsResourceUrl(attrs.uibTooltipTemplateTransclude), function(src) {
  4410. var thisChangeId = ++changeCounter;
  4411. if (src) {
  4412. //set the 2nd param to true to ignore the template request error so that the inner
  4413. //contents and scope can be cleaned up.
  4414. $templateRequest(src, true).then(function(response) {
  4415. if (thisChangeId !== changeCounter) { return; }
  4416. var newScope = origScope.$new();
  4417. var template = response;
  4418. var clone = $compile(template)(newScope, function(clone) {
  4419. cleanupLastIncludeContent();
  4420. $animate.enter(clone, elem);
  4421. });
  4422. currentScope = newScope;
  4423. currentElement = clone;
  4424. currentScope.$emit('$includeContentLoaded', src);
  4425. }, function() {
  4426. if (thisChangeId === changeCounter) {
  4427. cleanupLastIncludeContent();
  4428. scope.$emit('$includeContentError', src);
  4429. }
  4430. });
  4431. scope.$emit('$includeContentRequested', src);
  4432. } else {
  4433. cleanupLastIncludeContent();
  4434. }
  4435. });
  4436. scope.$on('$destroy', cleanupLastIncludeContent);
  4437. }
  4438. };
  4439. }])
  4440. /**
  4441. * Note that it's intentional that these classes are *not* applied through $animate.
  4442. * They must not be animated as they're expected to be present on the tooltip on
  4443. * initialization.
  4444. */
  4445. .directive('uibTooltipClasses', ['$uibPosition', function($uibPosition) {
  4446. return {
  4447. restrict: 'A',
  4448. link: function(scope, element, attrs) {
  4449. // need to set the primary position so the
  4450. // arrow has space during position measure.
  4451. // tooltip.positionTooltip()
  4452. if (scope.placement) {
  4453. // // There are no top-left etc... classes
  4454. // // in TWBS, so we need the primary position.
  4455. var position = $uibPosition.parsePlacement(scope.placement);
  4456. element.addClass(position[0]);
  4457. }
  4458. if (scope.popupClass) {
  4459. element.addClass(scope.popupClass);
  4460. }
  4461. if (scope.animation()) {
  4462. element.addClass(attrs.tooltipAnimationClass);
  4463. }
  4464. }
  4465. };
  4466. }])
  4467. .directive('uibTooltipPopup', function() {
  4468. return {
  4469. replace: true,
  4470. scope: { content: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
  4471. templateUrl: 'uib/template/tooltip/tooltip-popup.html'
  4472. };
  4473. })
  4474. .directive('uibTooltip', [ '$uibTooltip', function($uibTooltip) {
  4475. return $uibTooltip('uibTooltip', 'tooltip', 'mouseenter');
  4476. }])
  4477. .directive('uibTooltipTemplatePopup', function() {
  4478. return {
  4479. replace: true,
  4480. scope: { contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&',
  4481. originScope: '&' },
  4482. templateUrl: 'uib/template/tooltip/tooltip-template-popup.html'
  4483. };
  4484. })
  4485. .directive('uibTooltipTemplate', ['$uibTooltip', function($uibTooltip) {
  4486. return $uibTooltip('uibTooltipTemplate', 'tooltip', 'mouseenter', {
  4487. useContentExp: true
  4488. });
  4489. }])
  4490. .directive('uibTooltipHtmlPopup', function() {
  4491. return {
  4492. replace: true,
  4493. scope: { contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
  4494. templateUrl: 'uib/template/tooltip/tooltip-html-popup.html'
  4495. };
  4496. })
  4497. .directive('uibTooltipHtml', ['$uibTooltip', function($uibTooltip) {
  4498. return $uibTooltip('uibTooltipHtml', 'tooltip', 'mouseenter', {
  4499. useContentExp: true
  4500. });
  4501. }]);
  4502. /**
  4503. * The following features are still outstanding: popup delay, animation as a
  4504. * function, placement as a function, inside, support for more triggers than
  4505. * just mouse enter/leave, and selector delegatation.
  4506. */
  4507. angular.module('ui.bootstrap.popover', ['ui.bootstrap.tooltip'])
  4508. .directive('uibPopoverTemplatePopup', function() {
  4509. return {
  4510. replace: true,
  4511. scope: { uibTitle: '@', contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&',
  4512. originScope: '&' },
  4513. templateUrl: 'uib/template/popover/popover-template.html'
  4514. };
  4515. })
  4516. .directive('uibPopoverTemplate', ['$uibTooltip', function($uibTooltip) {
  4517. return $uibTooltip('uibPopoverTemplate', 'popover', 'click', {
  4518. useContentExp: true
  4519. });
  4520. }])
  4521. .directive('uibPopoverHtmlPopup', function() {
  4522. return {
  4523. replace: true,
  4524. scope: { contentExp: '&', uibTitle: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
  4525. templateUrl: 'uib/template/popover/popover-html.html'
  4526. };
  4527. })
  4528. .directive('uibPopoverHtml', ['$uibTooltip', function($uibTooltip) {
  4529. return $uibTooltip('uibPopoverHtml', 'popover', 'click', {
  4530. useContentExp: true
  4531. });
  4532. }])
  4533. .directive('uibPopoverPopup', function() {
  4534. return {
  4535. replace: true,
  4536. scope: { uibTitle: '@', content: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
  4537. templateUrl: 'uib/template/popover/popover.html'
  4538. };
  4539. })
  4540. .directive('uibPopover', ['$uibTooltip', function($uibTooltip) {
  4541. return $uibTooltip('uibPopover', 'popover', 'click');
  4542. }]);
  4543. angular.module('ui.bootstrap.progressbar', [])
  4544. .constant('uibProgressConfig', {
  4545. animate: true,
  4546. max: 100
  4547. })
  4548. .controller('UibProgressController', ['$scope', '$attrs', 'uibProgressConfig', function($scope, $attrs, progressConfig) {
  4549. var self = this,
  4550. animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate;
  4551. this.bars = [];
  4552. $scope.max = getMaxOrDefault();
  4553. this.addBar = function(bar, element, attrs) {
  4554. if (!animate) {
  4555. element.css({'transition': 'none'});
  4556. }
  4557. this.bars.push(bar);
  4558. bar.max = getMaxOrDefault();
  4559. bar.title = attrs && angular.isDefined(attrs.title) ? attrs.title : 'progressbar';
  4560. bar.$watch('value', function(value) {
  4561. bar.recalculatePercentage();
  4562. });
  4563. bar.recalculatePercentage = function() {
  4564. var totalPercentage = self.bars.reduce(function(total, bar) {
  4565. bar.percent = +(100 * bar.value / bar.max).toFixed(2);
  4566. return total + bar.percent;
  4567. }, 0);
  4568. if (totalPercentage > 100) {
  4569. bar.percent -= totalPercentage - 100;
  4570. }
  4571. };
  4572. bar.$on('$destroy', function() {
  4573. element = null;
  4574. self.removeBar(bar);
  4575. });
  4576. };
  4577. this.removeBar = function(bar) {
  4578. this.bars.splice(this.bars.indexOf(bar), 1);
  4579. this.bars.forEach(function (bar) {
  4580. bar.recalculatePercentage();
  4581. });
  4582. };
  4583. //$attrs.$observe('maxParam', function(maxParam) {
  4584. $scope.$watch('maxParam', function(maxParam) {
  4585. self.bars.forEach(function(bar) {
  4586. bar.max = getMaxOrDefault();
  4587. bar.recalculatePercentage();
  4588. });
  4589. });
  4590. function getMaxOrDefault () {
  4591. return angular.isDefined($scope.maxParam) ? $scope.maxParam : progressConfig.max;
  4592. }
  4593. }])
  4594. .directive('uibProgress', function() {
  4595. return {
  4596. replace: true,
  4597. transclude: true,
  4598. controller: 'UibProgressController',
  4599. require: 'uibProgress',
  4600. scope: {
  4601. maxParam: '=?max'
  4602. },
  4603. templateUrl: 'uib/template/progressbar/progress.html'
  4604. };
  4605. })
  4606. .directive('uibBar', function() {
  4607. return {
  4608. replace: true,
  4609. transclude: true,
  4610. require: '^uibProgress',
  4611. scope: {
  4612. value: '=',
  4613. type: '@'
  4614. },
  4615. templateUrl: 'uib/template/progressbar/bar.html',
  4616. link: function(scope, element, attrs, progressCtrl) {
  4617. progressCtrl.addBar(scope, element, attrs);
  4618. }
  4619. };
  4620. })
  4621. .directive('uibProgressbar', function() {
  4622. return {
  4623. replace: true,
  4624. transclude: true,
  4625. controller: 'UibProgressController',
  4626. scope: {
  4627. value: '=',
  4628. maxParam: '=?max',
  4629. type: '@'
  4630. },
  4631. templateUrl: 'uib/template/progressbar/progressbar.html',
  4632. link: function(scope, element, attrs, progressCtrl) {
  4633. progressCtrl.addBar(scope, angular.element(element.children()[0]), {title: attrs.title});
  4634. }
  4635. };
  4636. });
  4637. angular.module('ui.bootstrap.rating', [])
  4638. .constant('uibRatingConfig', {
  4639. max: 5,
  4640. stateOn: null,
  4641. stateOff: null,
  4642. enableReset: true,
  4643. titles : ['one', 'two', 'three', 'four', 'five']
  4644. })
  4645. .controller('UibRatingController', ['$scope', '$attrs', 'uibRatingConfig', function($scope, $attrs, ratingConfig) {
  4646. var ngModelCtrl = { $setViewValue: angular.noop },
  4647. self = this;
  4648. this.init = function(ngModelCtrl_) {
  4649. ngModelCtrl = ngModelCtrl_;
  4650. ngModelCtrl.$render = this.render;
  4651. ngModelCtrl.$formatters.push(function(value) {
  4652. if (angular.isNumber(value) && value << 0 !== value) {
  4653. value = Math.round(value);
  4654. }
  4655. return value;
  4656. });
  4657. this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn;
  4658. this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff;
  4659. this.enableReset = angular.isDefined($attrs.enableReset) ?
  4660. $scope.$parent.$eval($attrs.enableReset) : ratingConfig.enableReset;
  4661. var tmpTitles = angular.isDefined($attrs.titles) ? $scope.$parent.$eval($attrs.titles) : ratingConfig.titles;
  4662. this.titles = angular.isArray(tmpTitles) && tmpTitles.length > 0 ?
  4663. tmpTitles : ratingConfig.titles;
  4664. var ratingStates = angular.isDefined($attrs.ratingStates) ?
  4665. $scope.$parent.$eval($attrs.ratingStates) :
  4666. new Array(angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max);
  4667. $scope.range = this.buildTemplateObjects(ratingStates);
  4668. };
  4669. this.buildTemplateObjects = function(states) {
  4670. for (var i = 0, n = states.length; i < n; i++) {
  4671. states[i] = angular.extend({ index: i }, { stateOn: this.stateOn, stateOff: this.stateOff, title: this.getTitle(i) }, states[i]);
  4672. }
  4673. return states;
  4674. };
  4675. this.getTitle = function(index) {
  4676. if (index >= this.titles.length) {
  4677. return index + 1;
  4678. }
  4679. return this.titles[index];
  4680. };
  4681. $scope.rate = function(value) {
  4682. if (!$scope.readonly && value >= 0 && value <= $scope.range.length) {
  4683. var newViewValue = self.enableReset && ngModelCtrl.$viewValue === value ? 0 : value;
  4684. ngModelCtrl.$setViewValue(newViewValue);
  4685. ngModelCtrl.$render();
  4686. }
  4687. };
  4688. $scope.enter = function(value) {
  4689. if (!$scope.readonly) {
  4690. $scope.value = value;
  4691. }
  4692. $scope.onHover({value: value});
  4693. };
  4694. $scope.reset = function() {
  4695. $scope.value = ngModelCtrl.$viewValue;
  4696. $scope.onLeave();
  4697. };
  4698. $scope.onKeydown = function(evt) {
  4699. if (/(37|38|39|40)/.test(evt.which)) {
  4700. evt.preventDefault();
  4701. evt.stopPropagation();
  4702. $scope.rate($scope.value + (evt.which === 38 || evt.which === 39 ? 1 : -1));
  4703. }
  4704. };
  4705. this.render = function() {
  4706. $scope.value = ngModelCtrl.$viewValue;
  4707. $scope.title = self.getTitle($scope.value - 1);
  4708. };
  4709. }])
  4710. .directive('uibRating', function() {
  4711. return {
  4712. require: ['uibRating', 'ngModel'],
  4713. scope: {
  4714. readonly: '=?readOnly',
  4715. onHover: '&',
  4716. onLeave: '&'
  4717. },
  4718. controller: 'UibRatingController',
  4719. templateUrl: 'uib/template/rating/rating.html',
  4720. replace: true,
  4721. link: function(scope, element, attrs, ctrls) {
  4722. var ratingCtrl = ctrls[0], ngModelCtrl = ctrls[1];
  4723. ratingCtrl.init(ngModelCtrl);
  4724. }
  4725. };
  4726. });
  4727. angular.module('ui.bootstrap.tabs', [])
  4728. .controller('UibTabsetController', ['$scope', function ($scope) {
  4729. var ctrl = this,
  4730. oldIndex;
  4731. ctrl.tabs = [];
  4732. ctrl.select = function(index, evt) {
  4733. if (!destroyed) {
  4734. var previousIndex = findTabIndex(oldIndex);
  4735. var previousSelected = ctrl.tabs[previousIndex];
  4736. if (previousSelected) {
  4737. previousSelected.tab.onDeselect({
  4738. $event: evt,
  4739. $selectedIndex: index
  4740. });
  4741. if (evt && evt.isDefaultPrevented()) {
  4742. return;
  4743. }
  4744. previousSelected.tab.active = false;
  4745. }
  4746. var selected = ctrl.tabs[index];
  4747. if (selected) {
  4748. selected.tab.onSelect({
  4749. $event: evt
  4750. });
  4751. selected.tab.active = true;
  4752. ctrl.active = selected.index;
  4753. oldIndex = selected.index;
  4754. } else if (!selected && angular.isDefined(oldIndex)) {
  4755. ctrl.active = null;
  4756. oldIndex = null;
  4757. }
  4758. }
  4759. };
  4760. ctrl.addTab = function addTab(tab) {
  4761. ctrl.tabs.push({
  4762. tab: tab,
  4763. index: tab.index
  4764. });
  4765. ctrl.tabs.sort(function(t1, t2) {
  4766. if (t1.index > t2.index) {
  4767. return 1;
  4768. }
  4769. if (t1.index < t2.index) {
  4770. return -1;
  4771. }
  4772. return 0;
  4773. });
  4774. if (tab.index === ctrl.active || !angular.isDefined(ctrl.active) && ctrl.tabs.length === 1) {
  4775. var newActiveIndex = findTabIndex(tab.index);
  4776. ctrl.select(newActiveIndex);
  4777. }
  4778. };
  4779. ctrl.removeTab = function removeTab(tab) {
  4780. var index;
  4781. for (var i = 0; i < ctrl.tabs.length; i++) {
  4782. if (ctrl.tabs[i].tab === tab) {
  4783. index = i;
  4784. break;
  4785. }
  4786. }
  4787. if (ctrl.tabs[index].index === ctrl.active) {
  4788. var newActiveTabIndex = index === ctrl.tabs.length - 1 ?
  4789. index - 1 : index + 1 % ctrl.tabs.length;
  4790. ctrl.select(newActiveTabIndex);
  4791. }
  4792. ctrl.tabs.splice(index, 1);
  4793. };
  4794. $scope.$watch('tabset.active', function(val) {
  4795. if (angular.isDefined(val) && val !== oldIndex) {
  4796. ctrl.select(findTabIndex(val));
  4797. }
  4798. });
  4799. var destroyed;
  4800. $scope.$on('$destroy', function() {
  4801. destroyed = true;
  4802. });
  4803. function findTabIndex(index) {
  4804. for (var i = 0; i < ctrl.tabs.length; i++) {
  4805. if (ctrl.tabs[i].index === index) {
  4806. return i;
  4807. }
  4808. }
  4809. }
  4810. }])
  4811. .directive('uibTabset', function() {
  4812. return {
  4813. transclude: true,
  4814. replace: true,
  4815. scope: {},
  4816. bindToController: {
  4817. active: '=?',
  4818. type: '@'
  4819. },
  4820. controller: 'UibTabsetController',
  4821. controllerAs: 'tabset',
  4822. templateUrl: function(element, attrs) {
  4823. return attrs.templateUrl || 'uib/template/tabs/tabset.html';
  4824. },
  4825. link: function(scope, element, attrs) {
  4826. scope.vertical = angular.isDefined(attrs.vertical) ?
  4827. scope.$parent.$eval(attrs.vertical) : false;
  4828. scope.justified = angular.isDefined(attrs.justified) ?
  4829. scope.$parent.$eval(attrs.justified) : false;
  4830. }
  4831. };
  4832. })
  4833. .directive('uibTab', ['$parse', function($parse) {
  4834. return {
  4835. require: '^uibTabset',
  4836. replace: true,
  4837. templateUrl: function(element, attrs) {
  4838. return attrs.templateUrl || 'uib/template/tabs/tab.html';
  4839. },
  4840. transclude: true,
  4841. scope: {
  4842. heading: '@',
  4843. index: '=?',
  4844. classes: '@?',
  4845. onSelect: '&select', //This callback is called in contentHeadingTransclude
  4846. //once it inserts the tab's content into the dom
  4847. onDeselect: '&deselect'
  4848. },
  4849. controller: function() {
  4850. //Empty controller so other directives can require being 'under' a tab
  4851. },
  4852. controllerAs: 'tab',
  4853. link: function(scope, elm, attrs, tabsetCtrl, transclude) {
  4854. scope.disabled = false;
  4855. if (attrs.disable) {
  4856. scope.$parent.$watch($parse(attrs.disable), function(value) {
  4857. scope.disabled = !! value;
  4858. });
  4859. }
  4860. if (angular.isUndefined(attrs.index)) {
  4861. if (tabsetCtrl.tabs && tabsetCtrl.tabs.length) {
  4862. scope.index = Math.max.apply(null, tabsetCtrl.tabs.map(function(t) { return t.index; })) + 1;
  4863. } else {
  4864. scope.index = 0;
  4865. }
  4866. }
  4867. if (angular.isUndefined(attrs.classes)) {
  4868. scope.classes = '';
  4869. }
  4870. scope.select = function(evt) {
  4871. if (!scope.disabled) {
  4872. var index;
  4873. for (var i = 0; i < tabsetCtrl.tabs.length; i++) {
  4874. if (tabsetCtrl.tabs[i].tab === scope) {
  4875. index = i;
  4876. break;
  4877. }
  4878. }
  4879. tabsetCtrl.select(index, evt);
  4880. }
  4881. };
  4882. tabsetCtrl.addTab(scope);
  4883. scope.$on('$destroy', function() {
  4884. tabsetCtrl.removeTab(scope);
  4885. });
  4886. //We need to transclude later, once the content container is ready.
  4887. //when this link happens, we're inside a tab heading.
  4888. scope.$transcludeFn = transclude;
  4889. }
  4890. };
  4891. }])
  4892. .directive('uibTabHeadingTransclude', function() {
  4893. return {
  4894. restrict: 'A',
  4895. require: '^uibTab',
  4896. link: function(scope, elm) {
  4897. scope.$watch('headingElement', function updateHeadingElement(heading) {
  4898. if (heading) {
  4899. elm.html('');
  4900. elm.append(heading);
  4901. }
  4902. });
  4903. }
  4904. };
  4905. })
  4906. .directive('uibTabContentTransclude', function() {
  4907. return {
  4908. restrict: 'A',
  4909. require: '^uibTabset',
  4910. link: function(scope, elm, attrs) {
  4911. var tab = scope.$eval(attrs.uibTabContentTransclude).tab;
  4912. //Now our tab is ready to be transcluded: both the tab heading area
  4913. //and the tab content area are loaded. Transclude 'em both.
  4914. tab.$transcludeFn(tab.$parent, function(contents) {
  4915. angular.forEach(contents, function(node) {
  4916. if (isTabHeading(node)) {
  4917. //Let tabHeadingTransclude know.
  4918. tab.headingElement = node;
  4919. } else {
  4920. elm.append(node);
  4921. }
  4922. });
  4923. });
  4924. }
  4925. };
  4926. function isTabHeading(node) {
  4927. return node.tagName && (
  4928. node.hasAttribute('uib-tab-heading') ||
  4929. node.hasAttribute('data-uib-tab-heading') ||
  4930. node.hasAttribute('x-uib-tab-heading') ||
  4931. node.tagName.toLowerCase() === 'uib-tab-heading' ||
  4932. node.tagName.toLowerCase() === 'data-uib-tab-heading' ||
  4933. node.tagName.toLowerCase() === 'x-uib-tab-heading' ||
  4934. node.tagName.toLowerCase() === 'uib:tab-heading'
  4935. );
  4936. }
  4937. });
  4938. angular.module('ui.bootstrap.timepicker', [])
  4939. .constant('uibTimepickerConfig', {
  4940. hourStep: 1,
  4941. minuteStep: 1,
  4942. secondStep: 1,
  4943. showMeridian: true,
  4944. showSeconds: false,
  4945. meridians: null,
  4946. readonlyInput: false,
  4947. mousewheel: true,
  4948. arrowkeys: true,
  4949. showSpinners: true,
  4950. templateUrl: 'uib/template/timepicker/timepicker.html'
  4951. })
  4952. .controller('UibTimepickerController', ['$scope', '$element', '$attrs', '$parse', '$log', '$locale', 'uibTimepickerConfig', function($scope, $element, $attrs, $parse, $log, $locale, timepickerConfig) {
  4953. var selected = new Date(),
  4954. watchers = [],
  4955. ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
  4956. meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS,
  4957. padHours = angular.isDefined($attrs.padHours) ? $scope.$parent.$eval($attrs.padHours) : true;
  4958. $scope.tabindex = angular.isDefined($attrs.tabindex) ? $attrs.tabindex : 0;
  4959. $element.removeAttr('tabindex');
  4960. this.init = function(ngModelCtrl_, inputs) {
  4961. ngModelCtrl = ngModelCtrl_;
  4962. ngModelCtrl.$render = this.render;
  4963. ngModelCtrl.$formatters.unshift(function(modelValue) {
  4964. return modelValue ? new Date(modelValue) : null;
  4965. });
  4966. var hoursInputEl = inputs.eq(0),
  4967. minutesInputEl = inputs.eq(1),
  4968. secondsInputEl = inputs.eq(2);
  4969. var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel;
  4970. if (mousewheel) {
  4971. this.setupMousewheelEvents(hoursInputEl, minutesInputEl, secondsInputEl);
  4972. }
  4973. var arrowkeys = angular.isDefined($attrs.arrowkeys) ? $scope.$parent.$eval($attrs.arrowkeys) : timepickerConfig.arrowkeys;
  4974. if (arrowkeys) {
  4975. this.setupArrowkeyEvents(hoursInputEl, minutesInputEl, secondsInputEl);
  4976. }
  4977. $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput;
  4978. this.setupInputEvents(hoursInputEl, minutesInputEl, secondsInputEl);
  4979. };
  4980. var hourStep = timepickerConfig.hourStep;
  4981. if ($attrs.hourStep) {
  4982. watchers.push($scope.$parent.$watch($parse($attrs.hourStep), function(value) {
  4983. hourStep = +value;
  4984. }));
  4985. }
  4986. var minuteStep = timepickerConfig.minuteStep;
  4987. if ($attrs.minuteStep) {
  4988. watchers.push($scope.$parent.$watch($parse($attrs.minuteStep), function(value) {
  4989. minuteStep = +value;
  4990. }));
  4991. }
  4992. var min;
  4993. watchers.push($scope.$parent.$watch($parse($attrs.min), function(value) {
  4994. var dt = new Date(value);
  4995. min = isNaN(dt) ? undefined : dt;
  4996. }));
  4997. var max;
  4998. watchers.push($scope.$parent.$watch($parse($attrs.max), function(value) {
  4999. var dt = new Date(value);
  5000. max = isNaN(dt) ? undefined : dt;
  5001. }));
  5002. var disabled = false;
  5003. if ($attrs.ngDisabled) {
  5004. watchers.push($scope.$parent.$watch($parse($attrs.ngDisabled), function(value) {
  5005. disabled = value;
  5006. }));
  5007. }
  5008. $scope.noIncrementHours = function() {
  5009. var incrementedSelected = addMinutes(selected, hourStep * 60);
  5010. return disabled || incrementedSelected > max ||
  5011. incrementedSelected < selected && incrementedSelected < min;
  5012. };
  5013. $scope.noDecrementHours = function() {
  5014. var decrementedSelected = addMinutes(selected, -hourStep * 60);
  5015. return disabled || decrementedSelected < min ||
  5016. decrementedSelected > selected && decrementedSelected > max;
  5017. };
  5018. $scope.noIncrementMinutes = function() {
  5019. var incrementedSelected = addMinutes(selected, minuteStep);
  5020. return disabled || incrementedSelected > max ||
  5021. incrementedSelected < selected && incrementedSelected < min;
  5022. };
  5023. $scope.noDecrementMinutes = function() {
  5024. var decrementedSelected = addMinutes(selected, -minuteStep);
  5025. return disabled || decrementedSelected < min ||
  5026. decrementedSelected > selected && decrementedSelected > max;
  5027. };
  5028. $scope.noIncrementSeconds = function() {
  5029. var incrementedSelected = addSeconds(selected, secondStep);
  5030. return disabled || incrementedSelected > max ||
  5031. incrementedSelected < selected && incrementedSelected < min;
  5032. };
  5033. $scope.noDecrementSeconds = function() {
  5034. var decrementedSelected = addSeconds(selected, -secondStep);
  5035. return disabled || decrementedSelected < min ||
  5036. decrementedSelected > selected && decrementedSelected > max;
  5037. };
  5038. $scope.noToggleMeridian = function() {
  5039. if (selected.getHours() < 12) {
  5040. return disabled || addMinutes(selected, 12 * 60) > max;
  5041. }
  5042. return disabled || addMinutes(selected, -12 * 60) < min;
  5043. };
  5044. var secondStep = timepickerConfig.secondStep;
  5045. if ($attrs.secondStep) {
  5046. watchers.push($scope.$parent.$watch($parse($attrs.secondStep), function(value) {
  5047. secondStep = +value;
  5048. }));
  5049. }
  5050. $scope.showSeconds = timepickerConfig.showSeconds;
  5051. if ($attrs.showSeconds) {
  5052. watchers.push($scope.$parent.$watch($parse($attrs.showSeconds), function(value) {
  5053. $scope.showSeconds = !!value;
  5054. }));
  5055. }
  5056. // 12H / 24H mode
  5057. $scope.showMeridian = timepickerConfig.showMeridian;
  5058. if ($attrs.showMeridian) {
  5059. watchers.push($scope.$parent.$watch($parse($attrs.showMeridian), function(value) {
  5060. $scope.showMeridian = !!value;
  5061. if (ngModelCtrl.$error.time) {
  5062. // Evaluate from template
  5063. var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
  5064. if (angular.isDefined(hours) && angular.isDefined(minutes)) {
  5065. selected.setHours(hours);
  5066. refresh();
  5067. }
  5068. } else {
  5069. updateTemplate();
  5070. }
  5071. }));
  5072. }
  5073. // Get $scope.hours in 24H mode if valid
  5074. function getHoursFromTemplate() {
  5075. var hours = +$scope.hours;
  5076. var valid = $scope.showMeridian ? hours > 0 && hours < 13 :
  5077. hours >= 0 && hours < 24;
  5078. if (!valid || $scope.hours === '') {
  5079. return undefined;
  5080. }
  5081. if ($scope.showMeridian) {
  5082. if (hours === 12) {
  5083. hours = 0;
  5084. }
  5085. if ($scope.meridian === meridians[1]) {
  5086. hours = hours + 12;
  5087. }
  5088. }
  5089. return hours;
  5090. }
  5091. function getMinutesFromTemplate() {
  5092. var minutes = +$scope.minutes;
  5093. var valid = minutes >= 0 && minutes < 60;
  5094. if (!valid || $scope.minutes === '') {
  5095. return undefined;
  5096. }
  5097. return minutes;
  5098. }
  5099. function getSecondsFromTemplate() {
  5100. var seconds = +$scope.seconds;
  5101. return seconds >= 0 && seconds < 60 ? seconds : undefined;
  5102. }
  5103. function pad(value, noPad) {
  5104. if (value === null) {
  5105. return '';
  5106. }
  5107. return angular.isDefined(value) && value.toString().length < 2 && !noPad ?
  5108. '0' + value : value.toString();
  5109. }
  5110. // Respond on mousewheel spin
  5111. this.setupMousewheelEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
  5112. var isScrollingUp = function(e) {
  5113. if (e.originalEvent) {
  5114. e = e.originalEvent;
  5115. }
  5116. //pick correct delta variable depending on event
  5117. var delta = e.wheelDelta ? e.wheelDelta : -e.deltaY;
  5118. return e.detail || delta > 0;
  5119. };
  5120. hoursInputEl.bind('mousewheel wheel', function(e) {
  5121. if (!disabled) {
  5122. $scope.$apply(isScrollingUp(e) ? $scope.incrementHours() : $scope.decrementHours());
  5123. }
  5124. e.preventDefault();
  5125. });
  5126. minutesInputEl.bind('mousewheel wheel', function(e) {
  5127. if (!disabled) {
  5128. $scope.$apply(isScrollingUp(e) ? $scope.incrementMinutes() : $scope.decrementMinutes());
  5129. }
  5130. e.preventDefault();
  5131. });
  5132. secondsInputEl.bind('mousewheel wheel', function(e) {
  5133. if (!disabled) {
  5134. $scope.$apply(isScrollingUp(e) ? $scope.incrementSeconds() : $scope.decrementSeconds());
  5135. }
  5136. e.preventDefault();
  5137. });
  5138. };
  5139. // Respond on up/down arrowkeys
  5140. this.setupArrowkeyEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
  5141. hoursInputEl.bind('keydown', function(e) {
  5142. if (!disabled) {
  5143. if (e.which === 38) { // up
  5144. e.preventDefault();
  5145. $scope.incrementHours();
  5146. $scope.$apply();
  5147. } else if (e.which === 40) { // down
  5148. e.preventDefault();
  5149. $scope.decrementHours();
  5150. $scope.$apply();
  5151. }
  5152. }
  5153. });
  5154. minutesInputEl.bind('keydown', function(e) {
  5155. if (!disabled) {
  5156. if (e.which === 38) { // up
  5157. e.preventDefault();
  5158. $scope.incrementMinutes();
  5159. $scope.$apply();
  5160. } else if (e.which === 40) { // down
  5161. e.preventDefault();
  5162. $scope.decrementMinutes();
  5163. $scope.$apply();
  5164. }
  5165. }
  5166. });
  5167. secondsInputEl.bind('keydown', function(e) {
  5168. if (!disabled) {
  5169. if (e.which === 38) { // up
  5170. e.preventDefault();
  5171. $scope.incrementSeconds();
  5172. $scope.$apply();
  5173. } else if (e.which === 40) { // down
  5174. e.preventDefault();
  5175. $scope.decrementSeconds();
  5176. $scope.$apply();
  5177. }
  5178. }
  5179. });
  5180. };
  5181. this.setupInputEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
  5182. if ($scope.readonlyInput) {
  5183. $scope.updateHours = angular.noop;
  5184. $scope.updateMinutes = angular.noop;
  5185. $scope.updateSeconds = angular.noop;
  5186. return;
  5187. }
  5188. var invalidate = function(invalidHours, invalidMinutes, invalidSeconds) {
  5189. ngModelCtrl.$setViewValue(null);
  5190. ngModelCtrl.$setValidity('time', false);
  5191. if (angular.isDefined(invalidHours)) {
  5192. $scope.invalidHours = invalidHours;
  5193. }
  5194. if (angular.isDefined(invalidMinutes)) {
  5195. $scope.invalidMinutes = invalidMinutes;
  5196. }
  5197. if (angular.isDefined(invalidSeconds)) {
  5198. $scope.invalidSeconds = invalidSeconds;
  5199. }
  5200. };
  5201. $scope.updateHours = function() {
  5202. var hours = getHoursFromTemplate(),
  5203. minutes = getMinutesFromTemplate();
  5204. ngModelCtrl.$setDirty();
  5205. if (angular.isDefined(hours) && angular.isDefined(minutes)) {
  5206. selected.setHours(hours);
  5207. selected.setMinutes(minutes);
  5208. if (selected < min || selected > max) {
  5209. invalidate(true);
  5210. } else {
  5211. refresh('h');
  5212. }
  5213. } else {
  5214. invalidate(true);
  5215. }
  5216. };
  5217. hoursInputEl.bind('blur', function(e) {
  5218. ngModelCtrl.$setTouched();
  5219. if (modelIsEmpty()) {
  5220. makeValid();
  5221. } else if ($scope.hours === null || $scope.hours === '') {
  5222. invalidate(true);
  5223. } else if (!$scope.invalidHours && $scope.hours < 10) {
  5224. $scope.$apply(function() {
  5225. $scope.hours = pad($scope.hours, !padHours);
  5226. });
  5227. }
  5228. });
  5229. $scope.updateMinutes = function() {
  5230. var minutes = getMinutesFromTemplate(),
  5231. hours = getHoursFromTemplate();
  5232. ngModelCtrl.$setDirty();
  5233. if (angular.isDefined(minutes) && angular.isDefined(hours)) {
  5234. selected.setHours(hours);
  5235. selected.setMinutes(minutes);
  5236. if (selected < min || selected > max) {
  5237. invalidate(undefined, true);
  5238. } else {
  5239. refresh('m');
  5240. }
  5241. } else {
  5242. invalidate(undefined, true);
  5243. }
  5244. };
  5245. minutesInputEl.bind('blur', function(e) {
  5246. ngModelCtrl.$setTouched();
  5247. if (modelIsEmpty()) {
  5248. makeValid();
  5249. } else if ($scope.minutes === null) {
  5250. invalidate(undefined, true);
  5251. } else if (!$scope.invalidMinutes && $scope.minutes < 10) {
  5252. $scope.$apply(function() {
  5253. $scope.minutes = pad($scope.minutes);
  5254. });
  5255. }
  5256. });
  5257. $scope.updateSeconds = function() {
  5258. var seconds = getSecondsFromTemplate();
  5259. ngModelCtrl.$setDirty();
  5260. if (angular.isDefined(seconds)) {
  5261. selected.setSeconds(seconds);
  5262. refresh('s');
  5263. } else {
  5264. invalidate(undefined, undefined, true);
  5265. }
  5266. };
  5267. secondsInputEl.bind('blur', function(e) {
  5268. if (modelIsEmpty()) {
  5269. makeValid();
  5270. } else if (!$scope.invalidSeconds && $scope.seconds < 10) {
  5271. $scope.$apply( function() {
  5272. $scope.seconds = pad($scope.seconds);
  5273. });
  5274. }
  5275. });
  5276. };
  5277. this.render = function() {
  5278. var date = ngModelCtrl.$viewValue;
  5279. if (isNaN(date)) {
  5280. ngModelCtrl.$setValidity('time', false);
  5281. $log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
  5282. } else {
  5283. if (date) {
  5284. selected = date;
  5285. }
  5286. if (selected < min || selected > max) {
  5287. ngModelCtrl.$setValidity('time', false);
  5288. $scope.invalidHours = true;
  5289. $scope.invalidMinutes = true;
  5290. } else {
  5291. makeValid();
  5292. }
  5293. updateTemplate();
  5294. }
  5295. };
  5296. // Call internally when we know that model is valid.
  5297. function refresh(keyboardChange) {
  5298. makeValid();
  5299. ngModelCtrl.$setViewValue(new Date(selected));
  5300. updateTemplate(keyboardChange);
  5301. }
  5302. function makeValid() {
  5303. ngModelCtrl.$setValidity('time', true);
  5304. $scope.invalidHours = false;
  5305. $scope.invalidMinutes = false;
  5306. $scope.invalidSeconds = false;
  5307. }
  5308. function updateTemplate(keyboardChange) {
  5309. if (!ngModelCtrl.$modelValue) {
  5310. $scope.hours = null;
  5311. $scope.minutes = null;
  5312. $scope.seconds = null;
  5313. $scope.meridian = meridians[0];
  5314. } else {
  5315. var hours = selected.getHours(),
  5316. minutes = selected.getMinutes(),
  5317. seconds = selected.getSeconds();
  5318. if ($scope.showMeridian) {
  5319. hours = hours === 0 || hours === 12 ? 12 : hours % 12; // Convert 24 to 12 hour system
  5320. }
  5321. $scope.hours = keyboardChange === 'h' ? hours : pad(hours, !padHours);
  5322. if (keyboardChange !== 'm') {
  5323. $scope.minutes = pad(minutes);
  5324. }
  5325. $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
  5326. if (keyboardChange !== 's') {
  5327. $scope.seconds = pad(seconds);
  5328. }
  5329. $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
  5330. }
  5331. }
  5332. function addSecondsToSelected(seconds) {
  5333. selected = addSeconds(selected, seconds);
  5334. refresh();
  5335. }
  5336. function addMinutes(selected, minutes) {
  5337. return addSeconds(selected, minutes*60);
  5338. }
  5339. function addSeconds(date, seconds) {
  5340. var dt = new Date(date.getTime() + seconds * 1000);
  5341. var newDate = new Date(date);
  5342. newDate.setHours(dt.getHours(), dt.getMinutes(), dt.getSeconds());
  5343. return newDate;
  5344. }
  5345. function modelIsEmpty() {
  5346. return ($scope.hours === null || $scope.hours === '') &&
  5347. ($scope.minutes === null || $scope.minutes === '') &&
  5348. (!$scope.showSeconds || $scope.showSeconds && ($scope.seconds === null || $scope.seconds === ''));
  5349. }
  5350. $scope.showSpinners = angular.isDefined($attrs.showSpinners) ?
  5351. $scope.$parent.$eval($attrs.showSpinners) : timepickerConfig.showSpinners;
  5352. $scope.incrementHours = function() {
  5353. if (!$scope.noIncrementHours()) {
  5354. addSecondsToSelected(hourStep * 60 * 60);
  5355. }
  5356. };
  5357. $scope.decrementHours = function() {
  5358. if (!$scope.noDecrementHours()) {
  5359. addSecondsToSelected(-hourStep * 60 * 60);
  5360. }
  5361. };
  5362. $scope.incrementMinutes = function() {
  5363. if (!$scope.noIncrementMinutes()) {
  5364. addSecondsToSelected(minuteStep * 60);
  5365. }
  5366. };
  5367. $scope.decrementMinutes = function() {
  5368. if (!$scope.noDecrementMinutes()) {
  5369. addSecondsToSelected(-minuteStep * 60);
  5370. }
  5371. };
  5372. $scope.incrementSeconds = function() {
  5373. if (!$scope.noIncrementSeconds()) {
  5374. addSecondsToSelected(secondStep);
  5375. }
  5376. };
  5377. $scope.decrementSeconds = function() {
  5378. if (!$scope.noDecrementSeconds()) {
  5379. addSecondsToSelected(-secondStep);
  5380. }
  5381. };
  5382. $scope.toggleMeridian = function() {
  5383. var minutes = getMinutesFromTemplate(),
  5384. hours = getHoursFromTemplate();
  5385. if (!$scope.noToggleMeridian()) {
  5386. if (angular.isDefined(minutes) && angular.isDefined(hours)) {
  5387. addSecondsToSelected(12 * 60 * (selected.getHours() < 12 ? 60 : -60));
  5388. } else {
  5389. $scope.meridian = $scope.meridian === meridians[0] ? meridians[1] : meridians[0];
  5390. }
  5391. }
  5392. };
  5393. $scope.blur = function() {
  5394. ngModelCtrl.$setTouched();
  5395. };
  5396. $scope.$on('$destroy', function() {
  5397. while (watchers.length) {
  5398. watchers.shift()();
  5399. }
  5400. });
  5401. }])
  5402. .directive('uibTimepicker', ['uibTimepickerConfig', function(uibTimepickerConfig) {
  5403. return {
  5404. require: ['uibTimepicker', '?^ngModel'],
  5405. controller: 'UibTimepickerController',
  5406. controllerAs: 'timepicker',
  5407. replace: true,
  5408. scope: {},
  5409. templateUrl: function(element, attrs) {
  5410. return attrs.templateUrl || uibTimepickerConfig.templateUrl;
  5411. },
  5412. link: function(scope, element, attrs, ctrls) {
  5413. var timepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
  5414. if (ngModelCtrl) {
  5415. timepickerCtrl.init(ngModelCtrl, element.find('input'));
  5416. }
  5417. }
  5418. };
  5419. }]);
  5420. angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap.position'])
  5421. /**
  5422. * A helper service that can parse typeahead's syntax (string provided by users)
  5423. * Extracted to a separate service for ease of unit testing
  5424. */
  5425. .factory('uibTypeaheadParser', ['$parse', function($parse) {
  5426. // 00000111000000000000022200000000000000003333333333333330000000000044000
  5427. var TYPEAHEAD_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+([\s\S]+?)$/;
  5428. return {
  5429. parse: function(input) {
  5430. var match = input.match(TYPEAHEAD_REGEXP);
  5431. if (!match) {
  5432. throw new Error(
  5433. 'Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_"' +
  5434. ' but got "' + input + '".');
  5435. }
  5436. return {
  5437. itemName: match[3],
  5438. source: $parse(match[4]),
  5439. viewMapper: $parse(match[2] || match[1]),
  5440. modelMapper: $parse(match[1])
  5441. };
  5442. }
  5443. };
  5444. }])
  5445. .controller('UibTypeaheadController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$q', '$timeout', '$document', '$window', '$rootScope', '$$debounce', '$uibPosition', 'uibTypeaheadParser',
  5446. function(originalScope, element, attrs, $compile, $parse, $q, $timeout, $document, $window, $rootScope, $$debounce, $position, typeaheadParser) {
  5447. var HOT_KEYS = [9, 13, 27, 38, 40];
  5448. var eventDebounceTime = 200;
  5449. var modelCtrl, ngModelOptions;
  5450. //SUPPORTED ATTRIBUTES (OPTIONS)
  5451. //minimal no of characters that needs to be entered before typeahead kicks-in
  5452. var minLength = originalScope.$eval(attrs.typeaheadMinLength);
  5453. if (!minLength && minLength !== 0) {
  5454. minLength = 1;
  5455. }
  5456. originalScope.$watch(attrs.typeaheadMinLength, function (newVal) {
  5457. minLength = !newVal && newVal !== 0 ? 1 : newVal;
  5458. });
  5459. //minimal wait time after last character typed before typeahead kicks-in
  5460. var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;
  5461. //should it restrict model values to the ones selected from the popup only?
  5462. var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;
  5463. originalScope.$watch(attrs.typeaheadEditable, function (newVal) {
  5464. isEditable = newVal !== false;
  5465. });
  5466. //binding to a variable that indicates if matches are being retrieved asynchronously
  5467. var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
  5468. //a function to determine if an event should cause selection
  5469. var isSelectEvent = attrs.typeaheadShouldSelect ? $parse(attrs.typeaheadShouldSelect) : function(scope, vals) {
  5470. var evt = vals.$event;
  5471. return evt.which === 13 || evt.which === 9;
  5472. };
  5473. //a callback executed when a match is selected
  5474. var onSelectCallback = $parse(attrs.typeaheadOnSelect);
  5475. //should it select highlighted popup value when losing focus?
  5476. var isSelectOnBlur = angular.isDefined(attrs.typeaheadSelectOnBlur) ? originalScope.$eval(attrs.typeaheadSelectOnBlur) : false;
  5477. //binding to a variable that indicates if there were no results after the query is completed
  5478. var isNoResultsSetter = $parse(attrs.typeaheadNoResults).assign || angular.noop;
  5479. var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;
  5480. var appendToBody = attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false;
  5481. var appendTo = attrs.typeaheadAppendTo ?
  5482. originalScope.$eval(attrs.typeaheadAppendTo) : null;
  5483. var focusFirst = originalScope.$eval(attrs.typeaheadFocusFirst) !== false;
  5484. //If input matches an item of the list exactly, select it automatically
  5485. var selectOnExact = attrs.typeaheadSelectOnExact ? originalScope.$eval(attrs.typeaheadSelectOnExact) : false;
  5486. //binding to a variable that indicates if dropdown is open
  5487. var isOpenSetter = $parse(attrs.typeaheadIsOpen).assign || angular.noop;
  5488. var showHint = originalScope.$eval(attrs.typeaheadShowHint) || false;
  5489. //INTERNAL VARIABLES
  5490. //model setter executed upon match selection
  5491. var parsedModel = $parse(attrs.ngModel);
  5492. var invokeModelSetter = $parse(attrs.ngModel + '($$$p)');
  5493. var $setModelValue = function(scope, newValue) {
  5494. if (angular.isFunction(parsedModel(originalScope)) &&
  5495. ngModelOptions && ngModelOptions.$options && ngModelOptions.$options.getterSetter) {
  5496. return invokeModelSetter(scope, {$$$p: newValue});
  5497. }
  5498. return parsedModel.assign(scope, newValue);
  5499. };
  5500. //expressions used by typeahead
  5501. var parserResult = typeaheadParser.parse(attrs.uibTypeahead);
  5502. var hasFocus;
  5503. //Used to avoid bug in iOS webview where iOS keyboard does not fire
  5504. //mousedown & mouseup events
  5505. //Issue #3699
  5506. var selected;
  5507. //create a child scope for the typeahead directive so we are not polluting original scope
  5508. //with typeahead-specific data (matches, query etc.)
  5509. var scope = originalScope.$new();
  5510. var offDestroy = originalScope.$on('$destroy', function() {
  5511. scope.$destroy();
  5512. });
  5513. scope.$on('$destroy', offDestroy);
  5514. // WAI-ARIA
  5515. var popupId = 'typeahead-' + scope.$id + '-' + Math.floor(Math.random() * 10000);
  5516. element.attr({
  5517. 'aria-autocomplete': 'list',
  5518. 'aria-expanded': false,
  5519. 'aria-owns': popupId
  5520. });
  5521. var inputsContainer, hintInputElem;
  5522. //add read-only input to show hint
  5523. if (showHint) {
  5524. inputsContainer = angular.element('<div></div>');
  5525. inputsContainer.css('position', 'relative');
  5526. element.after(inputsContainer);
  5527. hintInputElem = element.clone();
  5528. hintInputElem.attr('placeholder', '');
  5529. hintInputElem.attr('tabindex', '-1');
  5530. hintInputElem.val('');
  5531. hintInputElem.css({
  5532. 'position': 'absolute',
  5533. 'top': '0px',
  5534. 'left': '0px',
  5535. 'border-color': 'transparent',
  5536. 'box-shadow': 'none',
  5537. 'opacity': 1,
  5538. 'background': 'none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255)',
  5539. 'color': '#999'
  5540. });
  5541. element.css({
  5542. 'position': 'relative',
  5543. 'vertical-align': 'top',
  5544. 'background-color': 'transparent'
  5545. });
  5546. inputsContainer.append(hintInputElem);
  5547. hintInputElem.after(element);
  5548. }
  5549. //pop-up element used to display matches
  5550. var popUpEl = angular.element('<div uib-typeahead-popup></div>');
  5551. popUpEl.attr({
  5552. id: popupId,
  5553. matches: 'matches',
  5554. active: 'activeIdx',
  5555. select: 'select(activeIdx, evt)',
  5556. 'move-in-progress': 'moveInProgress',
  5557. query: 'query',
  5558. position: 'position',
  5559. 'assign-is-open': 'assignIsOpen(isOpen)',
  5560. debounce: 'debounceUpdate'
  5561. });
  5562. //custom item template
  5563. if (angular.isDefined(attrs.typeaheadTemplateUrl)) {
  5564. popUpEl.attr('template-url', attrs.typeaheadTemplateUrl);
  5565. }
  5566. if (angular.isDefined(attrs.typeaheadPopupTemplateUrl)) {
  5567. popUpEl.attr('popup-template-url', attrs.typeaheadPopupTemplateUrl);
  5568. }
  5569. var resetHint = function() {
  5570. if (showHint) {
  5571. hintInputElem.val('');
  5572. }
  5573. };
  5574. var resetMatches = function() {
  5575. scope.matches = [];
  5576. scope.activeIdx = -1;
  5577. element.attr('aria-expanded', false);
  5578. resetHint();
  5579. };
  5580. var getMatchId = function(index) {
  5581. return popupId + '-option-' + index;
  5582. };
  5583. // Indicate that the specified match is the active (pre-selected) item in the list owned by this typeahead.
  5584. // This attribute is added or removed automatically when the `activeIdx` changes.
  5585. scope.$watch('activeIdx', function(index) {
  5586. if (index < 0) {
  5587. element.removeAttr('aria-activedescendant');
  5588. } else {
  5589. element.attr('aria-activedescendant', getMatchId(index));
  5590. }
  5591. });
  5592. var inputIsExactMatch = function(inputValue, index) {
  5593. if (scope.matches.length > index && inputValue) {
  5594. return inputValue.toUpperCase() === scope.matches[index].label.toUpperCase();
  5595. }
  5596. return false;
  5597. };
  5598. var getMatchesAsync = function(inputValue, evt) {
  5599. var locals = {$viewValue: inputValue};
  5600. isLoadingSetter(originalScope, true);
  5601. isNoResultsSetter(originalScope, false);
  5602. $q.when(parserResult.source(originalScope, locals)).then(function(matches) {
  5603. //it might happen that several async queries were in progress if a user were typing fast
  5604. //but we are interested only in responses that correspond to the current view value
  5605. var onCurrentRequest = inputValue === modelCtrl.$viewValue;
  5606. if (onCurrentRequest && hasFocus) {
  5607. if (matches && matches.length > 0) {
  5608. scope.activeIdx = focusFirst ? 0 : -1;
  5609. isNoResultsSetter(originalScope, false);
  5610. scope.matches.length = 0;
  5611. //transform labels
  5612. for (var i = 0; i < matches.length; i++) {
  5613. locals[parserResult.itemName] = matches[i];
  5614. scope.matches.push({
  5615. id: getMatchId(i),
  5616. label: parserResult.viewMapper(scope, locals),
  5617. model: matches[i]
  5618. });
  5619. }
  5620. scope.query = inputValue;
  5621. //position pop-up with matches - we need to re-calculate its position each time we are opening a window
  5622. //with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
  5623. //due to other elements being rendered
  5624. recalculatePosition();
  5625. element.attr('aria-expanded', true);
  5626. //Select the single remaining option if user input matches
  5627. if (selectOnExact && scope.matches.length === 1 && inputIsExactMatch(inputValue, 0)) {
  5628. if (angular.isNumber(scope.debounceUpdate) || angular.isObject(scope.debounceUpdate)) {
  5629. $$debounce(function() {
  5630. scope.select(0, evt);
  5631. }, angular.isNumber(scope.debounceUpdate) ? scope.debounceUpdate : scope.debounceUpdate['default']);
  5632. } else {
  5633. scope.select(0, evt);
  5634. }
  5635. }
  5636. if (showHint) {
  5637. var firstLabel = scope.matches[0].label;
  5638. if (angular.isString(inputValue) &&
  5639. inputValue.length > 0 &&
  5640. firstLabel.slice(0, inputValue.length).toUpperCase() === inputValue.toUpperCase()) {
  5641. hintInputElem.val(inputValue + firstLabel.slice(inputValue.length));
  5642. } else {
  5643. hintInputElem.val('');
  5644. }
  5645. }
  5646. } else {
  5647. resetMatches();
  5648. isNoResultsSetter(originalScope, true);
  5649. }
  5650. }
  5651. if (onCurrentRequest) {
  5652. isLoadingSetter(originalScope, false);
  5653. }
  5654. }, function() {
  5655. resetMatches();
  5656. isLoadingSetter(originalScope, false);
  5657. isNoResultsSetter(originalScope, true);
  5658. });
  5659. };
  5660. // bind events only if appendToBody params exist - performance feature
  5661. if (appendToBody) {
  5662. angular.element($window).on('resize', fireRecalculating);
  5663. $document.find('body').on('scroll', fireRecalculating);
  5664. }
  5665. // Declare the debounced function outside recalculating for
  5666. // proper debouncing
  5667. var debouncedRecalculate = $$debounce(function() {
  5668. // if popup is visible
  5669. if (scope.matches.length) {
  5670. recalculatePosition();
  5671. }
  5672. scope.moveInProgress = false;
  5673. }, eventDebounceTime);
  5674. // Default progress type
  5675. scope.moveInProgress = false;
  5676. function fireRecalculating() {
  5677. if (!scope.moveInProgress) {
  5678. scope.moveInProgress = true;
  5679. scope.$digest();
  5680. }
  5681. debouncedRecalculate();
  5682. }
  5683. // recalculate actual position and set new values to scope
  5684. // after digest loop is popup in right position
  5685. function recalculatePosition() {
  5686. scope.position = appendToBody ? $position.offset(element) : $position.position(element);
  5687. scope.position.top += element.prop('offsetHeight');
  5688. }
  5689. //we need to propagate user's query so we can higlight matches
  5690. scope.query = undefined;
  5691. //Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later
  5692. var timeoutPromise;
  5693. var scheduleSearchWithTimeout = function(inputValue) {
  5694. timeoutPromise = $timeout(function() {
  5695. getMatchesAsync(inputValue);
  5696. }, waitTime);
  5697. };
  5698. var cancelPreviousTimeout = function() {
  5699. if (timeoutPromise) {
  5700. $timeout.cancel(timeoutPromise);
  5701. }
  5702. };
  5703. resetMatches();
  5704. scope.assignIsOpen = function (isOpen) {
  5705. isOpenSetter(originalScope, isOpen);
  5706. };
  5707. scope.select = function(activeIdx, evt) {
  5708. //called from within the $digest() cycle
  5709. var locals = {};
  5710. var model, item;
  5711. selected = true;
  5712. locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
  5713. model = parserResult.modelMapper(originalScope, locals);
  5714. $setModelValue(originalScope, model);
  5715. modelCtrl.$setValidity('editable', true);
  5716. modelCtrl.$setValidity('parse', true);
  5717. onSelectCallback(originalScope, {
  5718. $item: item,
  5719. $model: model,
  5720. $label: parserResult.viewMapper(originalScope, locals),
  5721. $event: evt
  5722. });
  5723. resetMatches();
  5724. //return focus to the input element if a match was selected via a mouse click event
  5725. // use timeout to avoid $rootScope:inprog error
  5726. if (scope.$eval(attrs.typeaheadFocusOnSelect) !== false) {
  5727. $timeout(function() { element[0].focus(); }, 0, false);
  5728. }
  5729. };
  5730. //bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
  5731. element.on('keydown', function(evt) {
  5732. //typeahead is open and an "interesting" key was pressed
  5733. if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
  5734. return;
  5735. }
  5736. var shouldSelect = isSelectEvent(originalScope, {$event: evt});
  5737. /**
  5738. * if there's nothing selected (i.e. focusFirst) and enter or tab is hit
  5739. * or
  5740. * shift + tab is pressed to bring focus to the previous element
  5741. * then clear the results
  5742. */
  5743. if (scope.activeIdx === -1 && shouldSelect || evt.which === 9 && !!evt.shiftKey) {
  5744. resetMatches();
  5745. scope.$digest();
  5746. return;
  5747. }
  5748. evt.preventDefault();
  5749. var target;
  5750. switch (evt.which) {
  5751. case 27: // escape
  5752. evt.stopPropagation();
  5753. resetMatches();
  5754. originalScope.$digest();
  5755. break;
  5756. case 38: // up arrow
  5757. scope.activeIdx = (scope.activeIdx > 0 ? scope.activeIdx : scope.matches.length) - 1;
  5758. scope.$digest();
  5759. target = popUpEl.find('li')[scope.activeIdx];
  5760. target.parentNode.scrollTop = target.offsetTop;
  5761. break;
  5762. case 40: // down arrow
  5763. scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length;
  5764. scope.$digest();
  5765. target = popUpEl.find('li')[scope.activeIdx];
  5766. target.parentNode.scrollTop = target.offsetTop;
  5767. break;
  5768. default:
  5769. if (shouldSelect) {
  5770. scope.$apply(function() {
  5771. if (angular.isNumber(scope.debounceUpdate) || angular.isObject(scope.debounceUpdate)) {
  5772. $$debounce(function() {
  5773. scope.select(scope.activeIdx, evt);
  5774. }, angular.isNumber(scope.debounceUpdate) ? scope.debounceUpdate : scope.debounceUpdate['default']);
  5775. } else {
  5776. scope.select(scope.activeIdx, evt);
  5777. }
  5778. });
  5779. }
  5780. }
  5781. });
  5782. element.bind('focus', function (evt) {
  5783. hasFocus = true;
  5784. if (minLength === 0 && !modelCtrl.$viewValue) {
  5785. $timeout(function() {
  5786. getMatchesAsync(modelCtrl.$viewValue, evt);
  5787. }, 0);
  5788. }
  5789. });
  5790. element.bind('blur', function(evt) {
  5791. if (isSelectOnBlur && scope.matches.length && scope.activeIdx !== -1 && !selected) {
  5792. selected = true;
  5793. scope.$apply(function() {
  5794. if (angular.isObject(scope.debounceUpdate) && angular.isNumber(scope.debounceUpdate.blur)) {
  5795. $$debounce(function() {
  5796. scope.select(scope.activeIdx, evt);
  5797. }, scope.debounceUpdate.blur);
  5798. } else {
  5799. scope.select(scope.activeIdx, evt);
  5800. }
  5801. });
  5802. }
  5803. if (!isEditable && modelCtrl.$error.editable) {
  5804. modelCtrl.$setViewValue();
  5805. // Reset validity as we are clearing
  5806. modelCtrl.$setValidity('editable', true);
  5807. modelCtrl.$setValidity('parse', true);
  5808. element.val('');
  5809. }
  5810. hasFocus = false;
  5811. selected = false;
  5812. });
  5813. // Keep reference to click handler to unbind it.
  5814. var dismissClickHandler = function(evt) {
  5815. // Issue #3973
  5816. // Firefox treats right click as a click on document
  5817. if (element[0] !== evt.target && evt.which !== 3 && scope.matches.length !== 0) {
  5818. resetMatches();
  5819. if (!$rootScope.$$phase) {
  5820. originalScope.$digest();
  5821. }
  5822. }
  5823. };
  5824. $document.on('click', dismissClickHandler);
  5825. originalScope.$on('$destroy', function() {
  5826. $document.off('click', dismissClickHandler);
  5827. if (appendToBody || appendTo) {
  5828. $popup.remove();
  5829. }
  5830. if (appendToBody) {
  5831. angular.element($window).off('resize', fireRecalculating);
  5832. $document.find('body').off('scroll', fireRecalculating);
  5833. }
  5834. // Prevent jQuery cache memory leak
  5835. popUpEl.remove();
  5836. if (showHint) {
  5837. inputsContainer.remove();
  5838. }
  5839. });
  5840. var $popup = $compile(popUpEl)(scope);
  5841. if (appendToBody) {
  5842. $document.find('body').append($popup);
  5843. } else if (appendTo) {
  5844. angular.element(appendTo).eq(0).append($popup);
  5845. } else {
  5846. element.after($popup);
  5847. }
  5848. this.init = function(_modelCtrl, _ngModelOptions) {
  5849. modelCtrl = _modelCtrl;
  5850. ngModelOptions = _ngModelOptions;
  5851. scope.debounceUpdate = modelCtrl.$options && $parse(modelCtrl.$options.debounce)(originalScope);
  5852. //plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
  5853. //$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
  5854. modelCtrl.$parsers.unshift(function(inputValue) {
  5855. hasFocus = true;
  5856. if (minLength === 0 || inputValue && inputValue.length >= minLength) {
  5857. if (waitTime > 0) {
  5858. cancelPreviousTimeout();
  5859. scheduleSearchWithTimeout(inputValue);
  5860. } else {
  5861. getMatchesAsync(inputValue);
  5862. }
  5863. } else {
  5864. isLoadingSetter(originalScope, false);
  5865. cancelPreviousTimeout();
  5866. resetMatches();
  5867. }
  5868. if (isEditable) {
  5869. return inputValue;
  5870. }
  5871. if (!inputValue) {
  5872. // Reset in case user had typed something previously.
  5873. modelCtrl.$setValidity('editable', true);
  5874. return null;
  5875. }
  5876. modelCtrl.$setValidity('editable', false);
  5877. return undefined;
  5878. });
  5879. modelCtrl.$formatters.push(function(modelValue) {
  5880. var candidateViewValue, emptyViewValue;
  5881. var locals = {};
  5882. // The validity may be set to false via $parsers (see above) if
  5883. // the model is restricted to selected values. If the model
  5884. // is set manually it is considered to be valid.
  5885. if (!isEditable) {
  5886. modelCtrl.$setValidity('editable', true);
  5887. }
  5888. if (inputFormatter) {
  5889. locals.$model = modelValue;
  5890. return inputFormatter(originalScope, locals);
  5891. }
  5892. //it might happen that we don't have enough info to properly render input value
  5893. //we need to check for this situation and simply return model value if we can't apply custom formatting
  5894. locals[parserResult.itemName] = modelValue;
  5895. candidateViewValue = parserResult.viewMapper(originalScope, locals);
  5896. locals[parserResult.itemName] = undefined;
  5897. emptyViewValue = parserResult.viewMapper(originalScope, locals);
  5898. return candidateViewValue !== emptyViewValue ? candidateViewValue : modelValue;
  5899. });
  5900. };
  5901. }])
  5902. .directive('uibTypeahead', function() {
  5903. return {
  5904. controller: 'UibTypeaheadController',
  5905. require: ['ngModel', '^?ngModelOptions', 'uibTypeahead'],
  5906. link: function(originalScope, element, attrs, ctrls) {
  5907. ctrls[2].init(ctrls[0], ctrls[1]);
  5908. }
  5909. };
  5910. })
  5911. .directive('uibTypeaheadPopup', ['$$debounce', function($$debounce) {
  5912. return {
  5913. scope: {
  5914. matches: '=',
  5915. query: '=',
  5916. active: '=',
  5917. position: '&',
  5918. moveInProgress: '=',
  5919. select: '&',
  5920. assignIsOpen: '&',
  5921. debounce: '&'
  5922. },
  5923. replace: true,
  5924. templateUrl: function(element, attrs) {
  5925. return attrs.popupTemplateUrl || 'uib/template/typeahead/typeahead-popup.html';
  5926. },
  5927. link: function(scope, element, attrs) {
  5928. scope.templateUrl = attrs.templateUrl;
  5929. scope.isOpen = function() {
  5930. var isDropdownOpen = scope.matches.length > 0;
  5931. scope.assignIsOpen({ isOpen: isDropdownOpen });
  5932. return isDropdownOpen;
  5933. };
  5934. scope.isActive = function(matchIdx) {
  5935. return scope.active === matchIdx;
  5936. };
  5937. scope.selectActive = function(matchIdx) {
  5938. scope.active = matchIdx;
  5939. };
  5940. scope.selectMatch = function(activeIdx, evt) {
  5941. var debounce = scope.debounce();
  5942. if (angular.isNumber(debounce) || angular.isObject(debounce)) {
  5943. $$debounce(function() {
  5944. scope.select({activeIdx: activeIdx, evt: evt});
  5945. }, angular.isNumber(debounce) ? debounce : debounce['default']);
  5946. } else {
  5947. scope.select({activeIdx: activeIdx, evt: evt});
  5948. }
  5949. };
  5950. }
  5951. };
  5952. }])
  5953. .directive('uibTypeaheadMatch', ['$templateRequest', '$compile', '$parse', function($templateRequest, $compile, $parse) {
  5954. return {
  5955. scope: {
  5956. index: '=',
  5957. match: '=',
  5958. query: '='
  5959. },
  5960. link: function(scope, element, attrs) {
  5961. var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'uib/template/typeahead/typeahead-match.html';
  5962. $templateRequest(tplUrl).then(function(tplContent) {
  5963. var tplEl = angular.element(tplContent.trim());
  5964. element.replaceWith(tplEl);
  5965. $compile(tplEl)(scope);
  5966. });
  5967. }
  5968. };
  5969. }])
  5970. .filter('uibTypeaheadHighlight', ['$sce', '$injector', '$log', function($sce, $injector, $log) {
  5971. var isSanitizePresent;
  5972. isSanitizePresent = $injector.has('$sanitize');
  5973. function escapeRegexp(queryToEscape) {
  5974. // Regex: capture the whole query string and replace it with the string that will be used to match
  5975. // the results, for example if the capture is "a" the result will be \a
  5976. return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
  5977. }
  5978. function containsHtml(matchItem) {
  5979. return /<.*>/g.test(matchItem);
  5980. }
  5981. return function(matchItem, query) {
  5982. if (!isSanitizePresent && containsHtml(matchItem)) {
  5983. $log.warn('Unsafe use of typeahead please use ngSanitize'); // Warn the user about the danger
  5984. }
  5985. matchItem = query ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem; // Replaces the capture string with a the same string inside of a "strong" tag
  5986. if (!isSanitizePresent) {
  5987. matchItem = $sce.trustAsHtml(matchItem); // If $sanitize is not present we pack the string in a $sce object for the ng-bind-html directive
  5988. }
  5989. return matchItem;
  5990. };
  5991. }]);
  5992. angular.module("uib/template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
  5993. $templateCache.put("uib/template/accordion/accordion-group.html",
  5994. "<div class=\"panel\" ng-class=\"panelClass || 'panel-default'\">\n" +
  5995. " <div role=\"tab\" id=\"{{::headingId}}\" aria-selected=\"{{isOpen}}\" class=\"panel-heading\" ng-keypress=\"toggleOpen($event)\">\n" +
  5996. " <h4 class=\"panel-title\">\n" +
  5997. " <a role=\"button\" data-toggle=\"collapse\" href aria-expanded=\"{{isOpen}}\" aria-controls=\"{{::panelId}}\" tabindex=\"0\" class=\"accordion-toggle\" ng-click=\"toggleOpen()\" uib-accordion-transclude=\"heading\"><span uib-accordion-header ng-class=\"{'text-muted': isDisabled}\">{{heading}}</span></a>\n" +
  5998. " </h4>\n" +
  5999. " </div>\n" +
  6000. " <div id=\"{{::panelId}}\" aria-labelledby=\"{{::headingId}}\" aria-hidden=\"{{!isOpen}}\" role=\"tabpanel\" class=\"panel-collapse collapse\" uib-collapse=\"!isOpen\">\n" +
  6001. " <div class=\"panel-body\" ng-transclude></div>\n" +
  6002. " </div>\n" +
  6003. "</div>\n" +
  6004. "");
  6005. }]);
  6006. angular.module("uib/template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
  6007. $templateCache.put("uib/template/accordion/accordion.html",
  6008. "<div role=\"tablist\" class=\"panel-group\" ng-transclude></div>");
  6009. }]);
  6010. angular.module("uib/template/alert/alert.html", []).run(["$templateCache", function($templateCache) {
  6011. $templateCache.put("uib/template/alert/alert.html",
  6012. "<div class=\"alert\" ng-class=\"['alert-' + (type || 'warning'), closeable ? 'alert-dismissible' : null]\" role=\"alert\">\n" +
  6013. " <button ng-show=\"closeable\" type=\"button\" class=\"close\" ng-click=\"close({$event: $event})\">\n" +
  6014. " <span aria-hidden=\"true\">&times;</span>\n" +
  6015. " <span class=\"sr-only\">Close</span>\n" +
  6016. " </button>\n" +
  6017. " <div ng-transclude></div>\n" +
  6018. "</div>\n" +
  6019. "");
  6020. }]);
  6021. angular.module("uib/template/carousel/carousel.html", []).run(["$templateCache", function($templateCache) {
  6022. $templateCache.put("uib/template/carousel/carousel.html",
  6023. "<div ng-mouseenter=\"pause()\" ng-mouseleave=\"play()\" class=\"carousel\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\">\n" +
  6024. " <div class=\"carousel-inner\" ng-transclude></div>\n" +
  6025. " <a role=\"button\" href class=\"left carousel-control\" ng-click=\"prev()\" ng-class=\"{ disabled: isPrevDisabled() }\" ng-show=\"slides.length > 1\">\n" +
  6026. " <span aria-hidden=\"true\" class=\"glyphicon glyphicon-chevron-left\"></span>\n" +
  6027. " <span class=\"sr-only\">previous</span>\n" +
  6028. " </a>\n" +
  6029. " <a role=\"button\" href class=\"right carousel-control\" ng-click=\"next()\" ng-class=\"{ disabled: isNextDisabled() }\" ng-show=\"slides.length > 1\">\n" +
  6030. " <span aria-hidden=\"true\" class=\"glyphicon glyphicon-chevron-right\"></span>\n" +
  6031. " <span class=\"sr-only\">next</span>\n" +
  6032. " </a>\n" +
  6033. " <ol class=\"carousel-indicators\" ng-show=\"slides.length > 1\">\n" +
  6034. " <li ng-repeat=\"slide in slides | orderBy:indexOfSlide track by $index\" ng-class=\"{ active: isActive(slide) }\" ng-click=\"select(slide)\">\n" +
  6035. " <span class=\"sr-only\">slide {{ $index + 1 }} of {{ slides.length }}<span ng-if=\"isActive(slide)\">, currently active</span></span>\n" +
  6036. " </li>\n" +
  6037. " </ol>\n" +
  6038. "</div>\n" +
  6039. "");
  6040. }]);
  6041. angular.module("uib/template/carousel/slide.html", []).run(["$templateCache", function($templateCache) {
  6042. $templateCache.put("uib/template/carousel/slide.html",
  6043. "<div ng-class=\"{\n" +
  6044. " 'active': active\n" +
  6045. " }\" class=\"item text-center\" ng-transclude></div>\n" +
  6046. "");
  6047. }]);
  6048. angular.module("uib/template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
  6049. $templateCache.put("uib/template/datepicker/datepicker.html",
  6050. "<div class=\"uib-datepicker\" ng-switch=\"datepickerMode\" role=\"application\" ng-keydown=\"keydown($event)\">\n" +
  6051. " <uib-daypicker ng-switch-when=\"day\" tabindex=\"0\"></uib-daypicker>\n" +
  6052. " <uib-monthpicker ng-switch-when=\"month\" tabindex=\"0\"></uib-monthpicker>\n" +
  6053. " <uib-yearpicker ng-switch-when=\"year\" tabindex=\"0\"></uib-yearpicker>\n" +
  6054. "</div>\n" +
  6055. "");
  6056. }]);
  6057. angular.module("uib/template/datepicker/day.html", []).run(["$templateCache", function($templateCache) {
  6058. $templateCache.put("uib/template/datepicker/day.html",
  6059. "<table class=\"uib-daypicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
  6060. " <thead>\n" +
  6061. " <tr>\n" +
  6062. " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left uib-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
  6063. " <th colspan=\"{{::5 + showWeeks}}\"><button id=\"{{::uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm uib-title\" ng-click=\"toggleMode()\" ng-disabled=\"datepickerMode === maxMode\" tabindex=\"-1\"><strong>{{title}}</strong></button></th>\n" +
  6064. " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right uib-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
  6065. " </tr>\n" +
  6066. " <tr>\n" +
  6067. " <th ng-if=\"showWeeks\" class=\"text-center\"></th>\n" +
  6068. " <th ng-repeat=\"label in ::labels track by $index\" class=\"text-center\"><small aria-label=\"{{::label.full}}\">{{::label.abbr}}</small></th>\n" +
  6069. " </tr>\n" +
  6070. " </thead>\n" +
  6071. " <tbody>\n" +
  6072. " <tr class=\"uib-weeks\" ng-repeat=\"row in rows track by $index\">\n" +
  6073. " <td ng-if=\"showWeeks\" class=\"text-center h6\"><em>{{ weekNumbers[$index] }}</em></td>\n" +
  6074. " <td ng-repeat=\"dt in row\" class=\"uib-day text-center\" role=\"gridcell\"\n" +
  6075. " id=\"{{::dt.uid}}\"\n" +
  6076. " ng-class=\"::dt.customClass\">\n" +
  6077. " <button type=\"button\" class=\"btn btn-default btn-sm\"\n" +
  6078. " uib-is-class=\"\n" +
  6079. " 'btn-info' for selectedDt,\n" +
  6080. " 'active' for activeDt\n" +
  6081. " on dt\"\n" +
  6082. " ng-click=\"select(dt.date)\"\n" +
  6083. " ng-disabled=\"::dt.disabled\"\n" +
  6084. " tabindex=\"-1\"><span ng-class=\"::{'text-muted': dt.secondary, 'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
  6085. " </td>\n" +
  6086. " </tr>\n" +
  6087. " </tbody>\n" +
  6088. "</table>\n" +
  6089. "");
  6090. }]);
  6091. angular.module("uib/template/datepicker/month.html", []).run(["$templateCache", function($templateCache) {
  6092. $templateCache.put("uib/template/datepicker/month.html",
  6093. "<table class=\"uib-monthpicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
  6094. " <thead>\n" +
  6095. " <tr>\n" +
  6096. " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left uib-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
  6097. " <th><button id=\"{{::uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm uib-title\" ng-click=\"toggleMode()\" ng-disabled=\"datepickerMode === maxMode\" tabindex=\"-1\"><strong>{{title}}</strong></button></th>\n" +
  6098. " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right uib-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
  6099. " </tr>\n" +
  6100. " </thead>\n" +
  6101. " <tbody>\n" +
  6102. " <tr class=\"uib-months\" ng-repeat=\"row in rows track by $index\">\n" +
  6103. " <td ng-repeat=\"dt in row\" class=\"uib-month text-center\" role=\"gridcell\"\n" +
  6104. " id=\"{{::dt.uid}}\"\n" +
  6105. " ng-class=\"::dt.customClass\">\n" +
  6106. " <button type=\"button\" class=\"btn btn-default\"\n" +
  6107. " uib-is-class=\"\n" +
  6108. " 'btn-info' for selectedDt,\n" +
  6109. " 'active' for activeDt\n" +
  6110. " on dt\"\n" +
  6111. " ng-click=\"select(dt.date)\"\n" +
  6112. " ng-disabled=\"::dt.disabled\"\n" +
  6113. " tabindex=\"-1\"><span ng-class=\"::{'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
  6114. " </td>\n" +
  6115. " </tr>\n" +
  6116. " </tbody>\n" +
  6117. "</table>\n" +
  6118. "");
  6119. }]);
  6120. angular.module("uib/template/datepicker/year.html", []).run(["$templateCache", function($templateCache) {
  6121. $templateCache.put("uib/template/datepicker/year.html",
  6122. "<table class=\"uib-yearpicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
  6123. " <thead>\n" +
  6124. " <tr>\n" +
  6125. " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left uib-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
  6126. " <th colspan=\"{{::columns - 2}}\"><button id=\"{{::uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm uib-title\" ng-click=\"toggleMode()\" ng-disabled=\"datepickerMode === maxMode\" tabindex=\"-1\"><strong>{{title}}</strong></button></th>\n" +
  6127. " <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right uib-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
  6128. " </tr>\n" +
  6129. " </thead>\n" +
  6130. " <tbody>\n" +
  6131. " <tr class=\"uib-years\" ng-repeat=\"row in rows track by $index\">\n" +
  6132. " <td ng-repeat=\"dt in row\" class=\"uib-year text-center\" role=\"gridcell\"\n" +
  6133. " id=\"{{::dt.uid}}\"\n" +
  6134. " ng-class=\"::dt.customClass\">\n" +
  6135. " <button type=\"button\" class=\"btn btn-default\"\n" +
  6136. " uib-is-class=\"\n" +
  6137. " 'btn-info' for selectedDt,\n" +
  6138. " 'active' for activeDt\n" +
  6139. " on dt\"\n" +
  6140. " ng-click=\"select(dt.date)\"\n" +
  6141. " ng-disabled=\"::dt.disabled\"\n" +
  6142. " tabindex=\"-1\"><span ng-class=\"::{'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
  6143. " </td>\n" +
  6144. " </tr>\n" +
  6145. " </tbody>\n" +
  6146. "</table>\n" +
  6147. "");
  6148. }]);
  6149. angular.module("uib/template/datepickerPopup/popup.html", []).run(["$templateCache", function($templateCache) {
  6150. $templateCache.put("uib/template/datepickerPopup/popup.html",
  6151. "<div>\n" +
  6152. " <ul class=\"uib-datepicker-popup dropdown-menu uib-position-measure\" dropdown-nested ng-if=\"isOpen\" ng-keydown=\"keydown($event)\" ng-click=\"$event.stopPropagation()\">\n" +
  6153. " <li ng-transclude></li>\n" +
  6154. " <li ng-if=\"showButtonBar\" class=\"uib-button-bar\">\n" +
  6155. " <span class=\"btn-group pull-left\">\n" +
  6156. " <button type=\"button\" class=\"btn btn-sm btn-info uib-datepicker-current\" ng-click=\"select('today', $event)\" ng-disabled=\"isDisabled('today')\">{{ getText('current') }}</button>\n" +
  6157. " <button type=\"button\" class=\"btn btn-sm btn-danger uib-clear\" ng-click=\"select(null, $event)\">{{ getText('clear') }}</button>\n" +
  6158. " </span>\n" +
  6159. " <button type=\"button\" class=\"btn btn-sm btn-success pull-right uib-close\" ng-click=\"close($event)\">{{ getText('close') }}</button>\n" +
  6160. " </li>\n" +
  6161. " </ul>\n" +
  6162. "</div>\n" +
  6163. "");
  6164. }]);
  6165. angular.module("uib/template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
  6166. $templateCache.put("uib/template/modal/backdrop.html",
  6167. "<div class=\"modal-backdrop\"\n" +
  6168. " uib-modal-animation-class=\"fade\"\n" +
  6169. " modal-in-class=\"in\"\n" +
  6170. " ng-style=\"{'z-index': 1040 + (index && 1 || 0) + index*10}\"\n" +
  6171. "></div>\n" +
  6172. "");
  6173. }]);
  6174. angular.module("uib/template/modal/window.html", []).run(["$templateCache", function($templateCache) {
  6175. $templateCache.put("uib/template/modal/window.html",
  6176. "<div modal-render=\"{{$isRendered}}\" tabindex=\"-1\" role=\"dialog\" class=\"modal\"\n" +
  6177. " uib-modal-animation-class=\"fade\"\n" +
  6178. " modal-in-class=\"in\"\n" +
  6179. " ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\">\n" +
  6180. " <div class=\"modal-dialog {{size ? 'modal-' + size : ''}}\"><div class=\"modal-content\" uib-modal-transclude></div></div>\n" +
  6181. "</div>\n" +
  6182. "");
  6183. }]);
  6184. angular.module("uib/template/pager/pager.html", []).run(["$templateCache", function($templateCache) {
  6185. $templateCache.put("uib/template/pager/pager.html",
  6186. "<ul class=\"pager\">\n" +
  6187. " <li ng-class=\"{disabled: noPrevious()||ngDisabled, previous: align}\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
  6188. " <li ng-class=\"{disabled: noNext()||ngDisabled, next: align}\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
  6189. "</ul>\n" +
  6190. "");
  6191. }]);
  6192. angular.module("uib/template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
  6193. $templateCache.put("uib/template/pagination/pagination.html",
  6194. "<ul class=\"pagination\">\n" +
  6195. " <li ng-if=\"::boundaryLinks\" ng-class=\"{disabled: noPrevious()||ngDisabled}\" class=\"pagination-first\"><a href ng-click=\"selectPage(1, $event)\">{{::getText('first')}}</a></li>\n" +
  6196. " <li ng-if=\"::directionLinks\" ng-class=\"{disabled: noPrevious()||ngDisabled}\" class=\"pagination-prev\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
  6197. " <li ng-repeat=\"page in pages track by $index\" ng-class=\"{active: page.active,disabled: ngDisabled&&!page.active}\" class=\"pagination-page\"><a href ng-click=\"selectPage(page.number, $event)\">{{page.text}}</a></li>\n" +
  6198. " <li ng-if=\"::directionLinks\" ng-class=\"{disabled: noNext()||ngDisabled}\" class=\"pagination-next\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
  6199. " <li ng-if=\"::boundaryLinks\" ng-class=\"{disabled: noNext()||ngDisabled}\" class=\"pagination-last\"><a href ng-click=\"selectPage(totalPages, $event)\">{{::getText('last')}}</a></li>\n" +
  6200. "</ul>\n" +
  6201. "");
  6202. }]);
  6203. angular.module("uib/template/tooltip/tooltip-html-popup.html", []).run(["$templateCache", function($templateCache) {
  6204. $templateCache.put("uib/template/tooltip/tooltip-html-popup.html",
  6205. "<div class=\"tooltip\"\n" +
  6206. " tooltip-animation-class=\"fade\"\n" +
  6207. " uib-tooltip-classes\n" +
  6208. " ng-class=\"{ in: isOpen() }\">\n" +
  6209. " <div class=\"tooltip-arrow\"></div>\n" +
  6210. " <div class=\"tooltip-inner\" ng-bind-html=\"contentExp()\"></div>\n" +
  6211. "</div>\n" +
  6212. "");
  6213. }]);
  6214. angular.module("uib/template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
  6215. $templateCache.put("uib/template/tooltip/tooltip-popup.html",
  6216. "<div class=\"tooltip\"\n" +
  6217. " tooltip-animation-class=\"fade\"\n" +
  6218. " uib-tooltip-classes\n" +
  6219. " ng-class=\"{ in: isOpen() }\">\n" +
  6220. " <div class=\"tooltip-arrow\"></div>\n" +
  6221. " <div class=\"tooltip-inner\" ng-bind=\"content\"></div>\n" +
  6222. "</div>\n" +
  6223. "");
  6224. }]);
  6225. angular.module("uib/template/tooltip/tooltip-template-popup.html", []).run(["$templateCache", function($templateCache) {
  6226. $templateCache.put("uib/template/tooltip/tooltip-template-popup.html",
  6227. "<div class=\"tooltip\"\n" +
  6228. " tooltip-animation-class=\"fade\"\n" +
  6229. " uib-tooltip-classes\n" +
  6230. " ng-class=\"{ in: isOpen() }\">\n" +
  6231. " <div class=\"tooltip-arrow\"></div>\n" +
  6232. " <div class=\"tooltip-inner\"\n" +
  6233. " uib-tooltip-template-transclude=\"contentExp()\"\n" +
  6234. " tooltip-template-transclude-scope=\"originScope()\"></div>\n" +
  6235. "</div>\n" +
  6236. "");
  6237. }]);
  6238. angular.module("uib/template/popover/popover-html.html", []).run(["$templateCache", function($templateCache) {
  6239. $templateCache.put("uib/template/popover/popover-html.html",
  6240. "<div class=\"popover\"\n" +
  6241. " tooltip-animation-class=\"fade\"\n" +
  6242. " uib-tooltip-classes\n" +
  6243. " ng-class=\"{ in: isOpen() }\">\n" +
  6244. " <div class=\"arrow\"></div>\n" +
  6245. "\n" +
  6246. " <div class=\"popover-inner\">\n" +
  6247. " <h3 class=\"popover-title\" ng-bind=\"uibTitle\" ng-if=\"uibTitle\"></h3>\n" +
  6248. " <div class=\"popover-content\" ng-bind-html=\"contentExp()\"></div>\n" +
  6249. " </div>\n" +
  6250. "</div>\n" +
  6251. "");
  6252. }]);
  6253. angular.module("uib/template/popover/popover-template.html", []).run(["$templateCache", function($templateCache) {
  6254. $templateCache.put("uib/template/popover/popover-template.html",
  6255. "<div class=\"popover\"\n" +
  6256. " tooltip-animation-class=\"fade\"\n" +
  6257. " uib-tooltip-classes\n" +
  6258. " ng-class=\"{ in: isOpen() }\">\n" +
  6259. " <div class=\"arrow\"></div>\n" +
  6260. "\n" +
  6261. " <div class=\"popover-inner\">\n" +
  6262. " <h3 class=\"popover-title\" ng-bind=\"uibTitle\" ng-if=\"uibTitle\"></h3>\n" +
  6263. " <div class=\"popover-content\"\n" +
  6264. " uib-tooltip-template-transclude=\"contentExp()\"\n" +
  6265. " tooltip-template-transclude-scope=\"originScope()\"></div>\n" +
  6266. " </div>\n" +
  6267. "</div>\n" +
  6268. "");
  6269. }]);
  6270. angular.module("uib/template/popover/popover.html", []).run(["$templateCache", function($templateCache) {
  6271. $templateCache.put("uib/template/popover/popover.html",
  6272. "<div class=\"popover\"\n" +
  6273. " tooltip-animation-class=\"fade\"\n" +
  6274. " uib-tooltip-classes\n" +
  6275. " ng-class=\"{ in: isOpen() }\">\n" +
  6276. " <div class=\"arrow\"></div>\n" +
  6277. "\n" +
  6278. " <div class=\"popover-inner\">\n" +
  6279. " <h3 class=\"popover-title\" ng-bind=\"uibTitle\" ng-if=\"uibTitle\"></h3>\n" +
  6280. " <div class=\"popover-content\" ng-bind=\"content\"></div>\n" +
  6281. " </div>\n" +
  6282. "</div>\n" +
  6283. "");
  6284. }]);
  6285. angular.module("uib/template/progressbar/bar.html", []).run(["$templateCache", function($templateCache) {
  6286. $templateCache.put("uib/template/progressbar/bar.html",
  6287. "<div class=\"progress-bar\" ng-class=\"type && 'progress-bar-' + type\" role=\"progressbar\" aria-valuenow=\"{{value}}\" aria-valuemin=\"0\" aria-valuemax=\"{{max}}\" ng-style=\"{width: (percent < 100 ? percent : 100) + '%'}\" aria-valuetext=\"{{percent | number:0}}%\" aria-labelledby=\"{{::title}}\" ng-transclude></div>\n" +
  6288. "");
  6289. }]);
  6290. angular.module("uib/template/progressbar/progress.html", []).run(["$templateCache", function($templateCache) {
  6291. $templateCache.put("uib/template/progressbar/progress.html",
  6292. "<div class=\"progress\" ng-transclude aria-labelledby=\"{{::title}}\"></div>");
  6293. }]);
  6294. angular.module("uib/template/progressbar/progressbar.html", []).run(["$templateCache", function($templateCache) {
  6295. $templateCache.put("uib/template/progressbar/progressbar.html",
  6296. "<div class=\"progress\">\n" +
  6297. " <div class=\"progress-bar\" ng-class=\"type && 'progress-bar-' + type\" role=\"progressbar\" aria-valuenow=\"{{value}}\" aria-valuemin=\"0\" aria-valuemax=\"{{max}}\" ng-style=\"{width: (percent < 100 ? percent : 100) + '%'}\" aria-valuetext=\"{{percent | number:0}}%\" aria-labelledby=\"{{::title}}\" ng-transclude></div>\n" +
  6298. "</div>\n" +
  6299. "");
  6300. }]);
  6301. angular.module("uib/template/rating/rating.html", []).run(["$templateCache", function($templateCache) {
  6302. $templateCache.put("uib/template/rating/rating.html",
  6303. "<span ng-mouseleave=\"reset()\" ng-keydown=\"onKeydown($event)\" tabindex=\"0\" role=\"slider\" aria-valuemin=\"0\" aria-valuemax=\"{{range.length}}\" aria-valuenow=\"{{value}}\" aria-valuetext=\"{{title}}\">\n" +
  6304. " <span ng-repeat-start=\"r in range track by $index\" class=\"sr-only\">({{ $index < value ? '*' : ' ' }})</span>\n" +
  6305. " <i ng-repeat-end ng-mouseenter=\"enter($index + 1)\" ng-click=\"rate($index + 1)\" class=\"glyphicon\" ng-class=\"$index < value && (r.stateOn || 'glyphicon-star') || (r.stateOff || 'glyphicon-star-empty')\" ng-attr-title=\"{{r.title}}\"></i>\n" +
  6306. "</span>\n" +
  6307. "");
  6308. }]);
  6309. angular.module("uib/template/tabs/tab.html", []).run(["$templateCache", function($templateCache) {
  6310. $templateCache.put("uib/template/tabs/tab.html",
  6311. "<li ng-class=\"[{active: active, disabled: disabled}, classes]\" class=\"uib-tab nav-item\">\n" +
  6312. " <a href ng-click=\"select($event)\" class=\"nav-link\" uib-tab-heading-transclude>{{heading}}</a>\n" +
  6313. "</li>\n" +
  6314. "");
  6315. }]);
  6316. angular.module("uib/template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) {
  6317. $templateCache.put("uib/template/tabs/tabset.html",
  6318. "<div>\n" +
  6319. " <ul class=\"nav nav-{{tabset.type || 'tabs'}}\" ng-class=\"{'nav-stacked': vertical, 'nav-justified': justified}\" ng-transclude></ul>\n" +
  6320. " <div class=\"tab-content\">\n" +
  6321. " <div class=\"tab-pane\"\n" +
  6322. " ng-repeat=\"tab in tabset.tabs\"\n" +
  6323. " ng-class=\"{active: tabset.active === tab.index}\"\n" +
  6324. " uib-tab-content-transclude=\"tab\">\n" +
  6325. " </div>\n" +
  6326. " </div>\n" +
  6327. "</div>\n" +
  6328. "");
  6329. }]);
  6330. angular.module("uib/template/timepicker/timepicker.html", []).run(["$templateCache", function($templateCache) {
  6331. $templateCache.put("uib/template/timepicker/timepicker.html",
  6332. "<table class=\"uib-timepicker\">\n" +
  6333. " <tbody>\n" +
  6334. " <tr class=\"text-center\" ng-show=\"::showSpinners\">\n" +
  6335. " <td class=\"uib-increment hours\"><a ng-click=\"incrementHours()\" ng-class=\"{disabled: noIncrementHours()}\" class=\"btn btn-link\" ng-disabled=\"noIncrementHours()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-up\"></span></a></td>\n" +
  6336. " <td>&nbsp;</td>\n" +
  6337. " <td class=\"uib-increment minutes\"><a ng-click=\"incrementMinutes()\" ng-class=\"{disabled: noIncrementMinutes()}\" class=\"btn btn-link\" ng-disabled=\"noIncrementMinutes()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-up\"></span></a></td>\n" +
  6338. " <td ng-show=\"showSeconds\">&nbsp;</td>\n" +
  6339. " <td ng-show=\"showSeconds\" class=\"uib-increment seconds\"><a ng-click=\"incrementSeconds()\" ng-class=\"{disabled: noIncrementSeconds()}\" class=\"btn btn-link\" ng-disabled=\"noIncrementSeconds()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-up\"></span></a></td>\n" +
  6340. " <td ng-show=\"showMeridian\"></td>\n" +
  6341. " </tr>\n" +
  6342. " <tr>\n" +
  6343. " <td class=\"form-group uib-time hours\" ng-class=\"{'has-error': invalidHours}\">\n" +
  6344. " <input type=\"text\" placeholder=\"HH\" ng-model=\"hours\" ng-change=\"updateHours()\" class=\"form-control text-center\" ng-readonly=\"::readonlyInput\" maxlength=\"2\" tabindex=\"{{::tabindex}}\" ng-disabled=\"noIncrementHours()\" ng-blur=\"blur()\">\n" +
  6345. " </td>\n" +
  6346. " <td class=\"uib-separator\">:</td>\n" +
  6347. " <td class=\"form-group uib-time minutes\" ng-class=\"{'has-error': invalidMinutes}\">\n" +
  6348. " <input type=\"text\" placeholder=\"MM\" ng-model=\"minutes\" ng-change=\"updateMinutes()\" class=\"form-control text-center\" ng-readonly=\"::readonlyInput\" maxlength=\"2\" tabindex=\"{{::tabindex}}\" ng-disabled=\"noIncrementMinutes()\" ng-blur=\"blur()\">\n" +
  6349. " </td>\n" +
  6350. " <td ng-show=\"showSeconds\" class=\"uib-separator\">:</td>\n" +
  6351. " <td class=\"form-group uib-time seconds\" ng-class=\"{'has-error': invalidSeconds}\" ng-show=\"showSeconds\">\n" +
  6352. " <input type=\"text\" placeholder=\"SS\" ng-model=\"seconds\" ng-change=\"updateSeconds()\" class=\"form-control text-center\" ng-readonly=\"readonlyInput\" maxlength=\"2\" tabindex=\"{{::tabindex}}\" ng-disabled=\"noIncrementSeconds()\" ng-blur=\"blur()\">\n" +
  6353. " </td>\n" +
  6354. " <td ng-show=\"showMeridian\" class=\"uib-time am-pm\"><button type=\"button\" ng-class=\"{disabled: noToggleMeridian()}\" class=\"btn btn-default text-center\" ng-click=\"toggleMeridian()\" ng-disabled=\"noToggleMeridian()\" tabindex=\"{{::tabindex}}\">{{meridian}}</button></td>\n" +
  6355. " </tr>\n" +
  6356. " <tr class=\"text-center\" ng-show=\"::showSpinners\">\n" +
  6357. " <td class=\"uib-decrement hours\"><a ng-click=\"decrementHours()\" ng-class=\"{disabled: noDecrementHours()}\" class=\"btn btn-link\" ng-disabled=\"noDecrementHours()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-down\"></span></a></td>\n" +
  6358. " <td>&nbsp;</td>\n" +
  6359. " <td class=\"uib-decrement minutes\"><a ng-click=\"decrementMinutes()\" ng-class=\"{disabled: noDecrementMinutes()}\" class=\"btn btn-link\" ng-disabled=\"noDecrementMinutes()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-down\"></span></a></td>\n" +
  6360. " <td ng-show=\"showSeconds\">&nbsp;</td>\n" +
  6361. " <td ng-show=\"showSeconds\" class=\"uib-decrement seconds\"><a ng-click=\"decrementSeconds()\" ng-class=\"{disabled: noDecrementSeconds()}\" class=\"btn btn-link\" ng-disabled=\"noDecrementSeconds()\" tabindex=\"{{::tabindex}}\"><span class=\"glyphicon glyphicon-chevron-down\"></span></a></td>\n" +
  6362. " <td ng-show=\"showMeridian\"></td>\n" +
  6363. " </tr>\n" +
  6364. " </tbody>\n" +
  6365. "</table>\n" +
  6366. "");
  6367. }]);
  6368. angular.module("uib/template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) {
  6369. $templateCache.put("uib/template/typeahead/typeahead-match.html",
  6370. "<a href\n" +
  6371. " tabindex=\"-1\"\n" +
  6372. " ng-bind-html=\"match.label | uibTypeaheadHighlight:query\"\n" +
  6373. " ng-attr-title=\"{{match.label}}\"></a>\n" +
  6374. "");
  6375. }]);
  6376. angular.module("uib/template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) {
  6377. $templateCache.put("uib/template/typeahead/typeahead-popup.html",
  6378. "<ul class=\"dropdown-menu\" ng-show=\"isOpen() && !moveInProgress\" ng-style=\"{top: position().top+'px', left: position().left+'px'}\" role=\"listbox\" aria-hidden=\"{{!isOpen()}}\">\n" +
  6379. " <li ng-repeat=\"match in matches track by $index\" ng-class=\"{active: isActive($index) }\" ng-mouseenter=\"selectActive($index)\" ng-click=\"selectMatch($index, $event)\" role=\"option\" id=\"{{::match.id}}\">\n" +
  6380. " <div uib-typeahead-match index=\"$index\" match=\"match\" query=\"query\" template-url=\"templateUrl\"></div>\n" +
  6381. " </li>\n" +
  6382. "</ul>\n" +
  6383. "");
  6384. }]);
  6385. angular.module('ui.bootstrap.carousel').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibCarouselCss && angular.element(document).find('head').prepend('<style type="text/css">.ng-animate.item:not(.left):not(.right){-webkit-transition:0s ease-in-out left;transition:0s ease-in-out left}</style>'); angular.$$uibCarouselCss = true; });
  6386. angular.module('ui.bootstrap.datepicker').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibDatepickerCss && angular.element(document).find('head').prepend('<style type="text/css">.uib-datepicker .uib-title{width:100%;}.uib-day button,.uib-month button,.uib-year button{min-width:100%;}.uib-left,.uib-right{width:100%}</style>'); angular.$$uibDatepickerCss = true; });
  6387. angular.module('ui.bootstrap.position').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibPositionCss && angular.element(document).find('head').prepend('<style type="text/css">.uib-position-measure{display:block !important;visibility:hidden !important;position:absolute !important;top:-9999px !important;left:-9999px !important;}.uib-position-scrollbar-measure{position:absolute !important;top:-9999px !important;width:50px !important;height:50px !important;overflow:scroll !important;}.uib-position-body-scrollbar-measure{overflow:scroll !important;}</style>'); angular.$$uibPositionCss = true; });
  6388. angular.module('ui.bootstrap.datepickerPopup').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibDatepickerpopupCss && angular.element(document).find('head').prepend('<style type="text/css">.uib-datepicker-popup.dropdown-menu{display:block;float:none;margin:0;}.uib-button-bar{padding:10px 9px 2px;}</style>'); angular.$$uibDatepickerpopupCss = true; });
  6389. angular.module('ui.bootstrap.tooltip').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibTooltipCss && angular.element(document).find('head').prepend('<style type="text/css">[uib-tooltip-popup].tooltip.top-left > .tooltip-arrow,[uib-tooltip-popup].tooltip.top-right > .tooltip-arrow,[uib-tooltip-popup].tooltip.bottom-left > .tooltip-arrow,[uib-tooltip-popup].tooltip.bottom-right > .tooltip-arrow,[uib-tooltip-popup].tooltip.left-top > .tooltip-arrow,[uib-tooltip-popup].tooltip.left-bottom > .tooltip-arrow,[uib-tooltip-popup].tooltip.right-top > .tooltip-arrow,[uib-tooltip-popup].tooltip.right-bottom > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.top-left > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.top-right > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.bottom-left > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.bottom-right > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.left-top > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.left-bottom > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.right-top > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.right-bottom > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.top-left > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.top-right > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.bottom-left > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.bottom-right > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.left-top > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.left-bottom > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.right-top > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.right-bottom > .tooltip-arrow,[uib-popover-popup].popover.top-left > .arrow,[uib-popover-popup].popover.top-right > .arrow,[uib-popover-popup].popover.bottom-left > .arrow,[uib-popover-popup].popover.bottom-right > .arrow,[uib-popover-popup].popover.left-top > .arrow,[uib-popover-popup].popover.left-bottom > .arrow,[uib-popover-popup].popover.right-top > .arrow,[uib-popover-popup].popover.right-bottom > .arrow,[uib-popover-html-popup].popover.top-left > .arrow,[uib-popover-html-popup].popover.top-right > .arrow,[uib-popover-html-popup].popover.bottom-left > .arrow,[uib-popover-html-popup].popover.bottom-right > .arrow,[uib-popover-html-popup].popover.left-top > .arrow,[uib-popover-html-popup].popover.left-bottom > .arrow,[uib-popover-html-popup].popover.right-top > .arrow,[uib-popover-html-popup].popover.right-bottom > .arrow,[uib-popover-template-popup].popover.top-left > .arrow,[uib-popover-template-popup].popover.top-right > .arrow,[uib-popover-template-popup].popover.bottom-left > .arrow,[uib-popover-template-popup].popover.bottom-right > .arrow,[uib-popover-template-popup].popover.left-top > .arrow,[uib-popover-template-popup].popover.left-bottom > .arrow,[uib-popover-template-popup].popover.right-top > .arrow,[uib-popover-template-popup].popover.right-bottom > .arrow{top:auto;bottom:auto;left:auto;right:auto;margin:0;}[uib-popover-popup].popover,[uib-popover-html-popup].popover,[uib-popover-template-popup].popover{display:block !important;}</style>'); angular.$$uibTooltipCss = true; });
  6390. angular.module('ui.bootstrap.timepicker').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibTimepickerCss && angular.element(document).find('head').prepend('<style type="text/css">.uib-time input{width:50px;}</style>'); angular.$$uibTimepickerCss = true; });
  6391. angular.module('ui.bootstrap.typeahead').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibTypeaheadCss && angular.element(document).find('head').prepend('<style type="text/css">[uib-typeahead-popup].dropdown-menu{display:block;}</style>'); angular.$$uibTypeaheadCss = true; });