ui-bootstrap-tpls2.js 258 KB

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