angular-scenario.js 788 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223
  1. /*!
  2. * jQuery JavaScript Library v1.7.2
  3. * http://jquery.com/
  4. *
  5. * Copyright 2011, John Resig
  6. * Dual licensed under the MIT or GPL Version 2 licenses.
  7. * http://jquery.org/license
  8. *
  9. * Includes Sizzle.js
  10. * http://sizzlejs.com/
  11. * Copyright 2011, The Dojo Foundation
  12. * Released under the MIT, BSD, and GPL Licenses.
  13. *
  14. * Date: Wed Mar 21 12:46:34 2012 -0700
  15. */
  16. (function( window, undefined ) {
  17. 'use strict';
  18. // Use the correct document accordingly with window argument (sandbox)
  19. var document = window.document,
  20. navigator = window.navigator,
  21. location = window.location;
  22. var jQuery = (function() {
  23. // Define a local copy of jQuery
  24. var jQuery = function( selector, context ) {
  25. // The jQuery object is actually just the init constructor 'enhanced'
  26. return new jQuery.fn.init( selector, context, rootjQuery );
  27. },
  28. // Map over jQuery in case of overwrite
  29. _jQuery = window.jQuery,
  30. // Map over the $ in case of overwrite
  31. _$ = window.$,
  32. // A central reference to the root jQuery(document)
  33. rootjQuery,
  34. // A simple way to check for HTML strings or ID strings
  35. // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
  36. quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
  37. // Check if a string has a non-whitespace character in it
  38. rnotwhite = /\S/,
  39. // Used for trimming whitespace
  40. trimLeft = /^\s+/,
  41. trimRight = /\s+$/,
  42. // Match a standalone tag
  43. rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
  44. // JSON RegExp
  45. rvalidchars = /^[\],:{}\s]*$/,
  46. rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
  47. rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
  48. rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
  49. // Useragent RegExp
  50. rwebkit = /(webkit)[ \/]([\w.]+)/,
  51. ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
  52. rmsie = /(msie) ([\w.]+)/,
  53. rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
  54. // Matches dashed string for camelizing
  55. rdashAlpha = /-([a-z]|[0-9])/ig,
  56. rmsPrefix = /^-ms-/,
  57. // Used by jQuery.camelCase as callback to replace()
  58. fcamelCase = function( all, letter ) {
  59. return ( letter + "" ).toUpperCase();
  60. },
  61. // Keep a UserAgent string for use with jQuery.browser
  62. userAgent = navigator.userAgent,
  63. // For matching the engine and version of the browser
  64. browserMatch,
  65. // The deferred used on DOM ready
  66. readyList,
  67. // The ready event handler
  68. DOMContentLoaded,
  69. // Save a reference to some core methods
  70. toString = Object.prototype.toString,
  71. hasOwn = Object.prototype.hasOwnProperty,
  72. push = Array.prototype.push,
  73. slice = Array.prototype.slice,
  74. trim = String.prototype.trim,
  75. indexOf = Array.prototype.indexOf,
  76. // [[Class]] -> type pairs
  77. class2type = {};
  78. jQuery.fn = jQuery.prototype = {
  79. constructor: jQuery,
  80. init: function( selector, context, rootjQuery ) {
  81. var match, elem, ret, doc;
  82. // Handle $(""), $(null), or $(undefined)
  83. if ( !selector ) {
  84. return this;
  85. }
  86. // Handle $(DOMElement)
  87. if ( selector.nodeType ) {
  88. this.context = this[0] = selector;
  89. this.length = 1;
  90. return this;
  91. }
  92. // The body element only exists once, optimize finding it
  93. if ( selector === "body" && !context && document.body ) {
  94. this.context = document;
  95. this[0] = document.body;
  96. this.selector = selector;
  97. this.length = 1;
  98. return this;
  99. }
  100. // Handle HTML strings
  101. if ( typeof selector === "string" ) {
  102. // Are we dealing with HTML string or an ID?
  103. if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
  104. // Assume that strings that start and end with <> are HTML and skip the regex check
  105. match = [ null, selector, null ];
  106. } else {
  107. match = quickExpr.exec( selector );
  108. }
  109. // Verify a match, and that no context was specified for #id
  110. if ( match && (match[1] || !context) ) {
  111. // HANDLE: $(html) -> $(array)
  112. if ( match[1] ) {
  113. context = context instanceof jQuery ? context[0] : context;
  114. doc = ( context ? context.ownerDocument || context : document );
  115. // If a single string is passed in and it's a single tag
  116. // just do a createElement and skip the rest
  117. ret = rsingleTag.exec( selector );
  118. if ( ret ) {
  119. if ( jQuery.isPlainObject( context ) ) {
  120. selector = [ document.createElement( ret[1] ) ];
  121. jQuery.fn.attr.call( selector, context, true );
  122. } else {
  123. selector = [ doc.createElement( ret[1] ) ];
  124. }
  125. } else {
  126. ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
  127. selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
  128. }
  129. return jQuery.merge( this, selector );
  130. // HANDLE: $("#id")
  131. } else {
  132. elem = document.getElementById( match[2] );
  133. // Check parentNode to catch when Blackberry 4.6 returns
  134. // nodes that are no longer in the document #6963
  135. if ( elem && elem.parentNode ) {
  136. // Handle the case where IE and Opera return items
  137. // by name instead of ID
  138. if ( elem.id !== match[2] ) {
  139. return rootjQuery.find( selector );
  140. }
  141. // Otherwise, we inject the element directly into the jQuery object
  142. this.length = 1;
  143. this[0] = elem;
  144. }
  145. this.context = document;
  146. this.selector = selector;
  147. return this;
  148. }
  149. // HANDLE: $(expr, $(...))
  150. } else if ( !context || context.jquery ) {
  151. return ( context || rootjQuery ).find( selector );
  152. // HANDLE: $(expr, context)
  153. // (which is just equivalent to: $(context).find(expr)
  154. } else {
  155. return this.constructor( context ).find( selector );
  156. }
  157. // HANDLE: $(function)
  158. // Shortcut for document ready
  159. } else if ( jQuery.isFunction( selector ) ) {
  160. return rootjQuery.ready( selector );
  161. }
  162. if ( selector.selector !== undefined ) {
  163. this.selector = selector.selector;
  164. this.context = selector.context;
  165. }
  166. return jQuery.makeArray( selector, this );
  167. },
  168. // Start with an empty selector
  169. selector: "",
  170. // The current version of jQuery being used
  171. jquery: "1.7.2",
  172. // The default length of a jQuery object is 0
  173. length: 0,
  174. // The number of elements contained in the matched element set
  175. size: function() {
  176. return this.length;
  177. },
  178. toArray: function() {
  179. return slice.call( this, 0 );
  180. },
  181. // Get the Nth element in the matched element set OR
  182. // Get the whole matched element set as a clean array
  183. get: function( num ) {
  184. return num == null ?
  185. // Return a 'clean' array
  186. this.toArray() :
  187. // Return just the object
  188. ( num < 0 ? this[ this.length + num ] : this[ num ] );
  189. },
  190. // Take an array of elements and push it onto the stack
  191. // (returning the new matched element set)
  192. pushStack: function( elems, name, selector ) {
  193. // Build a new jQuery matched element set
  194. var ret = this.constructor();
  195. if ( jQuery.isArray( elems ) ) {
  196. push.apply( ret, elems );
  197. } else {
  198. jQuery.merge( ret, elems );
  199. }
  200. // Add the old object onto the stack (as a reference)
  201. ret.prevObject = this;
  202. ret.context = this.context;
  203. if ( name === "find" ) {
  204. ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
  205. } else if ( name ) {
  206. ret.selector = this.selector + "." + name + "(" + selector + ")";
  207. }
  208. // Return the newly-formed element set
  209. return ret;
  210. },
  211. // Execute a callback for every element in the matched set.
  212. // (You can seed the arguments with an array of args, but this is
  213. // only used internally.)
  214. each: function( callback, args ) {
  215. return jQuery.each( this, callback, args );
  216. },
  217. ready: function( fn ) {
  218. // Attach the listeners
  219. jQuery.bindReady();
  220. // Add the callback
  221. readyList.add( fn );
  222. return this;
  223. },
  224. eq: function( i ) {
  225. i = +i;
  226. return i === -1 ?
  227. this.slice( i ) :
  228. this.slice( i, i + 1 );
  229. },
  230. first: function() {
  231. return this.eq( 0 );
  232. },
  233. last: function() {
  234. return this.eq( -1 );
  235. },
  236. slice: function() {
  237. return this.pushStack( slice.apply( this, arguments ),
  238. "slice", slice.call(arguments).join(",") );
  239. },
  240. map: function( callback ) {
  241. return this.pushStack( jQuery.map(this, function( elem, i ) {
  242. return callback.call( elem, i, elem );
  243. }));
  244. },
  245. end: function() {
  246. return this.prevObject || this.constructor(null);
  247. },
  248. // For internal use only.
  249. // Behaves like an Array's method, not like a jQuery method.
  250. push: push,
  251. sort: [].sort,
  252. splice: [].splice
  253. };
  254. // Give the init function the jQuery prototype for later instantiation
  255. jQuery.fn.init.prototype = jQuery.fn;
  256. jQuery.extend = jQuery.fn.extend = function() {
  257. var options, name, src, copy, copyIsArray, clone,
  258. target = arguments[0] || {},
  259. i = 1,
  260. length = arguments.length,
  261. deep = false;
  262. // Handle a deep copy situation
  263. if ( typeof target === "boolean" ) {
  264. deep = target;
  265. target = arguments[1] || {};
  266. // skip the boolean and the target
  267. i = 2;
  268. }
  269. // Handle case when target is a string or something (possible in deep copy)
  270. if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
  271. target = {};
  272. }
  273. // extend jQuery itself if only one argument is passed
  274. if ( length === i ) {
  275. target = this;
  276. --i;
  277. }
  278. for ( ; i < length; i++ ) {
  279. // Only deal with non-null/undefined values
  280. if ( (options = arguments[ i ]) != null ) {
  281. // Extend the base object
  282. for ( name in options ) {
  283. src = target[ name ];
  284. copy = options[ name ];
  285. // Prevent never-ending loop
  286. if ( target === copy ) {
  287. continue;
  288. }
  289. // Recurse if we're merging plain objects or arrays
  290. if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
  291. if ( copyIsArray ) {
  292. copyIsArray = false;
  293. clone = src && jQuery.isArray(src) ? src : [];
  294. } else {
  295. clone = src && jQuery.isPlainObject(src) ? src : {};
  296. }
  297. // Never move original objects, clone them
  298. target[ name ] = jQuery.extend( deep, clone, copy );
  299. // Don't bring in undefined values
  300. } else if ( copy !== undefined ) {
  301. target[ name ] = copy;
  302. }
  303. }
  304. }
  305. }
  306. // Return the modified object
  307. return target;
  308. };
  309. jQuery.extend({
  310. noConflict: function( deep ) {
  311. if ( window.$ === jQuery ) {
  312. window.$ = _$;
  313. }
  314. if ( deep && window.jQuery === jQuery ) {
  315. window.jQuery = _jQuery;
  316. }
  317. return jQuery;
  318. },
  319. // Is the DOM ready to be used? Set to true once it occurs.
  320. isReady: false,
  321. // A counter to track how many items to wait for before
  322. // the ready event fires. See #6781
  323. readyWait: 1,
  324. // Hold (or release) the ready event
  325. holdReady: function( hold ) {
  326. if ( hold ) {
  327. jQuery.readyWait++;
  328. } else {
  329. jQuery.ready( true );
  330. }
  331. },
  332. // Handle when the DOM is ready
  333. ready: function( wait ) {
  334. // Either a released hold or an DOMready/load event and not yet ready
  335. if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
  336. // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
  337. if ( !document.body ) {
  338. return setTimeout( jQuery.ready, 1 );
  339. }
  340. // Remember that the DOM is ready
  341. jQuery.isReady = true;
  342. // If a normal DOM Ready event fired, decrement, and wait if need be
  343. if ( wait !== true && --jQuery.readyWait > 0 ) {
  344. return;
  345. }
  346. // If there are functions bound, to execute
  347. readyList.fireWith( document, [ jQuery ] );
  348. // Trigger any bound ready events
  349. if ( jQuery.fn.trigger ) {
  350. jQuery( document ).trigger( "ready" ).off( "ready" );
  351. }
  352. }
  353. },
  354. bindReady: function() {
  355. if ( readyList ) {
  356. return;
  357. }
  358. readyList = jQuery.Callbacks( "once memory" );
  359. // Catch cases where $(document).ready() is called after the
  360. // browser event has already occurred.
  361. if ( document.readyState === "complete" ) {
  362. // Handle it asynchronously to allow scripts the opportunity to delay ready
  363. return setTimeout( jQuery.ready, 1 );
  364. }
  365. // Mozilla, Opera and webkit nightlies currently support this event
  366. if ( document.addEventListener ) {
  367. // Use the handy event callback
  368. document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
  369. // A fallback to window.onload, that will always work
  370. window.addEventListener( "load", jQuery.ready, false );
  371. // If IE event model is used
  372. } else if ( document.attachEvent ) {
  373. // ensure firing before onload,
  374. // maybe late but safe also for iframes
  375. document.attachEvent( "onreadystatechange", DOMContentLoaded );
  376. // A fallback to window.onload, that will always work
  377. window.attachEvent( "onload", jQuery.ready );
  378. // If IE and not a frame
  379. // continually check to see if the document is ready
  380. var toplevel = false;
  381. try {
  382. toplevel = window.frameElement == null;
  383. } catch(e) {}
  384. if ( document.documentElement.doScroll && toplevel ) {
  385. doScrollCheck();
  386. }
  387. }
  388. },
  389. // See test/unit/core.js for details concerning isFunction.
  390. // Since version 1.3, DOM methods and functions like alert
  391. // aren't supported. They return false on IE (#2968).
  392. isFunction: function( obj ) {
  393. return jQuery.type(obj) === "function";
  394. },
  395. isArray: Array.isArray || function( obj ) {
  396. return jQuery.type(obj) === "array";
  397. },
  398. isWindow: function( obj ) {
  399. return obj != null && obj == obj.window;
  400. },
  401. isNumeric: function( obj ) {
  402. return !isNaN( parseFloat(obj) ) && isFinite( obj );
  403. },
  404. type: function( obj ) {
  405. return obj == null ?
  406. String( obj ) :
  407. class2type[ toString.call(obj) ] || "object";
  408. },
  409. isPlainObject: function( obj ) {
  410. // Must be an Object.
  411. // Because of IE, we also have to check the presence of the constructor property.
  412. // Make sure that DOM nodes and window objects don't pass through, as well
  413. if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
  414. return false;
  415. }
  416. try {
  417. // Not own constructor property must be Object
  418. if ( obj.constructor &&
  419. !hasOwn.call(obj, "constructor") &&
  420. !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
  421. return false;
  422. }
  423. } catch ( e ) {
  424. // IE8,9 Will throw exceptions on certain host objects #9897
  425. return false;
  426. }
  427. // Own properties are enumerated firstly, so to speed up,
  428. // if last one is own, then all properties are own.
  429. var key;
  430. for ( key in obj ) {}
  431. return key === undefined || hasOwn.call( obj, key );
  432. },
  433. isEmptyObject: function( obj ) {
  434. for ( var name in obj ) {
  435. return false;
  436. }
  437. return true;
  438. },
  439. error: function( msg ) {
  440. throw new Error( msg );
  441. },
  442. parseJSON: function( data ) {
  443. if ( typeof data !== "string" || !data ) {
  444. return null;
  445. }
  446. // Make sure leading/trailing whitespace is removed (IE can't handle it)
  447. data = jQuery.trim( data );
  448. // Attempt to parse using the native JSON parser first
  449. if ( window.JSON && window.JSON.parse ) {
  450. return window.JSON.parse( data );
  451. }
  452. // Make sure the incoming data is actual JSON
  453. // Logic borrowed from http://json.org/json2.js
  454. if ( rvalidchars.test( data.replace( rvalidescape, "@" )
  455. .replace( rvalidtokens, "]" )
  456. .replace( rvalidbraces, "")) ) {
  457. return ( new Function( "return " + data ) )();
  458. }
  459. jQuery.error( "Invalid JSON: " + data );
  460. },
  461. // Cross-browser xml parsing
  462. parseXML: function( data ) {
  463. if ( typeof data !== "string" || !data ) {
  464. return null;
  465. }
  466. var xml, tmp;
  467. try {
  468. if ( window.DOMParser ) { // Standard
  469. tmp = new DOMParser();
  470. xml = tmp.parseFromString( data , "text/xml" );
  471. } else { // IE
  472. xml = new ActiveXObject( "Microsoft.XMLDOM" );
  473. xml.async = "false";
  474. xml.loadXML( data );
  475. }
  476. } catch( e ) {
  477. xml = undefined;
  478. }
  479. if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
  480. jQuery.error( "Invalid XML: " + data );
  481. }
  482. return xml;
  483. },
  484. noop: function() {},
  485. // Evaluates a script in a global context
  486. // Workarounds based on findings by Jim Driscoll
  487. // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
  488. globalEval: function( data ) {
  489. if ( data && rnotwhite.test( data ) ) {
  490. // We use execScript on Internet Explorer
  491. // We use an anonymous function so that context is window
  492. // rather than jQuery in Firefox
  493. ( window.execScript || function( data ) {
  494. window[ "eval" ].call( window, data );
  495. } )( data );
  496. }
  497. },
  498. // Convert dashed to camelCase; used by the css and data modules
  499. // Microsoft forgot to hump their vendor prefix (#9572)
  500. camelCase: function( string ) {
  501. return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
  502. },
  503. nodeName: function( elem, name ) {
  504. return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
  505. },
  506. // args is for internal usage only
  507. each: function( object, callback, args ) {
  508. var name, i = 0,
  509. length = object.length,
  510. isObj = length === undefined || jQuery.isFunction( object );
  511. if ( args ) {
  512. if ( isObj ) {
  513. for ( name in object ) {
  514. if ( callback.apply( object[ name ], args ) === false ) {
  515. break;
  516. }
  517. }
  518. } else {
  519. for ( ; i < length; ) {
  520. if ( callback.apply( object[ i++ ], args ) === false ) {
  521. break;
  522. }
  523. }
  524. }
  525. // A special, fast, case for the most common use of each
  526. } else {
  527. if ( isObj ) {
  528. for ( name in object ) {
  529. if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
  530. break;
  531. }
  532. }
  533. } else {
  534. for ( ; i < length; ) {
  535. if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
  536. break;
  537. }
  538. }
  539. }
  540. }
  541. return object;
  542. },
  543. // Use native String.trim function wherever possible
  544. trim: trim ?
  545. function( text ) {
  546. return text == null ?
  547. "" :
  548. trim.call( text );
  549. } :
  550. // Otherwise use our own trimming functionality
  551. function( text ) {
  552. return text == null ?
  553. "" :
  554. text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
  555. },
  556. // results is for internal usage only
  557. makeArray: function( array, results ) {
  558. var ret = results || [];
  559. if ( array != null ) {
  560. // The window, strings (and functions) also have 'length'
  561. // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
  562. var type = jQuery.type( array );
  563. if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
  564. push.call( ret, array );
  565. } else {
  566. jQuery.merge( ret, array );
  567. }
  568. }
  569. return ret;
  570. },
  571. inArray: function( elem, array, i ) {
  572. var len;
  573. if ( array ) {
  574. if ( indexOf ) {
  575. return indexOf.call( array, elem, i );
  576. }
  577. len = array.length;
  578. i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
  579. for ( ; i < len; i++ ) {
  580. // Skip accessing in sparse arrays
  581. if ( i in array && array[ i ] === elem ) {
  582. return i;
  583. }
  584. }
  585. }
  586. return -1;
  587. },
  588. merge: function( first, second ) {
  589. var i = first.length,
  590. j = 0;
  591. if ( typeof second.length === "number" ) {
  592. for ( var l = second.length; j < l; j++ ) {
  593. first[ i++ ] = second[ j ];
  594. }
  595. } else {
  596. while ( second[j] !== undefined ) {
  597. first[ i++ ] = second[ j++ ];
  598. }
  599. }
  600. first.length = i;
  601. return first;
  602. },
  603. grep: function( elems, callback, inv ) {
  604. var ret = [], retVal;
  605. inv = !!inv;
  606. // Go through the array, only saving the items
  607. // that pass the validator function
  608. for ( var i = 0, length = elems.length; i < length; i++ ) {
  609. retVal = !!callback( elems[ i ], i );
  610. if ( inv !== retVal ) {
  611. ret.push( elems[ i ] );
  612. }
  613. }
  614. return ret;
  615. },
  616. // arg is for internal usage only
  617. map: function( elems, callback, arg ) {
  618. var value, key, ret = [],
  619. i = 0,
  620. length = elems.length,
  621. // jquery objects are treated as arrays
  622. isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
  623. // Go through the array, translating each of the items to their
  624. if ( isArray ) {
  625. for ( ; i < length; i++ ) {
  626. value = callback( elems[ i ], i, arg );
  627. if ( value != null ) {
  628. ret[ ret.length ] = value;
  629. }
  630. }
  631. // Go through every key on the object,
  632. } else {
  633. for ( key in elems ) {
  634. value = callback( elems[ key ], key, arg );
  635. if ( value != null ) {
  636. ret[ ret.length ] = value;
  637. }
  638. }
  639. }
  640. // Flatten any nested arrays
  641. return ret.concat.apply( [], ret );
  642. },
  643. // A global GUID counter for objects
  644. guid: 1,
  645. // Bind a function to a context, optionally partially applying any
  646. // arguments.
  647. proxy: function( fn, context ) {
  648. if ( typeof context === "string" ) {
  649. var tmp = fn[ context ];
  650. context = fn;
  651. fn = tmp;
  652. }
  653. // Quick check to determine if target is callable, in the spec
  654. // this throws a TypeError, but we will just return undefined.
  655. if ( !jQuery.isFunction( fn ) ) {
  656. return undefined;
  657. }
  658. // Simulated bind
  659. var args = slice.call( arguments, 2 ),
  660. proxy = function() {
  661. return fn.apply( context, args.concat( slice.call( arguments ) ) );
  662. };
  663. // Set the guid of unique handler to the same of original handler, so it can be removed
  664. proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
  665. return proxy;
  666. },
  667. // Mutifunctional method to get and set values to a collection
  668. // The value/s can optionally be executed if it's a function
  669. access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
  670. var exec,
  671. bulk = key == null,
  672. i = 0,
  673. length = elems.length;
  674. // Sets many values
  675. if ( key && typeof key === "object" ) {
  676. for ( i in key ) {
  677. jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
  678. }
  679. chainable = 1;
  680. // Sets one value
  681. } else if ( value !== undefined ) {
  682. // Optionally, function values get executed if exec is true
  683. exec = pass === undefined && jQuery.isFunction( value );
  684. if ( bulk ) {
  685. // Bulk operations only iterate when executing function values
  686. if ( exec ) {
  687. exec = fn;
  688. fn = function( elem, key, value ) {
  689. return exec.call( jQuery( elem ), value );
  690. };
  691. // Otherwise they run against the entire set
  692. } else {
  693. fn.call( elems, value );
  694. fn = null;
  695. }
  696. }
  697. if ( fn ) {
  698. for (; i < length; i++ ) {
  699. fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
  700. }
  701. }
  702. chainable = 1;
  703. }
  704. return chainable ?
  705. elems :
  706. // Gets
  707. bulk ?
  708. fn.call( elems ) :
  709. length ? fn( elems[0], key ) : emptyGet;
  710. },
  711. now: function() {
  712. return ( new Date() ).getTime();
  713. },
  714. // Use of jQuery.browser is frowned upon.
  715. // More details: http://docs.jquery.com/Utilities/jQuery.browser
  716. uaMatch: function( ua ) {
  717. ua = ua.toLowerCase();
  718. var match = rwebkit.exec( ua ) ||
  719. ropera.exec( ua ) ||
  720. rmsie.exec( ua ) ||
  721. ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
  722. [];
  723. return { browser: match[1] || "", version: match[2] || "0" };
  724. },
  725. sub: function() {
  726. function jQuerySub( selector, context ) {
  727. return new jQuerySub.fn.init( selector, context );
  728. }
  729. jQuery.extend( true, jQuerySub, this );
  730. jQuerySub.superclass = this;
  731. jQuerySub.fn = jQuerySub.prototype = this();
  732. jQuerySub.fn.constructor = jQuerySub;
  733. jQuerySub.sub = this.sub;
  734. jQuerySub.fn.init = function init( selector, context ) {
  735. if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
  736. context = jQuerySub( context );
  737. }
  738. return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
  739. };
  740. jQuerySub.fn.init.prototype = jQuerySub.fn;
  741. var rootjQuerySub = jQuerySub(document);
  742. return jQuerySub;
  743. },
  744. browser: {}
  745. });
  746. // Populate the class2type map
  747. jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
  748. class2type[ "[object " + name + "]" ] = name.toLowerCase();
  749. });
  750. browserMatch = jQuery.uaMatch( userAgent );
  751. if ( browserMatch.browser ) {
  752. jQuery.browser[ browserMatch.browser ] = true;
  753. jQuery.browser.version = browserMatch.version;
  754. }
  755. // Deprecated, use jQuery.browser.webkit instead
  756. if ( jQuery.browser.webkit ) {
  757. jQuery.browser.safari = true;
  758. }
  759. // IE doesn't match non-breaking spaces with \s
  760. if ( rnotwhite.test( "\xA0" ) ) {
  761. trimLeft = /^[\s\xA0]+/;
  762. trimRight = /[\s\xA0]+$/;
  763. }
  764. // All jQuery objects should point back to these
  765. rootjQuery = jQuery(document);
  766. // Cleanup functions for the document ready method
  767. if ( document.addEventListener ) {
  768. DOMContentLoaded = function() {
  769. document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
  770. jQuery.ready();
  771. };
  772. } else if ( document.attachEvent ) {
  773. DOMContentLoaded = function() {
  774. // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
  775. if ( document.readyState === "complete" ) {
  776. document.detachEvent( "onreadystatechange", DOMContentLoaded );
  777. jQuery.ready();
  778. }
  779. };
  780. }
  781. // The DOM ready check for Internet Explorer
  782. function doScrollCheck() {
  783. if ( jQuery.isReady ) {
  784. return;
  785. }
  786. try {
  787. // If IE is used, use the trick by Diego Perini
  788. // http://javascript.nwbox.com/IEContentLoaded/
  789. document.documentElement.doScroll("left");
  790. } catch(e) {
  791. setTimeout( doScrollCheck, 1 );
  792. return;
  793. }
  794. // and execute any waiting functions
  795. jQuery.ready();
  796. }
  797. return jQuery;
  798. })();
  799. // String to Object flags format cache
  800. var flagsCache = {};
  801. // Convert String-formatted flags into Object-formatted ones and store in cache
  802. function createFlags( flags ) {
  803. var object = flagsCache[ flags ] = {},
  804. i, length;
  805. flags = flags.split( /\s+/ );
  806. for ( i = 0, length = flags.length; i < length; i++ ) {
  807. object[ flags[i] ] = true;
  808. }
  809. return object;
  810. }
  811. /*
  812. * Create a callback list using the following parameters:
  813. *
  814. * flags: an optional list of space-separated flags that will change how
  815. * the callback list behaves
  816. *
  817. * By default a callback list will act like an event callback list and can be
  818. * "fired" multiple times.
  819. *
  820. * Possible flags:
  821. *
  822. * once: will ensure the callback list can only be fired once (like a Deferred)
  823. *
  824. * memory: will keep track of previous values and will call any callback added
  825. * after the list has been fired right away with the latest "memorized"
  826. * values (like a Deferred)
  827. *
  828. * unique: will ensure a callback can only be added once (no duplicate in the list)
  829. *
  830. * stopOnFalse: interrupt callings when a callback returns false
  831. *
  832. */
  833. jQuery.Callbacks = function( flags ) {
  834. // Convert flags from String-formatted to Object-formatted
  835. // (we check in cache first)
  836. flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
  837. var // Actual callback list
  838. list = [],
  839. // Stack of fire calls for repeatable lists
  840. stack = [],
  841. // Last fire value (for non-forgettable lists)
  842. memory,
  843. // Flag to know if list was already fired
  844. fired,
  845. // Flag to know if list is currently firing
  846. firing,
  847. // First callback to fire (used internally by add and fireWith)
  848. firingStart,
  849. // End of the loop when firing
  850. firingLength,
  851. // Index of currently firing callback (modified by remove if needed)
  852. firingIndex,
  853. // Add one or several callbacks to the list
  854. add = function( args ) {
  855. var i,
  856. length,
  857. elem,
  858. type,
  859. actual;
  860. for ( i = 0, length = args.length; i < length; i++ ) {
  861. elem = args[ i ];
  862. type = jQuery.type( elem );
  863. if ( type === "array" ) {
  864. // Inspect recursively
  865. add( elem );
  866. } else if ( type === "function" ) {
  867. // Add if not in unique mode and callback is not in
  868. if ( !flags.unique || !self.has( elem ) ) {
  869. list.push( elem );
  870. }
  871. }
  872. }
  873. },
  874. // Fire callbacks
  875. fire = function( context, args ) {
  876. args = args || [];
  877. memory = !flags.memory || [ context, args ];
  878. fired = true;
  879. firing = true;
  880. firingIndex = firingStart || 0;
  881. firingStart = 0;
  882. firingLength = list.length;
  883. for ( ; list && firingIndex < firingLength; firingIndex++ ) {
  884. if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
  885. memory = true; // Mark as halted
  886. break;
  887. }
  888. }
  889. firing = false;
  890. if ( list ) {
  891. if ( !flags.once ) {
  892. if ( stack && stack.length ) {
  893. memory = stack.shift();
  894. self.fireWith( memory[ 0 ], memory[ 1 ] );
  895. }
  896. } else if ( memory === true ) {
  897. self.disable();
  898. } else {
  899. list = [];
  900. }
  901. }
  902. },
  903. // Actual Callbacks object
  904. self = {
  905. // Add a callback or a collection of callbacks to the list
  906. add: function() {
  907. if ( list ) {
  908. var length = list.length;
  909. add( arguments );
  910. // Do we need to add the callbacks to the
  911. // current firing batch?
  912. if ( firing ) {
  913. firingLength = list.length;
  914. // With memory, if we're not firing then
  915. // we should call right away, unless previous
  916. // firing was halted (stopOnFalse)
  917. } else if ( memory && memory !== true ) {
  918. firingStart = length;
  919. fire( memory[ 0 ], memory[ 1 ] );
  920. }
  921. }
  922. return this;
  923. },
  924. // Remove a callback from the list
  925. remove: function() {
  926. if ( list ) {
  927. var args = arguments,
  928. argIndex = 0,
  929. argLength = args.length;
  930. for ( ; argIndex < argLength ; argIndex++ ) {
  931. for ( var i = 0; i < list.length; i++ ) {
  932. if ( args[ argIndex ] === list[ i ] ) {
  933. // Handle firingIndex and firingLength
  934. if ( firing ) {
  935. if ( i <= firingLength ) {
  936. firingLength--;
  937. if ( i <= firingIndex ) {
  938. firingIndex--;
  939. }
  940. }
  941. }
  942. // Remove the element
  943. list.splice( i--, 1 );
  944. // If we have some unicity property then
  945. // we only need to do this once
  946. if ( flags.unique ) {
  947. break;
  948. }
  949. }
  950. }
  951. }
  952. }
  953. return this;
  954. },
  955. // Control if a given callback is in the list
  956. has: function( fn ) {
  957. if ( list ) {
  958. var i = 0,
  959. length = list.length;
  960. for ( ; i < length; i++ ) {
  961. if ( fn === list[ i ] ) {
  962. return true;
  963. }
  964. }
  965. }
  966. return false;
  967. },
  968. // Remove all callbacks from the list
  969. empty: function() {
  970. list = [];
  971. return this;
  972. },
  973. // Have the list do nothing anymore
  974. disable: function() {
  975. list = stack = memory = undefined;
  976. return this;
  977. },
  978. // Is it disabled?
  979. disabled: function() {
  980. return !list;
  981. },
  982. // Lock the list in its current state
  983. lock: function() {
  984. stack = undefined;
  985. if ( !memory || memory === true ) {
  986. self.disable();
  987. }
  988. return this;
  989. },
  990. // Is it locked?
  991. locked: function() {
  992. return !stack;
  993. },
  994. // Call all callbacks with the given context and arguments
  995. fireWith: function( context, args ) {
  996. if ( stack ) {
  997. if ( firing ) {
  998. if ( !flags.once ) {
  999. stack.push( [ context, args ] );
  1000. }
  1001. } else if ( !( flags.once && memory ) ) {
  1002. fire( context, args );
  1003. }
  1004. }
  1005. return this;
  1006. },
  1007. // Call all the callbacks with the given arguments
  1008. fire: function() {
  1009. self.fireWith( this, arguments );
  1010. return this;
  1011. },
  1012. // To know if the callbacks have already been called at least once
  1013. fired: function() {
  1014. return !!fired;
  1015. }
  1016. };
  1017. return self;
  1018. };
  1019. var // Static reference to slice
  1020. sliceDeferred = [].slice;
  1021. jQuery.extend({
  1022. Deferred: function( func ) {
  1023. var doneList = jQuery.Callbacks( "once memory" ),
  1024. failList = jQuery.Callbacks( "once memory" ),
  1025. progressList = jQuery.Callbacks( "memory" ),
  1026. state = "pending",
  1027. lists = {
  1028. resolve: doneList,
  1029. reject: failList,
  1030. notify: progressList
  1031. },
  1032. promise = {
  1033. done: doneList.add,
  1034. fail: failList.add,
  1035. progress: progressList.add,
  1036. state: function() {
  1037. return state;
  1038. },
  1039. // Deprecated
  1040. isResolved: doneList.fired,
  1041. isRejected: failList.fired,
  1042. then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
  1043. deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
  1044. return this;
  1045. },
  1046. always: function() {
  1047. deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
  1048. return this;
  1049. },
  1050. pipe: function( fnDone, fnFail, fnProgress ) {
  1051. return jQuery.Deferred(function( newDefer ) {
  1052. jQuery.each( {
  1053. done: [ fnDone, "resolve" ],
  1054. fail: [ fnFail, "reject" ],
  1055. progress: [ fnProgress, "notify" ]
  1056. }, function( handler, data ) {
  1057. var fn = data[ 0 ],
  1058. action = data[ 1 ],
  1059. returned;
  1060. if ( jQuery.isFunction( fn ) ) {
  1061. deferred[ handler ](function() {
  1062. returned = fn.apply( this, arguments );
  1063. if ( returned && jQuery.isFunction( returned.promise ) ) {
  1064. returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
  1065. } else {
  1066. newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
  1067. }
  1068. });
  1069. } else {
  1070. deferred[ handler ]( newDefer[ action ] );
  1071. }
  1072. });
  1073. }).promise();
  1074. },
  1075. // Get a promise for this deferred
  1076. // If obj is provided, the promise aspect is added to the object
  1077. promise: function( obj ) {
  1078. if ( obj == null ) {
  1079. obj = promise;
  1080. } else {
  1081. for ( var key in promise ) {
  1082. obj[ key ] = promise[ key ];
  1083. }
  1084. }
  1085. return obj;
  1086. }
  1087. },
  1088. deferred = promise.promise({}),
  1089. key;
  1090. for ( key in lists ) {
  1091. deferred[ key ] = lists[ key ].fire;
  1092. deferred[ key + "With" ] = lists[ key ].fireWith;
  1093. }
  1094. // Handle state
  1095. deferred.done( function() {
  1096. state = "resolved";
  1097. }, failList.disable, progressList.lock ).fail( function() {
  1098. state = "rejected";
  1099. }, doneList.disable, progressList.lock );
  1100. // Call given func if any
  1101. if ( func ) {
  1102. func.call( deferred, deferred );
  1103. }
  1104. // All done!
  1105. return deferred;
  1106. },
  1107. // Deferred helper
  1108. when: function( firstParam ) {
  1109. var args = sliceDeferred.call( arguments, 0 ),
  1110. i = 0,
  1111. length = args.length,
  1112. pValues = new Array( length ),
  1113. count = length,
  1114. pCount = length,
  1115. deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
  1116. firstParam :
  1117. jQuery.Deferred(),
  1118. promise = deferred.promise();
  1119. function resolveFunc( i ) {
  1120. return function( value ) {
  1121. args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
  1122. if ( !( --count ) ) {
  1123. deferred.resolveWith( deferred, args );
  1124. }
  1125. };
  1126. }
  1127. function progressFunc( i ) {
  1128. return function( value ) {
  1129. pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
  1130. deferred.notifyWith( promise, pValues );
  1131. };
  1132. }
  1133. if ( length > 1 ) {
  1134. for ( ; i < length; i++ ) {
  1135. if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
  1136. args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
  1137. } else {
  1138. --count;
  1139. }
  1140. }
  1141. if ( !count ) {
  1142. deferred.resolveWith( deferred, args );
  1143. }
  1144. } else if ( deferred !== firstParam ) {
  1145. deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
  1146. }
  1147. return promise;
  1148. }
  1149. });
  1150. jQuery.support = (function() {
  1151. var support,
  1152. all,
  1153. a,
  1154. select,
  1155. opt,
  1156. input,
  1157. fragment,
  1158. tds,
  1159. events,
  1160. eventName,
  1161. i,
  1162. isSupported,
  1163. div = document.createElement( "div" ),
  1164. documentElement = document.documentElement;
  1165. // Preliminary tests
  1166. div.setAttribute("className", "t");
  1167. div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
  1168. all = div.getElementsByTagName( "*" );
  1169. a = div.getElementsByTagName( "a" )[ 0 ];
  1170. // Can't get basic test support
  1171. if ( !all || !all.length || !a ) {
  1172. return {};
  1173. }
  1174. // First batch of supports tests
  1175. select = document.createElement( "select" );
  1176. opt = select.appendChild( document.createElement("option") );
  1177. input = div.getElementsByTagName( "input" )[ 0 ];
  1178. support = {
  1179. // IE strips leading whitespace when .innerHTML is used
  1180. leadingWhitespace: ( div.firstChild.nodeType === 3 ),
  1181. // Make sure that tbody elements aren't automatically inserted
  1182. // IE will insert them into empty tables
  1183. tbody: !div.getElementsByTagName("tbody").length,
  1184. // Make sure that link elements get serialized correctly by innerHTML
  1185. // This requires a wrapper element in IE
  1186. htmlSerialize: !!div.getElementsByTagName("link").length,
  1187. // Get the style information from getAttribute
  1188. // (IE uses .cssText instead)
  1189. style: /top/.test( a.getAttribute("style") ),
  1190. // Make sure that URLs aren't manipulated
  1191. // (IE normalizes it by default)
  1192. hrefNormalized: ( a.getAttribute("href") === "/a" ),
  1193. // Make sure that element opacity exists
  1194. // (IE uses filter instead)
  1195. // Use a regex to work around a WebKit issue. See #5145
  1196. opacity: /^0.55/.test( a.style.opacity ),
  1197. // Verify style float existence
  1198. // (IE uses styleFloat instead of cssFloat)
  1199. cssFloat: !!a.style.cssFloat,
  1200. // Make sure that if no value is specified for a checkbox
  1201. // that it defaults to "on".
  1202. // (WebKit defaults to "" instead)
  1203. checkOn: ( input.value === "on" ),
  1204. // Make sure that a selected-by-default option has a working selected property.
  1205. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
  1206. optSelected: opt.selected,
  1207. // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
  1208. getSetAttribute: div.className !== "t",
  1209. // Tests for enctype support on a form(#6743)
  1210. enctype: !!document.createElement("form").enctype,
  1211. // Makes sure cloning an html5 element does not cause problems
  1212. // Where outerHTML is undefined, this still works
  1213. html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
  1214. // Will be defined later
  1215. submitBubbles: true,
  1216. changeBubbles: true,
  1217. focusinBubbles: false,
  1218. deleteExpando: true,
  1219. noCloneEvent: true,
  1220. inlineBlockNeedsLayout: false,
  1221. shrinkWrapBlocks: false,
  1222. reliableMarginRight: true,
  1223. pixelMargin: true
  1224. };
  1225. // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead
  1226. jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat");
  1227. // Make sure checked status is properly cloned
  1228. input.checked = true;
  1229. support.noCloneChecked = input.cloneNode( true ).checked;
  1230. // Make sure that the options inside disabled selects aren't marked as disabled
  1231. // (WebKit marks them as disabled)
  1232. select.disabled = true;
  1233. support.optDisabled = !opt.disabled;
  1234. // Test to see if it's possible to delete an expando from an element
  1235. // Fails in Internet Explorer
  1236. try {
  1237. delete div.test;
  1238. } catch( e ) {
  1239. support.deleteExpando = false;
  1240. }
  1241. if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
  1242. div.attachEvent( "onclick", function() {
  1243. // Cloning a node shouldn't copy over any
  1244. // bound event handlers (IE does this)
  1245. support.noCloneEvent = false;
  1246. });
  1247. div.cloneNode( true ).fireEvent( "onclick" );
  1248. }
  1249. // Check if a radio maintains its value
  1250. // after being appended to the DOM
  1251. input = document.createElement("input");
  1252. input.value = "t";
  1253. input.setAttribute("type", "radio");
  1254. support.radioValue = input.value === "t";
  1255. input.setAttribute("checked", "checked");
  1256. // #11217 - WebKit loses check when the name is after the checked attribute
  1257. input.setAttribute( "name", "t" );
  1258. div.appendChild( input );
  1259. fragment = document.createDocumentFragment();
  1260. fragment.appendChild( div.lastChild );
  1261. // WebKit doesn't clone checked state correctly in fragments
  1262. support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
  1263. // Check if a disconnected checkbox will retain its checked
  1264. // value of true after appended to the DOM (IE6/7)
  1265. support.appendChecked = input.checked;
  1266. fragment.removeChild( input );
  1267. fragment.appendChild( div );
  1268. // Technique from Juriy Zaytsev
  1269. // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
  1270. // We only care about the case where non-standard event systems
  1271. // are used, namely in IE. Short-circuiting here helps us to
  1272. // avoid an eval call (in setAttribute) which can cause CSP
  1273. // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
  1274. if ( div.attachEvent ) {
  1275. for ( i in {
  1276. submit: 1,
  1277. change: 1,
  1278. focusin: 1
  1279. }) {
  1280. eventName = "on" + i;
  1281. isSupported = ( eventName in div );
  1282. if ( !isSupported ) {
  1283. div.setAttribute( eventName, "return;" );
  1284. isSupported = ( typeof div[ eventName ] === "function" );
  1285. }
  1286. support[ i + "Bubbles" ] = isSupported;
  1287. }
  1288. }
  1289. fragment.removeChild( div );
  1290. // Null elements to avoid leaks in IE
  1291. fragment = select = opt = div = input = null;
  1292. // Run tests that need a body at doc ready
  1293. jQuery(function() {
  1294. var container, outer, inner, table, td, offsetSupport,
  1295. marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,
  1296. paddingMarginBorderVisibility, paddingMarginBorder,
  1297. body = document.getElementsByTagName("body")[0];
  1298. if ( !body ) {
  1299. // Return for frameset docs that don't have a body
  1300. return;
  1301. }
  1302. conMarginTop = 1;
  1303. paddingMarginBorder = "padding:0;margin:0;border:";
  1304. positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;";
  1305. paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;";
  1306. style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;";
  1307. html = "<div " + style + "display:block;'><div style='" + paddingMarginBorder + "0;display:block;overflow:hidden;'></div></div>" +
  1308. "<table " + style + "' cellpadding='0' cellspacing='0'>" +
  1309. "<tr><td></td></tr></table>";
  1310. container = document.createElement("div");
  1311. container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
  1312. body.insertBefore( container, body.firstChild );
  1313. // Construct the test element
  1314. div = document.createElement("div");
  1315. container.appendChild( div );
  1316. // Check if table cells still have offsetWidth/Height when they are set
  1317. // to display:none and there are still other visible table cells in a
  1318. // table row; if so, offsetWidth/Height are not reliable for use when
  1319. // determining if an element has been hidden directly using
  1320. // display:none (it is still safe to use offsets if a parent element is
  1321. // hidden; don safety goggles and see bug #4512 for more information).
  1322. // (only IE 8 fails this test)
  1323. div.innerHTML = "<table><tr><td style='" + paddingMarginBorder + "0;display:none'></td><td>t</td></tr></table>";
  1324. tds = div.getElementsByTagName( "td" );
  1325. isSupported = ( tds[ 0 ].offsetHeight === 0 );
  1326. tds[ 0 ].style.display = "";
  1327. tds[ 1 ].style.display = "none";
  1328. // Check if empty table cells still have offsetWidth/Height
  1329. // (IE <= 8 fail this test)
  1330. support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
  1331. // Check if div with explicit width and no margin-right incorrectly
  1332. // gets computed margin-right based on width of container. For more
  1333. // info see bug #3333
  1334. // Fails in WebKit before Feb 2011 nightlies
  1335. // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
  1336. if ( window.getComputedStyle ) {
  1337. div.innerHTML = "";
  1338. marginDiv = document.createElement( "div" );
  1339. marginDiv.style.width = "0";
  1340. marginDiv.style.marginRight = "0";
  1341. div.style.width = "2px";
  1342. div.appendChild( marginDiv );
  1343. support.reliableMarginRight =
  1344. ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
  1345. }
  1346. if ( typeof div.style.zoom !== "undefined" ) {
  1347. // Check if natively block-level elements act like inline-block
  1348. // elements when setting their display to 'inline' and giving
  1349. // them layout
  1350. // (IE < 8 does this)
  1351. div.innerHTML = "";
  1352. div.style.width = div.style.padding = "1px";
  1353. div.style.border = 0;
  1354. div.style.overflow = "hidden";
  1355. div.style.display = "inline";
  1356. div.style.zoom = 1;
  1357. support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
  1358. // Check if elements with layout shrink-wrap their children
  1359. // (IE 6 does this)
  1360. div.style.display = "block";
  1361. div.style.overflow = "visible";
  1362. div.innerHTML = "<div style='width:5px;'></div>";
  1363. support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
  1364. }
  1365. div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;
  1366. div.innerHTML = html;
  1367. outer = div.firstChild;
  1368. inner = outer.firstChild;
  1369. td = outer.nextSibling.firstChild.firstChild;
  1370. offsetSupport = {
  1371. doesNotAddBorder: ( inner.offsetTop !== 5 ),
  1372. doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
  1373. };
  1374. inner.style.position = "fixed";
  1375. inner.style.top = "20px";
  1376. // safari subtracts parent border width here which is 5px
  1377. offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
  1378. inner.style.position = inner.style.top = "";
  1379. outer.style.overflow = "hidden";
  1380. outer.style.position = "relative";
  1381. offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
  1382. offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
  1383. if ( window.getComputedStyle ) {
  1384. div.style.marginTop = "1%";
  1385. support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
  1386. }
  1387. if ( typeof container.style.zoom !== "undefined" ) {
  1388. container.style.zoom = 1;
  1389. }
  1390. body.removeChild( container );
  1391. marginDiv = div = container = null;
  1392. jQuery.extend( support, offsetSupport );
  1393. });
  1394. return support;
  1395. })();
  1396. var rbrace = /^(?:\{.*\}|\[.*\])$/,
  1397. rmultiDash = /([A-Z])/g;
  1398. jQuery.extend({
  1399. cache: {},
  1400. // Please use with caution
  1401. uuid: 0,
  1402. // Unique for each copy of jQuery on the page
  1403. // Non-digits removed to match rinlinejQuery
  1404. expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
  1405. // The following elements throw uncatchable exceptions if you
  1406. // attempt to add expando properties to them.
  1407. noData: {
  1408. "embed": true,
  1409. // Ban all objects except for Flash (which handle expandos)
  1410. "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
  1411. "applet": true
  1412. },
  1413. hasData: function( elem ) {
  1414. elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
  1415. return !!elem && !isEmptyDataObject( elem );
  1416. },
  1417. data: function( elem, name, data, pvt /* Internal Use Only */ ) {
  1418. if ( !jQuery.acceptData( elem ) ) {
  1419. return;
  1420. }
  1421. var privateCache, thisCache, ret,
  1422. internalKey = jQuery.expando,
  1423. getByName = typeof name === "string",
  1424. // We have to handle DOM nodes and JS objects differently because IE6-7
  1425. // can't GC object references properly across the DOM-JS boundary
  1426. isNode = elem.nodeType,
  1427. // Only DOM nodes need the global jQuery cache; JS object data is
  1428. // attached directly to the object so GC can occur automatically
  1429. cache = isNode ? jQuery.cache : elem,
  1430. // Only defining an ID for JS objects if its cache already exists allows
  1431. // the code to shortcut on the same path as a DOM node with no cache
  1432. id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
  1433. isEvents = name === "events";
  1434. // Avoid doing any more work than we need to when trying to get data on an
  1435. // object that has no data at all
  1436. if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
  1437. return;
  1438. }
  1439. if ( !id ) {
  1440. // Only DOM nodes need a new unique ID for each element since their data
  1441. // ends up in the global cache
  1442. if ( isNode ) {
  1443. elem[ internalKey ] = id = ++jQuery.uuid;
  1444. } else {
  1445. id = internalKey;
  1446. }
  1447. }
  1448. if ( !cache[ id ] ) {
  1449. cache[ id ] = {};
  1450. // Avoids exposing jQuery metadata on plain JS objects when the object
  1451. // is serialized using JSON.stringify
  1452. if ( !isNode ) {
  1453. cache[ id ].toJSON = jQuery.noop;
  1454. }
  1455. }
  1456. // An object can be passed to jQuery.data instead of a key/value pair; this gets
  1457. // shallow copied over onto the existing cache
  1458. if ( typeof name === "object" || typeof name === "function" ) {
  1459. if ( pvt ) {
  1460. cache[ id ] = jQuery.extend( cache[ id ], name );
  1461. } else {
  1462. cache[ id ].data = jQuery.extend( cache[ id ].data, name );
  1463. }
  1464. }
  1465. privateCache = thisCache = cache[ id ];
  1466. // jQuery data() is stored in a separate object inside the object's internal data
  1467. // cache in order to avoid key collisions between internal data and user-defined
  1468. // data.
  1469. if ( !pvt ) {
  1470. if ( !thisCache.data ) {
  1471. thisCache.data = {};
  1472. }
  1473. thisCache = thisCache.data;
  1474. }
  1475. if ( data !== undefined ) {
  1476. thisCache[ jQuery.camelCase( name ) ] = data;
  1477. }
  1478. // Users should not attempt to inspect the internal events object using jQuery.data,
  1479. // it is undocumented and subject to change. But does anyone listen? No.
  1480. if ( isEvents && !thisCache[ name ] ) {
  1481. return privateCache.events;
  1482. }
  1483. // Check for both converted-to-camel and non-converted data property names
  1484. // If a data property was specified
  1485. if ( getByName ) {
  1486. // First Try to find as-is property data
  1487. ret = thisCache[ name ];
  1488. // Test for null|undefined property data
  1489. if ( ret == null ) {
  1490. // Try to find the camelCased property
  1491. ret = thisCache[ jQuery.camelCase( name ) ];
  1492. }
  1493. } else {
  1494. ret = thisCache;
  1495. }
  1496. return ret;
  1497. },
  1498. removeData: function( elem, name, pvt /* Internal Use Only */ ) {
  1499. if ( !jQuery.acceptData( elem ) ) {
  1500. return;
  1501. }
  1502. var thisCache, i, l,
  1503. // Reference to internal data cache key
  1504. internalKey = jQuery.expando,
  1505. isNode = elem.nodeType,
  1506. // See jQuery.data for more information
  1507. cache = isNode ? jQuery.cache : elem,
  1508. // See jQuery.data for more information
  1509. id = isNode ? elem[ internalKey ] : internalKey;
  1510. // If there is already no cache entry for this object, there is no
  1511. // purpose in continuing
  1512. if ( !cache[ id ] ) {
  1513. return;
  1514. }
  1515. if ( name ) {
  1516. thisCache = pvt ? cache[ id ] : cache[ id ].data;
  1517. if ( thisCache ) {
  1518. // Support array or space separated string names for data keys
  1519. if ( !jQuery.isArray( name ) ) {
  1520. // try the string as a key before any manipulation
  1521. if ( name in thisCache ) {
  1522. name = [ name ];
  1523. } else {
  1524. // split the camel cased version by spaces unless a key with the spaces exists
  1525. name = jQuery.camelCase( name );
  1526. if ( name in thisCache ) {
  1527. name = [ name ];
  1528. } else {
  1529. name = name.split( " " );
  1530. }
  1531. }
  1532. }
  1533. for ( i = 0, l = name.length; i < l; i++ ) {
  1534. delete thisCache[ name[i] ];
  1535. }
  1536. // If there is no data left in the cache, we want to continue
  1537. // and let the cache object itself get destroyed
  1538. if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
  1539. return;
  1540. }
  1541. }
  1542. }
  1543. // See jQuery.data for more information
  1544. if ( !pvt ) {
  1545. delete cache[ id ].data;
  1546. // Don't destroy the parent cache unless the internal data object
  1547. // had been the only thing left in it
  1548. if ( !isEmptyDataObject(cache[ id ]) ) {
  1549. return;
  1550. }
  1551. }
  1552. // Browsers that fail expando deletion also refuse to delete expandos on
  1553. // the window, but it will allow it on all other JS objects; other browsers
  1554. // don't care
  1555. // Ensure that `cache` is not a window object #10080
  1556. if ( jQuery.support.deleteExpando || !cache.setInterval ) {
  1557. delete cache[ id ];
  1558. } else {
  1559. cache[ id ] = null;
  1560. }
  1561. // We destroyed the cache and need to eliminate the expando on the node to avoid
  1562. // false lookups in the cache for entries that no longer exist
  1563. if ( isNode ) {
  1564. // IE does not allow us to delete expando properties from nodes,
  1565. // nor does it have a removeAttribute function on Document nodes;
  1566. // we must handle all of these cases
  1567. if ( jQuery.support.deleteExpando ) {
  1568. delete elem[ internalKey ];
  1569. } else if ( elem.removeAttribute ) {
  1570. elem.removeAttribute( internalKey );
  1571. } else {
  1572. elem[ internalKey ] = null;
  1573. }
  1574. }
  1575. },
  1576. // For internal use only.
  1577. _data: function( elem, name, data ) {
  1578. return jQuery.data( elem, name, data, true );
  1579. },
  1580. // A method for determining if a DOM node can handle the data expando
  1581. acceptData: function( elem ) {
  1582. if ( elem.nodeName ) {
  1583. var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
  1584. if ( match ) {
  1585. return !(match === true || elem.getAttribute("classid") !== match);
  1586. }
  1587. }
  1588. return true;
  1589. }
  1590. });
  1591. jQuery.fn.extend({
  1592. data: function( key, value ) {
  1593. var parts, part, attr, name, l,
  1594. elem = this[0],
  1595. i = 0,
  1596. data = null;
  1597. // Gets all values
  1598. if ( key === undefined ) {
  1599. if ( this.length ) {
  1600. data = jQuery.data( elem );
  1601. if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
  1602. attr = elem.attributes;
  1603. for ( l = attr.length; i < l; i++ ) {
  1604. name = attr[i].name;
  1605. if ( name.indexOf( "data-" ) === 0 ) {
  1606. name = jQuery.camelCase( name.substring(5) );
  1607. dataAttr( elem, name, data[ name ] );
  1608. }
  1609. }
  1610. jQuery._data( elem, "parsedAttrs", true );
  1611. }
  1612. }
  1613. return data;
  1614. }
  1615. // Sets multiple values
  1616. if ( typeof key === "object" ) {
  1617. return this.each(function() {
  1618. jQuery.data( this, key );
  1619. });
  1620. }
  1621. parts = key.split( ".", 2 );
  1622. parts[1] = parts[1] ? "." + parts[1] : "";
  1623. part = parts[1] + "!";
  1624. return jQuery.access( this, function( value ) {
  1625. if ( value === undefined ) {
  1626. data = this.triggerHandler( "getData" + part, [ parts[0] ] );
  1627. // Try to fetch any internally stored data first
  1628. if ( data === undefined && elem ) {
  1629. data = jQuery.data( elem, key );
  1630. data = dataAttr( elem, key, data );
  1631. }
  1632. return data === undefined && parts[1] ?
  1633. this.data( parts[0] ) :
  1634. data;
  1635. }
  1636. parts[1] = value;
  1637. this.each(function() {
  1638. var self = jQuery( this );
  1639. self.triggerHandler( "setData" + part, parts );
  1640. jQuery.data( this, key, value );
  1641. self.triggerHandler( "changeData" + part, parts );
  1642. });
  1643. }, null, value, arguments.length > 1, null, false );
  1644. },
  1645. removeData: function( key ) {
  1646. return this.each(function() {
  1647. jQuery.removeData( this, key );
  1648. });
  1649. }
  1650. });
  1651. function dataAttr( elem, key, data ) {
  1652. // If nothing was found internally, try to fetch any
  1653. // data from the HTML5 data-* attribute
  1654. if ( data === undefined && elem.nodeType === 1 ) {
  1655. var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
  1656. data = elem.getAttribute( name );
  1657. if ( typeof data === "string" ) {
  1658. try {
  1659. data = data === "true" ? true :
  1660. data === "false" ? false :
  1661. data === "null" ? null :
  1662. jQuery.isNumeric( data ) ? +data :
  1663. rbrace.test( data ) ? jQuery.parseJSON( data ) :
  1664. data;
  1665. } catch( e ) {}
  1666. // Make sure we set the data so it isn't changed later
  1667. jQuery.data( elem, key, data );
  1668. } else {
  1669. data = undefined;
  1670. }
  1671. }
  1672. return data;
  1673. }
  1674. // checks a cache object for emptiness
  1675. function isEmptyDataObject( obj ) {
  1676. for ( var name in obj ) {
  1677. // if the public data object is empty, the private is still empty
  1678. if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
  1679. continue;
  1680. }
  1681. if ( name !== "toJSON" ) {
  1682. return false;
  1683. }
  1684. }
  1685. return true;
  1686. }
  1687. function handleQueueMarkDefer( elem, type, src ) {
  1688. var deferDataKey = type + "defer",
  1689. queueDataKey = type + "queue",
  1690. markDataKey = type + "mark",
  1691. defer = jQuery._data( elem, deferDataKey );
  1692. if ( defer &&
  1693. ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
  1694. ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
  1695. // Give room for hard-coded callbacks to fire first
  1696. // and eventually mark/queue something else on the element
  1697. setTimeout( function() {
  1698. if ( !jQuery._data( elem, queueDataKey ) &&
  1699. !jQuery._data( elem, markDataKey ) ) {
  1700. jQuery.removeData( elem, deferDataKey, true );
  1701. defer.fire();
  1702. }
  1703. }, 0 );
  1704. }
  1705. }
  1706. jQuery.extend({
  1707. _mark: function( elem, type ) {
  1708. if ( elem ) {
  1709. type = ( type || "fx" ) + "mark";
  1710. jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
  1711. }
  1712. },
  1713. _unmark: function( force, elem, type ) {
  1714. if ( force !== true ) {
  1715. type = elem;
  1716. elem = force;
  1717. force = false;
  1718. }
  1719. if ( elem ) {
  1720. type = type || "fx";
  1721. var key = type + "mark",
  1722. count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
  1723. if ( count ) {
  1724. jQuery._data( elem, key, count );
  1725. } else {
  1726. jQuery.removeData( elem, key, true );
  1727. handleQueueMarkDefer( elem, type, "mark" );
  1728. }
  1729. }
  1730. },
  1731. queue: function( elem, type, data ) {
  1732. var q;
  1733. if ( elem ) {
  1734. type = ( type || "fx" ) + "queue";
  1735. q = jQuery._data( elem, type );
  1736. // Speed up dequeue by getting out quickly if this is just a lookup
  1737. if ( data ) {
  1738. if ( !q || jQuery.isArray(data) ) {
  1739. q = jQuery._data( elem, type, jQuery.makeArray(data) );
  1740. } else {
  1741. q.push( data );
  1742. }
  1743. }
  1744. return q || [];
  1745. }
  1746. },
  1747. dequeue: function( elem, type ) {
  1748. type = type || "fx";
  1749. var queue = jQuery.queue( elem, type ),
  1750. fn = queue.shift(),
  1751. hooks = {};
  1752. // If the fx queue is dequeued, always remove the progress sentinel
  1753. if ( fn === "inprogress" ) {
  1754. fn = queue.shift();
  1755. }
  1756. if ( fn ) {
  1757. // Add a progress sentinel to prevent the fx queue from being
  1758. // automatically dequeued
  1759. if ( type === "fx" ) {
  1760. queue.unshift( "inprogress" );
  1761. }
  1762. jQuery._data( elem, type + ".run", hooks );
  1763. fn.call( elem, function() {
  1764. jQuery.dequeue( elem, type );
  1765. }, hooks );
  1766. }
  1767. if ( !queue.length ) {
  1768. jQuery.removeData( elem, type + "queue " + type + ".run", true );
  1769. handleQueueMarkDefer( elem, type, "queue" );
  1770. }
  1771. }
  1772. });
  1773. jQuery.fn.extend({
  1774. queue: function( type, data ) {
  1775. var setter = 2;
  1776. if ( typeof type !== "string" ) {
  1777. data = type;
  1778. type = "fx";
  1779. setter--;
  1780. }
  1781. if ( arguments.length < setter ) {
  1782. return jQuery.queue( this[0], type );
  1783. }
  1784. return data === undefined ?
  1785. this :
  1786. this.each(function() {
  1787. var queue = jQuery.queue( this, type, data );
  1788. if ( type === "fx" && queue[0] !== "inprogress" ) {
  1789. jQuery.dequeue( this, type );
  1790. }
  1791. });
  1792. },
  1793. dequeue: function( type ) {
  1794. return this.each(function() {
  1795. jQuery.dequeue( this, type );
  1796. });
  1797. },
  1798. // Based off of the plugin by Clint Helfers, with permission.
  1799. // http://blindsignals.com/index.php/2009/07/jquery-delay/
  1800. delay: function( time, type ) {
  1801. time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
  1802. type = type || "fx";
  1803. return this.queue( type, function( next, hooks ) {
  1804. var timeout = setTimeout( next, time );
  1805. hooks.stop = function() {
  1806. clearTimeout( timeout );
  1807. };
  1808. });
  1809. },
  1810. clearQueue: function( type ) {
  1811. return this.queue( type || "fx", [] );
  1812. },
  1813. // Get a promise resolved when queues of a certain type
  1814. // are emptied (fx is the type by default)
  1815. promise: function( type, object ) {
  1816. if ( typeof type !== "string" ) {
  1817. object = type;
  1818. type = undefined;
  1819. }
  1820. type = type || "fx";
  1821. var defer = jQuery.Deferred(),
  1822. elements = this,
  1823. i = elements.length,
  1824. count = 1,
  1825. deferDataKey = type + "defer",
  1826. queueDataKey = type + "queue",
  1827. markDataKey = type + "mark",
  1828. tmp;
  1829. function resolve() {
  1830. if ( !( --count ) ) {
  1831. defer.resolveWith( elements, [ elements ] );
  1832. }
  1833. }
  1834. while( i-- ) {
  1835. if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
  1836. ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
  1837. jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
  1838. jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
  1839. count++;
  1840. tmp.add( resolve );
  1841. }
  1842. }
  1843. resolve();
  1844. return defer.promise( object );
  1845. }
  1846. });
  1847. var rclass = /[\n\t\r]/g,
  1848. rspace = /\s+/,
  1849. rreturn = /\r/g,
  1850. rtype = /^(?:button|input)$/i,
  1851. rfocusable = /^(?:button|input|object|select|textarea)$/i,
  1852. rclickable = /^a(?:rea)?$/i,
  1853. rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
  1854. getSetAttribute = jQuery.support.getSetAttribute,
  1855. nodeHook, boolHook, fixSpecified;
  1856. jQuery.fn.extend({
  1857. attr: function( name, value ) {
  1858. return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
  1859. },
  1860. removeAttr: function( name ) {
  1861. return this.each(function() {
  1862. jQuery.removeAttr( this, name );
  1863. });
  1864. },
  1865. prop: function( name, value ) {
  1866. return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
  1867. },
  1868. removeProp: function( name ) {
  1869. name = jQuery.propFix[ name ] || name;
  1870. return this.each(function() {
  1871. // try/catch handles cases where IE balks (such as removing a property on window)
  1872. try {
  1873. this[ name ] = undefined;
  1874. delete this[ name ];
  1875. } catch( e ) {}
  1876. });
  1877. },
  1878. addClass: function( value ) {
  1879. var classNames, i, l, elem,
  1880. setClass, c, cl;
  1881. if ( jQuery.isFunction( value ) ) {
  1882. return this.each(function( j ) {
  1883. jQuery( this ).addClass( value.call(this, j, this.className) );
  1884. });
  1885. }
  1886. if ( value && typeof value === "string" ) {
  1887. classNames = value.split( rspace );
  1888. for ( i = 0, l = this.length; i < l; i++ ) {
  1889. elem = this[ i ];
  1890. if ( elem.nodeType === 1 ) {
  1891. if ( !elem.className && classNames.length === 1 ) {
  1892. elem.className = value;
  1893. } else {
  1894. setClass = " " + elem.className + " ";
  1895. for ( c = 0, cl = classNames.length; c < cl; c++ ) {
  1896. if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
  1897. setClass += classNames[ c ] + " ";
  1898. }
  1899. }
  1900. elem.className = jQuery.trim( setClass );
  1901. }
  1902. }
  1903. }
  1904. }
  1905. return this;
  1906. },
  1907. removeClass: function( value ) {
  1908. var classNames, i, l, elem, className, c, cl;
  1909. if ( jQuery.isFunction( value ) ) {
  1910. return this.each(function( j ) {
  1911. jQuery( this ).removeClass( value.call(this, j, this.className) );
  1912. });
  1913. }
  1914. if ( (value && typeof value === "string") || value === undefined ) {
  1915. classNames = ( value || "" ).split( rspace );
  1916. for ( i = 0, l = this.length; i < l; i++ ) {
  1917. elem = this[ i ];
  1918. if ( elem.nodeType === 1 && elem.className ) {
  1919. if ( value ) {
  1920. className = (" " + elem.className + " ").replace( rclass, " " );
  1921. for ( c = 0, cl = classNames.length; c < cl; c++ ) {
  1922. className = className.replace(" " + classNames[ c ] + " ", " ");
  1923. }
  1924. elem.className = jQuery.trim( className );
  1925. } else {
  1926. elem.className = "";
  1927. }
  1928. }
  1929. }
  1930. }
  1931. return this;
  1932. },
  1933. toggleClass: function( value, stateVal ) {
  1934. var type = typeof value,
  1935. isBool = typeof stateVal === "boolean";
  1936. if ( jQuery.isFunction( value ) ) {
  1937. return this.each(function( i ) {
  1938. jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
  1939. });
  1940. }
  1941. return this.each(function() {
  1942. if ( type === "string" ) {
  1943. // toggle individual class names
  1944. var className,
  1945. i = 0,
  1946. self = jQuery( this ),
  1947. state = stateVal,
  1948. classNames = value.split( rspace );
  1949. while ( (className = classNames[ i++ ]) ) {
  1950. // check each className given, space seperated list
  1951. state = isBool ? state : !self.hasClass( className );
  1952. self[ state ? "addClass" : "removeClass" ]( className );
  1953. }
  1954. } else if ( type === "undefined" || type === "boolean" ) {
  1955. if ( this.className ) {
  1956. // store className if set
  1957. jQuery._data( this, "__className__", this.className );
  1958. }
  1959. // toggle whole className
  1960. this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
  1961. }
  1962. });
  1963. },
  1964. hasClass: function( selector ) {
  1965. var className = " " + selector + " ",
  1966. i = 0,
  1967. l = this.length;
  1968. for ( ; i < l; i++ ) {
  1969. if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
  1970. return true;
  1971. }
  1972. }
  1973. return false;
  1974. },
  1975. val: function( value ) {
  1976. var hooks, ret, isFunction,
  1977. elem = this[0];
  1978. if ( !arguments.length ) {
  1979. if ( elem ) {
  1980. hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
  1981. if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
  1982. return ret;
  1983. }
  1984. ret = elem.value;
  1985. return typeof ret === "string" ?
  1986. // handle most common string cases
  1987. ret.replace(rreturn, "") :
  1988. // handle cases where value is null/undef or number
  1989. ret == null ? "" : ret;
  1990. }
  1991. return;
  1992. }
  1993. isFunction = jQuery.isFunction( value );
  1994. return this.each(function( i ) {
  1995. var self = jQuery(this), val;
  1996. if ( this.nodeType !== 1 ) {
  1997. return;
  1998. }
  1999. if ( isFunction ) {
  2000. val = value.call( this, i, self.val() );
  2001. } else {
  2002. val = value;
  2003. }
  2004. // Treat null/undefined as ""; convert numbers to string
  2005. if ( val == null ) {
  2006. val = "";
  2007. } else if ( typeof val === "number" ) {
  2008. val += "";
  2009. } else if ( jQuery.isArray( val ) ) {
  2010. val = jQuery.map(val, function ( value ) {
  2011. return value == null ? "" : value + "";
  2012. });
  2013. }
  2014. hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
  2015. // If set returns undefined, fall back to normal setting
  2016. if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
  2017. this.value = val;
  2018. }
  2019. });
  2020. }
  2021. });
  2022. jQuery.extend({
  2023. valHooks: {
  2024. option: {
  2025. get: function( elem ) {
  2026. // attributes.value is undefined in Blackberry 4.7 but
  2027. // uses .value. See #6932
  2028. var val = elem.attributes.value;
  2029. return !val || val.specified ? elem.value : elem.text;
  2030. }
  2031. },
  2032. select: {
  2033. get: function( elem ) {
  2034. var value, i, max, option,
  2035. index = elem.selectedIndex,
  2036. values = [],
  2037. options = elem.options,
  2038. one = elem.type === "select-one";
  2039. // Nothing was selected
  2040. if ( index < 0 ) {
  2041. return null;
  2042. }
  2043. // Loop through all the selected options
  2044. i = one ? index : 0;
  2045. max = one ? index + 1 : options.length;
  2046. for ( ; i < max; i++ ) {
  2047. option = options[ i ];
  2048. // Don't return options that are disabled or in a disabled optgroup
  2049. if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
  2050. (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
  2051. // Get the specific value for the option
  2052. value = jQuery( option ).val();
  2053. // We don't need an array for one selects
  2054. if ( one ) {
  2055. return value;
  2056. }
  2057. // Multi-Selects return an array
  2058. values.push( value );
  2059. }
  2060. }
  2061. // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
  2062. if ( one && !values.length && options.length ) {
  2063. return jQuery( options[ index ] ).val();
  2064. }
  2065. return values;
  2066. },
  2067. set: function( elem, value ) {
  2068. var values = jQuery.makeArray( value );
  2069. jQuery(elem).find("option").each(function() {
  2070. this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
  2071. });
  2072. if ( !values.length ) {
  2073. elem.selectedIndex = -1;
  2074. }
  2075. return values;
  2076. }
  2077. }
  2078. },
  2079. attrFn: {
  2080. val: true,
  2081. css: true,
  2082. html: true,
  2083. text: true,
  2084. data: true,
  2085. width: true,
  2086. height: true,
  2087. offset: true
  2088. },
  2089. attr: function( elem, name, value, pass ) {
  2090. var ret, hooks, notxml,
  2091. nType = elem.nodeType;
  2092. // don't get/set attributes on text, comment and attribute nodes
  2093. if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
  2094. return;
  2095. }
  2096. if ( pass && name in jQuery.attrFn ) {
  2097. return jQuery( elem )[ name ]( value );
  2098. }
  2099. // Fallback to prop when attributes are not supported
  2100. if ( typeof elem.getAttribute === "undefined" ) {
  2101. return jQuery.prop( elem, name, value );
  2102. }
  2103. notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
  2104. // All attributes are lowercase
  2105. // Grab necessary hook if one is defined
  2106. if ( notxml ) {
  2107. name = name.toLowerCase();
  2108. hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
  2109. }
  2110. if ( value !== undefined ) {
  2111. if ( value === null ) {
  2112. jQuery.removeAttr( elem, name );
  2113. return;
  2114. } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
  2115. return ret;
  2116. } else {
  2117. elem.setAttribute( name, "" + value );
  2118. return value;
  2119. }
  2120. } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
  2121. return ret;
  2122. } else {
  2123. ret = elem.getAttribute( name );
  2124. // Non-existent attributes return null, we normalize to undefined
  2125. return ret === null ?
  2126. undefined :
  2127. ret;
  2128. }
  2129. },
  2130. removeAttr: function( elem, value ) {
  2131. var propName, attrNames, name, l, isBool,
  2132. i = 0;
  2133. if ( value && elem.nodeType === 1 ) {
  2134. attrNames = value.toLowerCase().split( rspace );
  2135. l = attrNames.length;
  2136. for ( ; i < l; i++ ) {
  2137. name = attrNames[ i ];
  2138. if ( name ) {
  2139. propName = jQuery.propFix[ name ] || name;
  2140. isBool = rboolean.test( name );
  2141. // See #9699 for explanation of this approach (setting first, then removal)
  2142. // Do not do this for boolean attributes (see #10870)
  2143. if ( !isBool ) {
  2144. jQuery.attr( elem, name, "" );
  2145. }
  2146. elem.removeAttribute( getSetAttribute ? name : propName );
  2147. // Set corresponding property to false for boolean attributes
  2148. if ( isBool && propName in elem ) {
  2149. elem[ propName ] = false;
  2150. }
  2151. }
  2152. }
  2153. }
  2154. },
  2155. attrHooks: {
  2156. type: {
  2157. set: function( elem, value ) {
  2158. // We can't allow the type property to be changed (since it causes problems in IE)
  2159. if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
  2160. jQuery.error( "type property can't be changed" );
  2161. } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
  2162. // Setting the type on a radio button after the value resets the value in IE6-9
  2163. // Reset value to it's default in case type is set after value
  2164. // This is for element creation
  2165. var val = elem.value;
  2166. elem.setAttribute( "type", value );
  2167. if ( val ) {
  2168. elem.value = val;
  2169. }
  2170. return value;
  2171. }
  2172. }
  2173. },
  2174. // Use the value property for back compat
  2175. // Use the nodeHook for button elements in IE6/7 (#1954)
  2176. value: {
  2177. get: function( elem, name ) {
  2178. if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
  2179. return nodeHook.get( elem, name );
  2180. }
  2181. return name in elem ?
  2182. elem.value :
  2183. null;
  2184. },
  2185. set: function( elem, value, name ) {
  2186. if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
  2187. return nodeHook.set( elem, value, name );
  2188. }
  2189. // Does not return so that setAttribute is also used
  2190. elem.value = value;
  2191. }
  2192. }
  2193. },
  2194. propFix: {
  2195. tabindex: "tabIndex",
  2196. readonly: "readOnly",
  2197. "for": "htmlFor",
  2198. "class": "className",
  2199. maxlength: "maxLength",
  2200. cellspacing: "cellSpacing",
  2201. cellpadding: "cellPadding",
  2202. rowspan: "rowSpan",
  2203. colspan: "colSpan",
  2204. usemap: "useMap",
  2205. frameborder: "frameBorder",
  2206. contenteditable: "contentEditable"
  2207. },
  2208. prop: function( elem, name, value ) {
  2209. var ret, hooks, notxml,
  2210. nType = elem.nodeType;
  2211. // don't get/set properties on text, comment and attribute nodes
  2212. if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
  2213. return;
  2214. }
  2215. notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
  2216. if ( notxml ) {
  2217. // Fix name and attach hooks
  2218. name = jQuery.propFix[ name ] || name;
  2219. hooks = jQuery.propHooks[ name ];
  2220. }
  2221. if ( value !== undefined ) {
  2222. if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
  2223. return ret;
  2224. } else {
  2225. return ( elem[ name ] = value );
  2226. }
  2227. } else {
  2228. if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
  2229. return ret;
  2230. } else {
  2231. return elem[ name ];
  2232. }
  2233. }
  2234. },
  2235. propHooks: {
  2236. tabIndex: {
  2237. get: function( elem ) {
  2238. // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
  2239. // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
  2240. var attributeNode = elem.getAttributeNode("tabindex");
  2241. return attributeNode && attributeNode.specified ?
  2242. parseInt( attributeNode.value, 10 ) :
  2243. rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
  2244. 0 :
  2245. undefined;
  2246. }
  2247. }
  2248. }
  2249. });
  2250. // Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
  2251. jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
  2252. // Hook for boolean attributes
  2253. boolHook = {
  2254. get: function( elem, name ) {
  2255. // Align boolean attributes with corresponding properties
  2256. // Fall back to attribute presence where some booleans are not supported
  2257. var attrNode,
  2258. property = jQuery.prop( elem, name );
  2259. return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
  2260. name.toLowerCase() :
  2261. undefined;
  2262. },
  2263. set: function( elem, value, name ) {
  2264. var propName;
  2265. if ( value === false ) {
  2266. // Remove boolean attributes when set to false
  2267. jQuery.removeAttr( elem, name );
  2268. } else {
  2269. // value is true since we know at this point it's type boolean and not false
  2270. // Set boolean attributes to the same name and set the DOM property
  2271. propName = jQuery.propFix[ name ] || name;
  2272. if ( propName in elem ) {
  2273. // Only set the IDL specifically if it already exists on the element
  2274. elem[ propName ] = true;
  2275. }
  2276. elem.setAttribute( name, name.toLowerCase() );
  2277. }
  2278. return name;
  2279. }
  2280. };
  2281. // IE6/7 do not support getting/setting some attributes with get/setAttribute
  2282. if ( !getSetAttribute ) {
  2283. fixSpecified = {
  2284. name: true,
  2285. id: true,
  2286. coords: true
  2287. };
  2288. // Use this for any attribute in IE6/7
  2289. // This fixes almost every IE6/7 issue
  2290. nodeHook = jQuery.valHooks.button = {
  2291. get: function( elem, name ) {
  2292. var ret;
  2293. ret = elem.getAttributeNode( name );
  2294. return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
  2295. ret.nodeValue :
  2296. undefined;
  2297. },
  2298. set: function( elem, value, name ) {
  2299. // Set the existing or create a new attribute node
  2300. var ret = elem.getAttributeNode( name );
  2301. if ( !ret ) {
  2302. ret = document.createAttribute( name );
  2303. elem.setAttributeNode( ret );
  2304. }
  2305. return ( ret.nodeValue = value + "" );
  2306. }
  2307. };
  2308. // Apply the nodeHook to tabindex
  2309. jQuery.attrHooks.tabindex.set = nodeHook.set;
  2310. // Set width and height to auto instead of 0 on empty string( Bug #8150 )
  2311. // This is for removals
  2312. jQuery.each([ "width", "height" ], function( i, name ) {
  2313. jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
  2314. set: function( elem, value ) {
  2315. if ( value === "" ) {
  2316. elem.setAttribute( name, "auto" );
  2317. return value;
  2318. }
  2319. }
  2320. });
  2321. });
  2322. // Set contenteditable to false on removals(#10429)
  2323. // Setting to empty string throws an error as an invalid value
  2324. jQuery.attrHooks.contenteditable = {
  2325. get: nodeHook.get,
  2326. set: function( elem, value, name ) {
  2327. if ( value === "" ) {
  2328. value = "false";
  2329. }
  2330. nodeHook.set( elem, value, name );
  2331. }
  2332. };
  2333. }
  2334. // Some attributes require a special call on IE
  2335. if ( !jQuery.support.hrefNormalized ) {
  2336. jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
  2337. jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
  2338. get: function( elem ) {
  2339. var ret = elem.getAttribute( name, 2 );
  2340. return ret === null ? undefined : ret;
  2341. }
  2342. });
  2343. });
  2344. }
  2345. if ( !jQuery.support.style ) {
  2346. jQuery.attrHooks.style = {
  2347. get: function( elem ) {
  2348. // Return undefined in the case of empty string
  2349. // Normalize to lowercase since IE uppercases css property names
  2350. return elem.style.cssText.toLowerCase() || undefined;
  2351. },
  2352. set: function( elem, value ) {
  2353. return ( elem.style.cssText = "" + value );
  2354. }
  2355. };
  2356. }
  2357. // Safari mis-reports the default selected property of an option
  2358. // Accessing the parent's selectedIndex property fixes it
  2359. if ( !jQuery.support.optSelected ) {
  2360. jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
  2361. get: function( elem ) {
  2362. var parent = elem.parentNode;
  2363. if ( parent ) {
  2364. parent.selectedIndex;
  2365. // Make sure that it also works with optgroups, see #5701
  2366. if ( parent.parentNode ) {
  2367. parent.parentNode.selectedIndex;
  2368. }
  2369. }
  2370. return null;
  2371. }
  2372. });
  2373. }
  2374. // IE6/7 call enctype encoding
  2375. if ( !jQuery.support.enctype ) {
  2376. jQuery.propFix.enctype = "encoding";
  2377. }
  2378. // Radios and checkboxes getter/setter
  2379. if ( !jQuery.support.checkOn ) {
  2380. jQuery.each([ "radio", "checkbox" ], function() {
  2381. jQuery.valHooks[ this ] = {
  2382. get: function( elem ) {
  2383. // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
  2384. return elem.getAttribute("value") === null ? "on" : elem.value;
  2385. }
  2386. };
  2387. });
  2388. }
  2389. jQuery.each([ "radio", "checkbox" ], function() {
  2390. jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
  2391. set: function( elem, value ) {
  2392. if ( jQuery.isArray( value ) ) {
  2393. return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
  2394. }
  2395. }
  2396. });
  2397. });
  2398. var rformElems = /^(?:textarea|input|select)$/i,
  2399. rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
  2400. rhoverHack = /(?:^|\s)hover(\.\S+)?\b/,
  2401. rkeyEvent = /^key/,
  2402. rmouseEvent = /^(?:mouse|contextmenu)|click/,
  2403. rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
  2404. rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
  2405. quickParse = function( selector ) {
  2406. var quick = rquickIs.exec( selector );
  2407. if ( quick ) {
  2408. // 0 1 2 3
  2409. // [ _, tag, id, class ]
  2410. quick[1] = ( quick[1] || "" ).toLowerCase();
  2411. quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
  2412. }
  2413. return quick;
  2414. },
  2415. quickIs = function( elem, m ) {
  2416. var attrs = elem.attributes || {};
  2417. return (
  2418. (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
  2419. (!m[2] || (attrs.id || {}).value === m[2]) &&
  2420. (!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
  2421. );
  2422. },
  2423. hoverHack = function( events ) {
  2424. return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
  2425. };
  2426. /*
  2427. * Helper functions for managing events -- not part of the public interface.
  2428. * Props to Dean Edwards' addEvent library for many of the ideas.
  2429. */
  2430. jQuery.event = {
  2431. add: function( elem, types, handler, data, selector ) {
  2432. var elemData, eventHandle, events,
  2433. t, tns, type, namespaces, handleObj,
  2434. handleObjIn, quick, handlers, special;
  2435. // Don't attach events to noData or text/comment nodes (allow plain objects tho)
  2436. if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
  2437. return;
  2438. }
  2439. // Caller can pass in an object of custom data in lieu of the handler
  2440. if ( handler.handler ) {
  2441. handleObjIn = handler;
  2442. handler = handleObjIn.handler;
  2443. selector = handleObjIn.selector;
  2444. }
  2445. // Make sure that the handler has a unique ID, used to find/remove it later
  2446. if ( !handler.guid ) {
  2447. handler.guid = jQuery.guid++;
  2448. }
  2449. // Init the element's event structure and main handler, if this is the first
  2450. events = elemData.events;
  2451. if ( !events ) {
  2452. elemData.events = events = {};
  2453. }
  2454. eventHandle = elemData.handle;
  2455. if ( !eventHandle ) {
  2456. elemData.handle = eventHandle = function( e ) {
  2457. // Discard the second event of a jQuery.event.trigger() and
  2458. // when an event is called after a page has unloaded
  2459. return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
  2460. jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
  2461. undefined;
  2462. };
  2463. // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
  2464. eventHandle.elem = elem;
  2465. }
  2466. // Handle multiple events separated by a space
  2467. // jQuery(...).bind("mouseover mouseout", fn);
  2468. types = jQuery.trim( hoverHack(types) ).split( " " );
  2469. for ( t = 0; t < types.length; t++ ) {
  2470. tns = rtypenamespace.exec( types[t] ) || [];
  2471. type = tns[1];
  2472. namespaces = ( tns[2] || "" ).split( "." ).sort();
  2473. // If event changes its type, use the special event handlers for the changed type
  2474. special = jQuery.event.special[ type ] || {};
  2475. // If selector defined, determine special event api type, otherwise given type
  2476. type = ( selector ? special.delegateType : special.bindType ) || type;
  2477. // Update special based on newly reset type
  2478. special = jQuery.event.special[ type ] || {};
  2479. // handleObj is passed to all event handlers
  2480. handleObj = jQuery.extend({
  2481. type: type,
  2482. origType: tns[1],
  2483. data: data,
  2484. handler: handler,
  2485. guid: handler.guid,
  2486. selector: selector,
  2487. quick: selector && quickParse( selector ),
  2488. namespace: namespaces.join(".")
  2489. }, handleObjIn );
  2490. // Init the event handler queue if we're the first
  2491. handlers = events[ type ];
  2492. if ( !handlers ) {
  2493. handlers = events[ type ] = [];
  2494. handlers.delegateCount = 0;
  2495. // Only use addEventListener/attachEvent if the special events handler returns false
  2496. if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
  2497. // Bind the global event handler to the element
  2498. if ( elem.addEventListener ) {
  2499. elem.addEventListener( type, eventHandle, false );
  2500. } else if ( elem.attachEvent ) {
  2501. elem.attachEvent( "on" + type, eventHandle );
  2502. }
  2503. }
  2504. }
  2505. if ( special.add ) {
  2506. special.add.call( elem, handleObj );
  2507. if ( !handleObj.handler.guid ) {
  2508. handleObj.handler.guid = handler.guid;
  2509. }
  2510. }
  2511. // Add to the element's handler list, delegates in front
  2512. if ( selector ) {
  2513. handlers.splice( handlers.delegateCount++, 0, handleObj );
  2514. } else {
  2515. handlers.push( handleObj );
  2516. }
  2517. // Keep track of which events have ever been used, for event optimization
  2518. jQuery.event.global[ type ] = true;
  2519. }
  2520. // Nullify elem to prevent memory leaks in IE
  2521. elem = null;
  2522. },
  2523. global: {},
  2524. // Detach an event or set of events from an element
  2525. remove: function( elem, types, handler, selector, mappedTypes ) {
  2526. var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
  2527. t, tns, type, origType, namespaces, origCount,
  2528. j, events, special, handle, eventType, handleObj;
  2529. if ( !elemData || !(events = elemData.events) ) {
  2530. return;
  2531. }
  2532. // Once for each type.namespace in types; type may be omitted
  2533. types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
  2534. for ( t = 0; t < types.length; t++ ) {
  2535. tns = rtypenamespace.exec( types[t] ) || [];
  2536. type = origType = tns[1];
  2537. namespaces = tns[2];
  2538. // Unbind all events (on this namespace, if provided) for the element
  2539. if ( !type ) {
  2540. for ( type in events ) {
  2541. jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
  2542. }
  2543. continue;
  2544. }
  2545. special = jQuery.event.special[ type ] || {};
  2546. type = ( selector? special.delegateType : special.bindType ) || type;
  2547. eventType = events[ type ] || [];
  2548. origCount = eventType.length;
  2549. namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
  2550. // Remove matching events
  2551. for ( j = 0; j < eventType.length; j++ ) {
  2552. handleObj = eventType[ j ];
  2553. if ( ( mappedTypes || origType === handleObj.origType ) &&
  2554. ( !handler || handler.guid === handleObj.guid ) &&
  2555. ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
  2556. ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
  2557. eventType.splice( j--, 1 );
  2558. if ( handleObj.selector ) {
  2559. eventType.delegateCount--;
  2560. }
  2561. if ( special.remove ) {
  2562. special.remove.call( elem, handleObj );
  2563. }
  2564. }
  2565. }
  2566. // Remove generic event handler if we removed something and no more handlers exist
  2567. // (avoids potential for endless recursion during removal of special event handlers)
  2568. if ( eventType.length === 0 && origCount !== eventType.length ) {
  2569. if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
  2570. jQuery.removeEvent( elem, type, elemData.handle );
  2571. }
  2572. delete events[ type ];
  2573. }
  2574. }
  2575. // Remove the expando if it's no longer used
  2576. if ( jQuery.isEmptyObject( events ) ) {
  2577. handle = elemData.handle;
  2578. if ( handle ) {
  2579. handle.elem = null;
  2580. }
  2581. // removeData also checks for emptiness and clears the expando if empty
  2582. // so use it instead of delete
  2583. jQuery.removeData( elem, [ "events", "handle" ], true );
  2584. }
  2585. },
  2586. // Events that are safe to short-circuit if no handlers are attached.
  2587. // Native DOM events should not be added, they may have inline handlers.
  2588. customEvent: {
  2589. "getData": true,
  2590. "setData": true,
  2591. "changeData": true
  2592. },
  2593. trigger: function( event, data, elem, onlyHandlers ) {
  2594. // Don't do events on text and comment nodes
  2595. if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
  2596. return;
  2597. }
  2598. // Event object or event type
  2599. var type = event.type || event,
  2600. namespaces = [],
  2601. cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
  2602. // focus/blur morphs to focusin/out; ensure we're not firing them right now
  2603. if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
  2604. return;
  2605. }
  2606. if ( type.indexOf( "!" ) >= 0 ) {
  2607. // Exclusive events trigger only for the exact event (no namespaces)
  2608. type = type.slice(0, -1);
  2609. exclusive = true;
  2610. }
  2611. if ( type.indexOf( "." ) >= 0 ) {
  2612. // Namespaced trigger; create a regexp to match event type in handle()
  2613. namespaces = type.split(".");
  2614. type = namespaces.shift();
  2615. namespaces.sort();
  2616. }
  2617. if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
  2618. // No jQuery handlers for this event type, and it can't have inline handlers
  2619. return;
  2620. }
  2621. // Caller can pass in an Event, Object, or just an event type string
  2622. event = typeof event === "object" ?
  2623. // jQuery.Event object
  2624. event[ jQuery.expando ] ? event :
  2625. // Object literal
  2626. new jQuery.Event( type, event ) :
  2627. // Just the event type (string)
  2628. new jQuery.Event( type );
  2629. event.type = type;
  2630. event.isTrigger = true;
  2631. event.exclusive = exclusive;
  2632. event.namespace = namespaces.join( "." );
  2633. event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
  2634. ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
  2635. // Handle a global trigger
  2636. if ( !elem ) {
  2637. // TODO: Stop taunting the data cache; remove global events and always attach to document
  2638. cache = jQuery.cache;
  2639. for ( i in cache ) {
  2640. if ( cache[ i ].events && cache[ i ].events[ type ] ) {
  2641. jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
  2642. }
  2643. }
  2644. return;
  2645. }
  2646. // Clean up the event in case it is being reused
  2647. event.result = undefined;
  2648. if ( !event.target ) {
  2649. event.target = elem;
  2650. }
  2651. // Clone any incoming data and prepend the event, creating the handler arg list
  2652. data = data != null ? jQuery.makeArray( data ) : [];
  2653. data.unshift( event );
  2654. // Allow special events to draw outside the lines
  2655. special = jQuery.event.special[ type ] || {};
  2656. if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
  2657. return;
  2658. }
  2659. // Determine event propagation path in advance, per W3C events spec (#9951)
  2660. // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
  2661. eventPath = [[ elem, special.bindType || type ]];
  2662. if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
  2663. bubbleType = special.delegateType || type;
  2664. cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
  2665. old = null;
  2666. for ( ; cur; cur = cur.parentNode ) {
  2667. eventPath.push([ cur, bubbleType ]);
  2668. old = cur;
  2669. }
  2670. // Only add window if we got to document (e.g., not plain obj or detached DOM)
  2671. if ( old && old === elem.ownerDocument ) {
  2672. eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
  2673. }
  2674. }
  2675. // Fire handlers on the event path
  2676. for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
  2677. cur = eventPath[i][0];
  2678. event.type = eventPath[i][1];
  2679. handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
  2680. if ( handle ) {
  2681. handle.apply( cur, data );
  2682. }
  2683. // Note that this is a bare JS function and not a jQuery handler
  2684. handle = ontype && cur[ ontype ];
  2685. if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
  2686. event.preventDefault();
  2687. }
  2688. }
  2689. event.type = type;
  2690. // If nobody prevented the default action, do it now
  2691. if ( !onlyHandlers && !event.isDefaultPrevented() ) {
  2692. if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
  2693. !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
  2694. // Call a native DOM method on the target with the same name name as the event.
  2695. // Can't use an .isFunction() check here because IE6/7 fails that test.
  2696. // Don't do default actions on window, that's where global variables be (#6170)
  2697. // IE<9 dies on focus/blur to hidden element (#1486)
  2698. if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
  2699. // Don't re-trigger an onFOO event when we call its FOO() method
  2700. old = elem[ ontype ];
  2701. if ( old ) {
  2702. elem[ ontype ] = null;
  2703. }
  2704. // Prevent re-triggering of the same event, since we already bubbled it above
  2705. jQuery.event.triggered = type;
  2706. elem[ type ]();
  2707. jQuery.event.triggered = undefined;
  2708. if ( old ) {
  2709. elem[ ontype ] = old;
  2710. }
  2711. }
  2712. }
  2713. }
  2714. return event.result;
  2715. },
  2716. dispatch: function( event ) {
  2717. // Make a writable jQuery.Event from the native event object
  2718. event = jQuery.event.fix( event || window.event );
  2719. var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
  2720. delegateCount = handlers.delegateCount,
  2721. args = [].slice.call( arguments, 0 ),
  2722. run_all = !event.exclusive && !event.namespace,
  2723. special = jQuery.event.special[ event.type ] || {},
  2724. handlerQueue = [],
  2725. i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
  2726. // Use the fix-ed jQuery.Event rather than the (read-only) native event
  2727. args[0] = event;
  2728. event.delegateTarget = this;
  2729. // Call the preDispatch hook for the mapped type, and let it bail if desired
  2730. if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
  2731. return;
  2732. }
  2733. // Determine handlers that should run if there are delegated events
  2734. // Avoid non-left-click bubbling in Firefox (#3861)
  2735. if ( delegateCount && !(event.button && event.type === "click") ) {
  2736. // Pregenerate a single jQuery object for reuse with .is()
  2737. jqcur = jQuery(this);
  2738. jqcur.context = this.ownerDocument || this;
  2739. for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
  2740. // Don't process events on disabled elements (#6911, #8165)
  2741. if ( cur.disabled !== true ) {
  2742. selMatch = {};
  2743. matches = [];
  2744. jqcur[0] = cur;
  2745. for ( i = 0; i < delegateCount; i++ ) {
  2746. handleObj = handlers[ i ];
  2747. sel = handleObj.selector;
  2748. if ( selMatch[ sel ] === undefined ) {
  2749. selMatch[ sel ] = (
  2750. handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
  2751. );
  2752. }
  2753. if ( selMatch[ sel ] ) {
  2754. matches.push( handleObj );
  2755. }
  2756. }
  2757. if ( matches.length ) {
  2758. handlerQueue.push({ elem: cur, matches: matches });
  2759. }
  2760. }
  2761. }
  2762. }
  2763. // Add the remaining (directly-bound) handlers
  2764. if ( handlers.length > delegateCount ) {
  2765. handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
  2766. }
  2767. // Run delegates first; they may want to stop propagation beneath us
  2768. for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
  2769. matched = handlerQueue[ i ];
  2770. event.currentTarget = matched.elem;
  2771. for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
  2772. handleObj = matched.matches[ j ];
  2773. // Triggered event must either 1) be non-exclusive and have no namespace, or
  2774. // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
  2775. if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
  2776. event.data = handleObj.data;
  2777. event.handleObj = handleObj;
  2778. ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
  2779. .apply( matched.elem, args );
  2780. if ( ret !== undefined ) {
  2781. event.result = ret;
  2782. if ( ret === false ) {
  2783. event.preventDefault();
  2784. event.stopPropagation();
  2785. }
  2786. }
  2787. }
  2788. }
  2789. }
  2790. // Call the postDispatch hook for the mapped type
  2791. if ( special.postDispatch ) {
  2792. special.postDispatch.call( this, event );
  2793. }
  2794. return event.result;
  2795. },
  2796. // Includes some event props shared by KeyEvent and MouseEvent
  2797. // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
  2798. props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
  2799. fixHooks: {},
  2800. keyHooks: {
  2801. props: "char charCode key keyCode".split(" "),
  2802. filter: function( event, original ) {
  2803. // Add which for key events
  2804. if ( event.which == null ) {
  2805. event.which = original.charCode != null ? original.charCode : original.keyCode;
  2806. }
  2807. return event;
  2808. }
  2809. },
  2810. mouseHooks: {
  2811. props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
  2812. filter: function( event, original ) {
  2813. var eventDoc, doc, body,
  2814. button = original.button,
  2815. fromElement = original.fromElement;
  2816. // Calculate pageX/Y if missing and clientX/Y available
  2817. if ( event.pageX == null && original.clientX != null ) {
  2818. eventDoc = event.target.ownerDocument || document;
  2819. doc = eventDoc.documentElement;
  2820. body = eventDoc.body;
  2821. event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
  2822. event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
  2823. }
  2824. // Add relatedTarget, if necessary
  2825. if ( !event.relatedTarget && fromElement ) {
  2826. event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
  2827. }
  2828. // Add which for click: 1 === left; 2 === middle; 3 === right
  2829. // Note: button is not normalized, so don't use it
  2830. if ( !event.which && button !== undefined ) {
  2831. event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
  2832. }
  2833. return event;
  2834. }
  2835. },
  2836. fix: function( event ) {
  2837. if ( event[ jQuery.expando ] ) {
  2838. return event;
  2839. }
  2840. // Create a writable copy of the event object and normalize some properties
  2841. var i, prop,
  2842. originalEvent = event,
  2843. fixHook = jQuery.event.fixHooks[ event.type ] || {},
  2844. copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
  2845. event = jQuery.Event( originalEvent );
  2846. for ( i = copy.length; i; ) {
  2847. prop = copy[ --i ];
  2848. event[ prop ] = originalEvent[ prop ];
  2849. }
  2850. // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
  2851. if ( !event.target ) {
  2852. event.target = originalEvent.srcElement || document;
  2853. }
  2854. // Target should not be a text node (#504, Safari)
  2855. if ( event.target.nodeType === 3 ) {
  2856. event.target = event.target.parentNode;
  2857. }
  2858. // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
  2859. if ( event.metaKey === undefined ) {
  2860. event.metaKey = event.ctrlKey;
  2861. }
  2862. return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
  2863. },
  2864. special: {
  2865. ready: {
  2866. // Make sure the ready event is setup
  2867. setup: jQuery.bindReady
  2868. },
  2869. load: {
  2870. // Prevent triggered image.load events from bubbling to window.load
  2871. noBubble: true
  2872. },
  2873. focus: {
  2874. delegateType: "focusin"
  2875. },
  2876. blur: {
  2877. delegateType: "focusout"
  2878. },
  2879. beforeunload: {
  2880. setup: function( data, namespaces, eventHandle ) {
  2881. // We only want to do this special case on windows
  2882. if ( jQuery.isWindow( this ) ) {
  2883. this.onbeforeunload = eventHandle;
  2884. }
  2885. },
  2886. teardown: function( namespaces, eventHandle ) {
  2887. if ( this.onbeforeunload === eventHandle ) {
  2888. this.onbeforeunload = null;
  2889. }
  2890. }
  2891. }
  2892. },
  2893. simulate: function( type, elem, event, bubble ) {
  2894. // Piggyback on a donor event to simulate a different one.
  2895. // Fake originalEvent to avoid donor's stopPropagation, but if the
  2896. // simulated event prevents default then we do the same on the donor.
  2897. var e = jQuery.extend(
  2898. new jQuery.Event(),
  2899. event,
  2900. { type: type,
  2901. isSimulated: true,
  2902. originalEvent: {}
  2903. }
  2904. );
  2905. if ( bubble ) {
  2906. jQuery.event.trigger( e, null, elem );
  2907. } else {
  2908. jQuery.event.dispatch.call( elem, e );
  2909. }
  2910. if ( e.isDefaultPrevented() ) {
  2911. event.preventDefault();
  2912. }
  2913. }
  2914. };
  2915. // Some plugins are using, but it's undocumented/deprecated and will be removed.
  2916. // The 1.7 special event interface should provide all the hooks needed now.
  2917. jQuery.event.handle = jQuery.event.dispatch;
  2918. jQuery.removeEvent = document.removeEventListener ?
  2919. function( elem, type, handle ) {
  2920. if ( elem.removeEventListener ) {
  2921. elem.removeEventListener( type, handle, false );
  2922. }
  2923. } :
  2924. function( elem, type, handle ) {
  2925. if ( elem.detachEvent ) {
  2926. elem.detachEvent( "on" + type, handle );
  2927. }
  2928. };
  2929. jQuery.Event = function( src, props ) {
  2930. // Allow instantiation without the 'new' keyword
  2931. if ( !(this instanceof jQuery.Event) ) {
  2932. return new jQuery.Event( src, props );
  2933. }
  2934. // Event object
  2935. if ( src && src.type ) {
  2936. this.originalEvent = src;
  2937. this.type = src.type;
  2938. // Events bubbling up the document may have been marked as prevented
  2939. // by a handler lower down the tree; reflect the correct value.
  2940. this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
  2941. src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
  2942. // Event type
  2943. } else {
  2944. this.type = src;
  2945. }
  2946. // Put explicitly provided properties onto the event object
  2947. if ( props ) {
  2948. jQuery.extend( this, props );
  2949. }
  2950. // Create a timestamp if incoming event doesn't have one
  2951. this.timeStamp = src && src.timeStamp || jQuery.now();
  2952. // Mark it as fixed
  2953. this[ jQuery.expando ] = true;
  2954. };
  2955. function returnFalse() {
  2956. return false;
  2957. }
  2958. function returnTrue() {
  2959. return true;
  2960. }
  2961. // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
  2962. // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
  2963. jQuery.Event.prototype = {
  2964. preventDefault: function() {
  2965. this.isDefaultPrevented = returnTrue;
  2966. var e = this.originalEvent;
  2967. if ( !e ) {
  2968. return;
  2969. }
  2970. // if preventDefault exists run it on the original event
  2971. if ( e.preventDefault ) {
  2972. e.preventDefault();
  2973. // otherwise set the returnValue property of the original event to false (IE)
  2974. } else {
  2975. e.returnValue = false;
  2976. }
  2977. },
  2978. stopPropagation: function() {
  2979. this.isPropagationStopped = returnTrue;
  2980. var e = this.originalEvent;
  2981. if ( !e ) {
  2982. return;
  2983. }
  2984. // if stopPropagation exists run it on the original event
  2985. if ( e.stopPropagation ) {
  2986. e.stopPropagation();
  2987. }
  2988. // otherwise set the cancelBubble property of the original event to true (IE)
  2989. e.cancelBubble = true;
  2990. },
  2991. stopImmediatePropagation: function() {
  2992. this.isImmediatePropagationStopped = returnTrue;
  2993. this.stopPropagation();
  2994. },
  2995. isDefaultPrevented: returnFalse,
  2996. isPropagationStopped: returnFalse,
  2997. isImmediatePropagationStopped: returnFalse
  2998. };
  2999. // Create mouseenter/leave events using mouseover/out and event-time checks
  3000. jQuery.each({
  3001. mouseenter: "mouseover",
  3002. mouseleave: "mouseout"
  3003. }, function( orig, fix ) {
  3004. jQuery.event.special[ orig ] = {
  3005. delegateType: fix,
  3006. bindType: fix,
  3007. handle: function( event ) {
  3008. var target = this,
  3009. related = event.relatedTarget,
  3010. handleObj = event.handleObj,
  3011. selector = handleObj.selector,
  3012. ret;
  3013. // For mousenter/leave call the handler if related is outside the target.
  3014. // NB: No relatedTarget if the mouse left/entered the browser window
  3015. if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
  3016. event.type = handleObj.origType;
  3017. ret = handleObj.handler.apply( this, arguments );
  3018. event.type = fix;
  3019. }
  3020. return ret;
  3021. }
  3022. };
  3023. });
  3024. // IE submit delegation
  3025. if ( !jQuery.support.submitBubbles ) {
  3026. jQuery.event.special.submit = {
  3027. setup: function() {
  3028. // Only need this for delegated form submit events
  3029. if ( jQuery.nodeName( this, "form" ) ) {
  3030. return false;
  3031. }
  3032. // Lazy-add a submit handler when a descendant form may potentially be submitted
  3033. jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
  3034. // Node name check avoids a VML-related crash in IE (#9807)
  3035. var elem = e.target,
  3036. form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
  3037. if ( form && !form._submit_attached ) {
  3038. jQuery.event.add( form, "submit._submit", function( event ) {
  3039. event._submit_bubble = true;
  3040. });
  3041. form._submit_attached = true;
  3042. }
  3043. });
  3044. // return undefined since we don't need an event listener
  3045. },
  3046. postDispatch: function( event ) {
  3047. // If form was submitted by the user, bubble the event up the tree
  3048. if ( event._submit_bubble ) {
  3049. delete event._submit_bubble;
  3050. if ( this.parentNode && !event.isTrigger ) {
  3051. jQuery.event.simulate( "submit", this.parentNode, event, true );
  3052. }
  3053. }
  3054. },
  3055. teardown: function() {
  3056. // Only need this for delegated form submit events
  3057. if ( jQuery.nodeName( this, "form" ) ) {
  3058. return false;
  3059. }
  3060. // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
  3061. jQuery.event.remove( this, "._submit" );
  3062. }
  3063. };
  3064. }
  3065. // IE change delegation and checkbox/radio fix
  3066. if ( !jQuery.support.changeBubbles ) {
  3067. jQuery.event.special.change = {
  3068. setup: function() {
  3069. if ( rformElems.test( this.nodeName ) ) {
  3070. // IE doesn't fire change on a check/radio until blur; trigger it on click
  3071. // after a propertychange. Eat the blur-change in special.change.handle.
  3072. // This still fires onchange a second time for check/radio after blur.
  3073. if ( this.type === "checkbox" || this.type === "radio" ) {
  3074. jQuery.event.add( this, "propertychange._change", function( event ) {
  3075. if ( event.originalEvent.propertyName === "checked" ) {
  3076. this._just_changed = true;
  3077. }
  3078. });
  3079. jQuery.event.add( this, "click._change", function( event ) {
  3080. if ( this._just_changed && !event.isTrigger ) {
  3081. this._just_changed = false;
  3082. jQuery.event.simulate( "change", this, event, true );
  3083. }
  3084. });
  3085. }
  3086. return false;
  3087. }
  3088. // Delegated event; lazy-add a change handler on descendant inputs
  3089. jQuery.event.add( this, "beforeactivate._change", function( e ) {
  3090. var elem = e.target;
  3091. if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
  3092. jQuery.event.add( elem, "change._change", function( event ) {
  3093. if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
  3094. jQuery.event.simulate( "change", this.parentNode, event, true );
  3095. }
  3096. });
  3097. elem._change_attached = true;
  3098. }
  3099. });
  3100. },
  3101. handle: function( event ) {
  3102. var elem = event.target;
  3103. // Swallow native change events from checkbox/radio, we already triggered them above
  3104. if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
  3105. return event.handleObj.handler.apply( this, arguments );
  3106. }
  3107. },
  3108. teardown: function() {
  3109. jQuery.event.remove( this, "._change" );
  3110. return rformElems.test( this.nodeName );
  3111. }
  3112. };
  3113. }
  3114. // Create "bubbling" focus and blur events
  3115. if ( !jQuery.support.focusinBubbles ) {
  3116. jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
  3117. // Attach a single capturing handler while someone wants focusin/focusout
  3118. var attaches = 0,
  3119. handler = function( event ) {
  3120. jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
  3121. };
  3122. jQuery.event.special[ fix ] = {
  3123. setup: function() {
  3124. if ( attaches++ === 0 ) {
  3125. document.addEventListener( orig, handler, true );
  3126. }
  3127. },
  3128. teardown: function() {
  3129. if ( --attaches === 0 ) {
  3130. document.removeEventListener( orig, handler, true );
  3131. }
  3132. }
  3133. };
  3134. });
  3135. }
  3136. jQuery.fn.extend({
  3137. on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
  3138. var origFn, type;
  3139. // Types can be a map of types/handlers
  3140. if ( typeof types === "object" ) {
  3141. // ( types-Object, selector, data )
  3142. if ( typeof selector !== "string" ) { // && selector != null
  3143. // ( types-Object, data )
  3144. data = data || selector;
  3145. selector = undefined;
  3146. }
  3147. for ( type in types ) {
  3148. this.on( type, selector, data, types[ type ], one );
  3149. }
  3150. return this;
  3151. }
  3152. if ( data == null && fn == null ) {
  3153. // ( types, fn )
  3154. fn = selector;
  3155. data = selector = undefined;
  3156. } else if ( fn == null ) {
  3157. if ( typeof selector === "string" ) {
  3158. // ( types, selector, fn )
  3159. fn = data;
  3160. data = undefined;
  3161. } else {
  3162. // ( types, data, fn )
  3163. fn = data;
  3164. data = selector;
  3165. selector = undefined;
  3166. }
  3167. }
  3168. if ( fn === false ) {
  3169. fn = returnFalse;
  3170. } else if ( !fn ) {
  3171. return this;
  3172. }
  3173. if ( one === 1 ) {
  3174. origFn = fn;
  3175. fn = function( event ) {
  3176. // Can use an empty set, since event contains the info
  3177. jQuery().off( event );
  3178. return origFn.apply( this, arguments );
  3179. };
  3180. // Use same guid so caller can remove using origFn
  3181. fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
  3182. }
  3183. return this.each( function() {
  3184. jQuery.event.add( this, types, fn, data, selector );
  3185. });
  3186. },
  3187. one: function( types, selector, data, fn ) {
  3188. return this.on( types, selector, data, fn, 1 );
  3189. },
  3190. off: function( types, selector, fn ) {
  3191. if ( types && types.preventDefault && types.handleObj ) {
  3192. // ( event ) dispatched jQuery.Event
  3193. var handleObj = types.handleObj;
  3194. jQuery( types.delegateTarget ).off(
  3195. handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
  3196. handleObj.selector,
  3197. handleObj.handler
  3198. );
  3199. return this;
  3200. }
  3201. if ( typeof types === "object" ) {
  3202. // ( types-object [, selector] )
  3203. for ( var type in types ) {
  3204. this.off( type, selector, types[ type ] );
  3205. }
  3206. return this;
  3207. }
  3208. if ( selector === false || typeof selector === "function" ) {
  3209. // ( types [, fn] )
  3210. fn = selector;
  3211. selector = undefined;
  3212. }
  3213. if ( fn === false ) {
  3214. fn = returnFalse;
  3215. }
  3216. return this.each(function() {
  3217. jQuery.event.remove( this, types, fn, selector );
  3218. });
  3219. },
  3220. bind: function( types, data, fn ) {
  3221. return this.on( types, null, data, fn );
  3222. },
  3223. unbind: function( types, fn ) {
  3224. return this.off( types, null, fn );
  3225. },
  3226. live: function( types, data, fn ) {
  3227. jQuery( this.context ).on( types, this.selector, data, fn );
  3228. return this;
  3229. },
  3230. die: function( types, fn ) {
  3231. jQuery( this.context ).off( types, this.selector || "**", fn );
  3232. return this;
  3233. },
  3234. delegate: function( selector, types, data, fn ) {
  3235. return this.on( types, selector, data, fn );
  3236. },
  3237. undelegate: function( selector, types, fn ) {
  3238. // ( namespace ) or ( selector, types [, fn] )
  3239. return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
  3240. },
  3241. trigger: function( type, data ) {
  3242. return this.each(function() {
  3243. jQuery.event.trigger( type, data, this );
  3244. });
  3245. },
  3246. triggerHandler: function( type, data ) {
  3247. if ( this[0] ) {
  3248. return jQuery.event.trigger( type, data, this[0], true );
  3249. }
  3250. },
  3251. toggle: function( fn ) {
  3252. // Save reference to arguments for access in closure
  3253. var args = arguments,
  3254. guid = fn.guid || jQuery.guid++,
  3255. i = 0,
  3256. toggler = function( event ) {
  3257. // Figure out which function to execute
  3258. var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
  3259. jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
  3260. // Make sure that clicks stop
  3261. event.preventDefault();
  3262. // and execute the function
  3263. return args[ lastToggle ].apply( this, arguments ) || false;
  3264. };
  3265. // link all the functions, so any of them can unbind this click handler
  3266. toggler.guid = guid;
  3267. while ( i < args.length ) {
  3268. args[ i++ ].guid = guid;
  3269. }
  3270. return this.click( toggler );
  3271. },
  3272. hover: function( fnOver, fnOut ) {
  3273. return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
  3274. }
  3275. });
  3276. jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
  3277. "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
  3278. "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
  3279. // Handle event binding
  3280. jQuery.fn[ name ] = function( data, fn ) {
  3281. if ( fn == null ) {
  3282. fn = data;
  3283. data = null;
  3284. }
  3285. return arguments.length > 0 ?
  3286. this.on( name, null, data, fn ) :
  3287. this.trigger( name );
  3288. };
  3289. if ( jQuery.attrFn ) {
  3290. jQuery.attrFn[ name ] = true;
  3291. }
  3292. if ( rkeyEvent.test( name ) ) {
  3293. jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
  3294. }
  3295. if ( rmouseEvent.test( name ) ) {
  3296. jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
  3297. }
  3298. });
  3299. /*!
  3300. * Sizzle CSS Selector Engine
  3301. * Copyright 2011, The Dojo Foundation
  3302. * Released under the MIT, BSD, and GPL Licenses.
  3303. * More information: http://sizzlejs.com/
  3304. */
  3305. (function(){
  3306. var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
  3307. expando = "sizcache" + (Math.random() + '').replace('.', ''),
  3308. done = 0,
  3309. toString = Object.prototype.toString,
  3310. hasDuplicate = false,
  3311. baseHasDuplicate = true,
  3312. rBackslash = /\\/g,
  3313. rReturn = /\r\n/g,
  3314. rNonWord = /\W/;
  3315. // Here we check if the JavaScript engine is using some sort of
  3316. // optimization where it does not always call our comparision
  3317. // function. If that is the case, discard the hasDuplicate value.
  3318. // Thus far that includes Google Chrome.
  3319. [0, 0].sort(function() {
  3320. baseHasDuplicate = false;
  3321. return 0;
  3322. });
  3323. var Sizzle = function( selector, context, results, seed ) {
  3324. results = results || [];
  3325. context = context || document;
  3326. var origContext = context;
  3327. if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
  3328. return [];
  3329. }
  3330. if ( !selector || typeof selector !== "string" ) {
  3331. return results;
  3332. }
  3333. var m, set, checkSet, extra, ret, cur, pop, i,
  3334. prune = true,
  3335. contextXML = Sizzle.isXML( context ),
  3336. parts = [],
  3337. soFar = selector;
  3338. // Reset the position of the chunker regexp (start from head)
  3339. do {
  3340. chunker.exec( "" );
  3341. m = chunker.exec( soFar );
  3342. if ( m ) {
  3343. soFar = m[3];
  3344. parts.push( m[1] );
  3345. if ( m[2] ) {
  3346. extra = m[3];
  3347. break;
  3348. }
  3349. }
  3350. } while ( m );
  3351. if ( parts.length > 1 && origPOS.exec( selector ) ) {
  3352. if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
  3353. set = posProcess( parts[0] + parts[1], context, seed );
  3354. } else {
  3355. set = Expr.relative[ parts[0] ] ?
  3356. [ context ] :
  3357. Sizzle( parts.shift(), context );
  3358. while ( parts.length ) {
  3359. selector = parts.shift();
  3360. if ( Expr.relative[ selector ] ) {
  3361. selector += parts.shift();
  3362. }
  3363. set = posProcess( selector, set, seed );
  3364. }
  3365. }
  3366. } else {
  3367. // Take a shortcut and set the context if the root selector is an ID
  3368. // (but not if it'll be faster if the inner selector is an ID)
  3369. if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
  3370. Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
  3371. ret = Sizzle.find( parts.shift(), context, contextXML );
  3372. context = ret.expr ?
  3373. Sizzle.filter( ret.expr, ret.set )[0] :
  3374. ret.set[0];
  3375. }
  3376. if ( context ) {
  3377. ret = seed ?
  3378. { expr: parts.pop(), set: makeArray(seed) } :
  3379. Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
  3380. set = ret.expr ?
  3381. Sizzle.filter( ret.expr, ret.set ) :
  3382. ret.set;
  3383. if ( parts.length > 0 ) {
  3384. checkSet = makeArray( set );
  3385. } else {
  3386. prune = false;
  3387. }
  3388. while ( parts.length ) {
  3389. cur = parts.pop();
  3390. pop = cur;
  3391. if ( !Expr.relative[ cur ] ) {
  3392. cur = "";
  3393. } else {
  3394. pop = parts.pop();
  3395. }
  3396. if ( pop == null ) {
  3397. pop = context;
  3398. }
  3399. Expr.relative[ cur ]( checkSet, pop, contextXML );
  3400. }
  3401. } else {
  3402. checkSet = parts = [];
  3403. }
  3404. }
  3405. if ( !checkSet ) {
  3406. checkSet = set;
  3407. }
  3408. if ( !checkSet ) {
  3409. Sizzle.error( cur || selector );
  3410. }
  3411. if ( toString.call(checkSet) === "[object Array]" ) {
  3412. if ( !prune ) {
  3413. results.push.apply( results, checkSet );
  3414. } else if ( context && context.nodeType === 1 ) {
  3415. for ( i = 0; checkSet[i] != null; i++ ) {
  3416. if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
  3417. results.push( set[i] );
  3418. }
  3419. }
  3420. } else {
  3421. for ( i = 0; checkSet[i] != null; i++ ) {
  3422. if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
  3423. results.push( set[i] );
  3424. }
  3425. }
  3426. }
  3427. } else {
  3428. makeArray( checkSet, results );
  3429. }
  3430. if ( extra ) {
  3431. Sizzle( extra, origContext, results, seed );
  3432. Sizzle.uniqueSort( results );
  3433. }
  3434. return results;
  3435. };
  3436. Sizzle.uniqueSort = function( results ) {
  3437. if ( sortOrder ) {
  3438. hasDuplicate = baseHasDuplicate;
  3439. results.sort( sortOrder );
  3440. if ( hasDuplicate ) {
  3441. for ( var i = 1; i < results.length; i++ ) {
  3442. if ( results[i] === results[ i - 1 ] ) {
  3443. results.splice( i--, 1 );
  3444. }
  3445. }
  3446. }
  3447. }
  3448. return results;
  3449. };
  3450. Sizzle.matches = function( expr, set ) {
  3451. return Sizzle( expr, null, null, set );
  3452. };
  3453. Sizzle.matchesSelector = function( node, expr ) {
  3454. return Sizzle( expr, null, null, [node] ).length > 0;
  3455. };
  3456. Sizzle.find = function( expr, context, isXML ) {
  3457. var set, i, len, match, type, left;
  3458. if ( !expr ) {
  3459. return [];
  3460. }
  3461. for ( i = 0, len = Expr.order.length; i < len; i++ ) {
  3462. type = Expr.order[i];
  3463. if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
  3464. left = match[1];
  3465. match.splice( 1, 1 );
  3466. if ( left.substr( left.length - 1 ) !== "\\" ) {
  3467. match[1] = (match[1] || "").replace( rBackslash, "" );
  3468. set = Expr.find[ type ]( match, context, isXML );
  3469. if ( set != null ) {
  3470. expr = expr.replace( Expr.match[ type ], "" );
  3471. break;
  3472. }
  3473. }
  3474. }
  3475. }
  3476. if ( !set ) {
  3477. set = typeof context.getElementsByTagName !== "undefined" ?
  3478. context.getElementsByTagName( "*" ) :
  3479. [];
  3480. }
  3481. return { set: set, expr: expr };
  3482. };
  3483. Sizzle.filter = function( expr, set, inplace, not ) {
  3484. var match, anyFound,
  3485. type, found, item, filter, left,
  3486. i, pass,
  3487. old = expr,
  3488. result = [],
  3489. curLoop = set,
  3490. isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
  3491. while ( expr && set.length ) {
  3492. for ( type in Expr.filter ) {
  3493. if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
  3494. filter = Expr.filter[ type ];
  3495. left = match[1];
  3496. anyFound = false;
  3497. match.splice(1,1);
  3498. if ( left.substr( left.length - 1 ) === "\\" ) {
  3499. continue;
  3500. }
  3501. if ( curLoop === result ) {
  3502. result = [];
  3503. }
  3504. if ( Expr.preFilter[ type ] ) {
  3505. match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
  3506. if ( !match ) {
  3507. anyFound = found = true;
  3508. } else if ( match === true ) {
  3509. continue;
  3510. }
  3511. }
  3512. if ( match ) {
  3513. for ( i = 0; (item = curLoop[i]) != null; i++ ) {
  3514. if ( item ) {
  3515. found = filter( item, match, i, curLoop );
  3516. pass = not ^ found;
  3517. if ( inplace && found != null ) {
  3518. if ( pass ) {
  3519. anyFound = true;
  3520. } else {
  3521. curLoop[i] = false;
  3522. }
  3523. } else if ( pass ) {
  3524. result.push( item );
  3525. anyFound = true;
  3526. }
  3527. }
  3528. }
  3529. }
  3530. if ( found !== undefined ) {
  3531. if ( !inplace ) {
  3532. curLoop = result;
  3533. }
  3534. expr = expr.replace( Expr.match[ type ], "" );
  3535. if ( !anyFound ) {
  3536. return [];
  3537. }
  3538. break;
  3539. }
  3540. }
  3541. }
  3542. // Improper expression
  3543. if ( expr === old ) {
  3544. if ( anyFound == null ) {
  3545. Sizzle.error( expr );
  3546. } else {
  3547. break;
  3548. }
  3549. }
  3550. old = expr;
  3551. }
  3552. return curLoop;
  3553. };
  3554. Sizzle.error = function( msg ) {
  3555. throw new Error( "Syntax error, unrecognized expression: " + msg );
  3556. };
  3557. /**
  3558. * Utility function for retreiving the text value of an array of DOM nodes
  3559. * @param {Array|Element} elem
  3560. */
  3561. var getText = Sizzle.getText = function( elem ) {
  3562. var i, node,
  3563. nodeType = elem.nodeType,
  3564. ret = "";
  3565. if ( nodeType ) {
  3566. if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
  3567. // Use textContent || innerText for elements
  3568. if ( typeof elem.textContent === 'string' ) {
  3569. return elem.textContent;
  3570. } else if ( typeof elem.innerText === 'string' ) {
  3571. // Replace IE's carriage returns
  3572. return elem.innerText.replace( rReturn, '' );
  3573. } else {
  3574. // Traverse it's children
  3575. for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
  3576. ret += getText( elem );
  3577. }
  3578. }
  3579. } else if ( nodeType === 3 || nodeType === 4 ) {
  3580. return elem.nodeValue;
  3581. }
  3582. } else {
  3583. // If no nodeType, this is expected to be an array
  3584. for ( i = 0; (node = elem[i]); i++ ) {
  3585. // Do not traverse comment nodes
  3586. if ( node.nodeType !== 8 ) {
  3587. ret += getText( node );
  3588. }
  3589. }
  3590. }
  3591. return ret;
  3592. };
  3593. var Expr = Sizzle.selectors = {
  3594. order: [ "ID", "NAME", "TAG" ],
  3595. match: {
  3596. ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
  3597. CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
  3598. NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
  3599. ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
  3600. TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
  3601. CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
  3602. POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
  3603. PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
  3604. },
  3605. leftMatch: {},
  3606. attrMap: {
  3607. "class": "className",
  3608. "for": "htmlFor"
  3609. },
  3610. attrHandle: {
  3611. href: function( elem ) {
  3612. return elem.getAttribute( "href" );
  3613. },
  3614. type: function( elem ) {
  3615. return elem.getAttribute( "type" );
  3616. }
  3617. },
  3618. relative: {
  3619. "+": function(checkSet, part){
  3620. var isPartStr = typeof part === "string",
  3621. isTag = isPartStr && !rNonWord.test( part ),
  3622. isPartStrNotTag = isPartStr && !isTag;
  3623. if ( isTag ) {
  3624. part = part.toLowerCase();
  3625. }
  3626. for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
  3627. if ( (elem = checkSet[i]) ) {
  3628. while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
  3629. checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
  3630. elem || false :
  3631. elem === part;
  3632. }
  3633. }
  3634. if ( isPartStrNotTag ) {
  3635. Sizzle.filter( part, checkSet, true );
  3636. }
  3637. },
  3638. ">": function( checkSet, part ) {
  3639. var elem,
  3640. isPartStr = typeof part === "string",
  3641. i = 0,
  3642. l = checkSet.length;
  3643. if ( isPartStr && !rNonWord.test( part ) ) {
  3644. part = part.toLowerCase();
  3645. for ( ; i < l; i++ ) {
  3646. elem = checkSet[i];
  3647. if ( elem ) {
  3648. var parent = elem.parentNode;
  3649. checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
  3650. }
  3651. }
  3652. } else {
  3653. for ( ; i < l; i++ ) {
  3654. elem = checkSet[i];
  3655. if ( elem ) {
  3656. checkSet[i] = isPartStr ?
  3657. elem.parentNode :
  3658. elem.parentNode === part;
  3659. }
  3660. }
  3661. if ( isPartStr ) {
  3662. Sizzle.filter( part, checkSet, true );
  3663. }
  3664. }
  3665. },
  3666. "": function(checkSet, part, isXML){
  3667. var nodeCheck,
  3668. doneName = done++,
  3669. checkFn = dirCheck;
  3670. if ( typeof part === "string" && !rNonWord.test( part ) ) {
  3671. part = part.toLowerCase();
  3672. nodeCheck = part;
  3673. checkFn = dirNodeCheck;
  3674. }
  3675. checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
  3676. },
  3677. "~": function( checkSet, part, isXML ) {
  3678. var nodeCheck,
  3679. doneName = done++,
  3680. checkFn = dirCheck;
  3681. if ( typeof part === "string" && !rNonWord.test( part ) ) {
  3682. part = part.toLowerCase();
  3683. nodeCheck = part;
  3684. checkFn = dirNodeCheck;
  3685. }
  3686. checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
  3687. }
  3688. },
  3689. find: {
  3690. ID: function( match, context, isXML ) {
  3691. if ( typeof context.getElementById !== "undefined" && !isXML ) {
  3692. var m = context.getElementById(match[1]);
  3693. // Check parentNode to catch when Blackberry 4.6 returns
  3694. // nodes that are no longer in the document #6963
  3695. return m && m.parentNode ? [m] : [];
  3696. }
  3697. },
  3698. NAME: function( match, context ) {
  3699. if ( typeof context.getElementsByName !== "undefined" ) {
  3700. var ret = [],
  3701. results = context.getElementsByName( match[1] );
  3702. for ( var i = 0, l = results.length; i < l; i++ ) {
  3703. if ( results[i].getAttribute("name") === match[1] ) {
  3704. ret.push( results[i] );
  3705. }
  3706. }
  3707. return ret.length === 0 ? null : ret;
  3708. }
  3709. },
  3710. TAG: function( match, context ) {
  3711. if ( typeof context.getElementsByTagName !== "undefined" ) {
  3712. return context.getElementsByTagName( match[1] );
  3713. }
  3714. }
  3715. },
  3716. preFilter: {
  3717. CLASS: function( match, curLoop, inplace, result, not, isXML ) {
  3718. match = " " + match[1].replace( rBackslash, "" ) + " ";
  3719. if ( isXML ) {
  3720. return match;
  3721. }
  3722. for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
  3723. if ( elem ) {
  3724. if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
  3725. if ( !inplace ) {
  3726. result.push( elem );
  3727. }
  3728. } else if ( inplace ) {
  3729. curLoop[i] = false;
  3730. }
  3731. }
  3732. }
  3733. return false;
  3734. },
  3735. ID: function( match ) {
  3736. return match[1].replace( rBackslash, "" );
  3737. },
  3738. TAG: function( match, curLoop ) {
  3739. return match[1].replace( rBackslash, "" ).toLowerCase();
  3740. },
  3741. CHILD: function( match ) {
  3742. if ( match[1] === "nth" ) {
  3743. if ( !match[2] ) {
  3744. Sizzle.error( match[0] );
  3745. }
  3746. match[2] = match[2].replace(/^\+|\s*/g, '');
  3747. // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
  3748. var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
  3749. match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
  3750. !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
  3751. // calculate the numbers (first)n+(last) including if they are negative
  3752. match[2] = (test[1] + (test[2] || 1)) - 0;
  3753. match[3] = test[3] - 0;
  3754. }
  3755. else if ( match[2] ) {
  3756. Sizzle.error( match[0] );
  3757. }
  3758. // TODO: Move to normal caching system
  3759. match[0] = done++;
  3760. return match;
  3761. },
  3762. ATTR: function( match, curLoop, inplace, result, not, isXML ) {
  3763. var name = match[1] = match[1].replace( rBackslash, "" );
  3764. if ( !isXML && Expr.attrMap[name] ) {
  3765. match[1] = Expr.attrMap[name];
  3766. }
  3767. // Handle if an un-quoted value was used
  3768. match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
  3769. if ( match[2] === "~=" ) {
  3770. match[4] = " " + match[4] + " ";
  3771. }
  3772. return match;
  3773. },
  3774. PSEUDO: function( match, curLoop, inplace, result, not ) {
  3775. if ( match[1] === "not" ) {
  3776. // If we're dealing with a complex expression, or a simple one
  3777. if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
  3778. match[3] = Sizzle(match[3], null, null, curLoop);
  3779. } else {
  3780. var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
  3781. if ( !inplace ) {
  3782. result.push.apply( result, ret );
  3783. }
  3784. return false;
  3785. }
  3786. } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
  3787. return true;
  3788. }
  3789. return match;
  3790. },
  3791. POS: function( match ) {
  3792. match.unshift( true );
  3793. return match;
  3794. }
  3795. },
  3796. filters: {
  3797. enabled: function( elem ) {
  3798. return elem.disabled === false && elem.type !== "hidden";
  3799. },
  3800. disabled: function( elem ) {
  3801. return elem.disabled === true;
  3802. },
  3803. checked: function( elem ) {
  3804. return elem.checked === true;
  3805. },
  3806. selected: function( elem ) {
  3807. // Accessing this property makes selected-by-default
  3808. // options in Safari work properly
  3809. if ( elem.parentNode ) {
  3810. elem.parentNode.selectedIndex;
  3811. }
  3812. return elem.selected === true;
  3813. },
  3814. parent: function( elem ) {
  3815. return !!elem.firstChild;
  3816. },
  3817. empty: function( elem ) {
  3818. return !elem.firstChild;
  3819. },
  3820. has: function( elem, i, match ) {
  3821. return !!Sizzle( match[3], elem ).length;
  3822. },
  3823. header: function( elem ) {
  3824. return (/h\d/i).test( elem.nodeName );
  3825. },
  3826. text: function( elem ) {
  3827. var attr = elem.getAttribute( "type" ), type = elem.type;
  3828. // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
  3829. // use getAttribute instead to test this case
  3830. return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
  3831. },
  3832. radio: function( elem ) {
  3833. return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
  3834. },
  3835. checkbox: function( elem ) {
  3836. return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
  3837. },
  3838. file: function( elem ) {
  3839. return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
  3840. },
  3841. password: function( elem ) {
  3842. return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
  3843. },
  3844. submit: function( elem ) {
  3845. var name = elem.nodeName.toLowerCase();
  3846. return (name === "input" || name === "button") && "submit" === elem.type;
  3847. },
  3848. image: function( elem ) {
  3849. return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
  3850. },
  3851. reset: function( elem ) {
  3852. var name = elem.nodeName.toLowerCase();
  3853. return (name === "input" || name === "button") && "reset" === elem.type;
  3854. },
  3855. button: function( elem ) {
  3856. var name = elem.nodeName.toLowerCase();
  3857. return name === "input" && "button" === elem.type || name === "button";
  3858. },
  3859. input: function( elem ) {
  3860. return (/input|select|textarea|button/i).test( elem.nodeName );
  3861. },
  3862. focus: function( elem ) {
  3863. return elem === elem.ownerDocument.activeElement;
  3864. }
  3865. },
  3866. setFilters: {
  3867. first: function( elem, i ) {
  3868. return i === 0;
  3869. },
  3870. last: function( elem, i, match, array ) {
  3871. return i === array.length - 1;
  3872. },
  3873. even: function( elem, i ) {
  3874. return i % 2 === 0;
  3875. },
  3876. odd: function( elem, i ) {
  3877. return i % 2 === 1;
  3878. },
  3879. lt: function( elem, i, match ) {
  3880. return i < match[3] - 0;
  3881. },
  3882. gt: function( elem, i, match ) {
  3883. return i > match[3] - 0;
  3884. },
  3885. nth: function( elem, i, match ) {
  3886. return match[3] - 0 === i;
  3887. },
  3888. eq: function( elem, i, match ) {
  3889. return match[3] - 0 === i;
  3890. }
  3891. },
  3892. filter: {
  3893. PSEUDO: function( elem, match, i, array ) {
  3894. var name = match[1],
  3895. filter = Expr.filters[ name ];
  3896. if ( filter ) {
  3897. return filter( elem, i, match, array );
  3898. } else if ( name === "contains" ) {
  3899. return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
  3900. } else if ( name === "not" ) {
  3901. var not = match[3];
  3902. for ( var j = 0, l = not.length; j < l; j++ ) {
  3903. if ( not[j] === elem ) {
  3904. return false;
  3905. }
  3906. }
  3907. return true;
  3908. } else {
  3909. Sizzle.error( name );
  3910. }
  3911. },
  3912. CHILD: function( elem, match ) {
  3913. var first, last,
  3914. doneName, parent, cache,
  3915. count, diff,
  3916. type = match[1],
  3917. node = elem;
  3918. switch ( type ) {
  3919. case "only":
  3920. case "first":
  3921. while ( (node = node.previousSibling) ) {
  3922. if ( node.nodeType === 1 ) {
  3923. return false;
  3924. }
  3925. }
  3926. if ( type === "first" ) {
  3927. return true;
  3928. }
  3929. node = elem;
  3930. /* falls through */
  3931. case "last":
  3932. while ( (node = node.nextSibling) ) {
  3933. if ( node.nodeType === 1 ) {
  3934. return false;
  3935. }
  3936. }
  3937. return true;
  3938. case "nth":
  3939. first = match[2];
  3940. last = match[3];
  3941. if ( first === 1 && last === 0 ) {
  3942. return true;
  3943. }
  3944. doneName = match[0];
  3945. parent = elem.parentNode;
  3946. if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
  3947. count = 0;
  3948. for ( node = parent.firstChild; node; node = node.nextSibling ) {
  3949. if ( node.nodeType === 1 ) {
  3950. node.nodeIndex = ++count;
  3951. }
  3952. }
  3953. parent[ expando ] = doneName;
  3954. }
  3955. diff = elem.nodeIndex - last;
  3956. if ( first === 0 ) {
  3957. return diff === 0;
  3958. } else {
  3959. return ( diff % first === 0 && diff / first >= 0 );
  3960. }
  3961. }
  3962. },
  3963. ID: function( elem, match ) {
  3964. return elem.nodeType === 1 && elem.getAttribute("id") === match;
  3965. },
  3966. TAG: function( elem, match ) {
  3967. return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
  3968. },
  3969. CLASS: function( elem, match ) {
  3970. return (" " + (elem.className || elem.getAttribute("class")) + " ")
  3971. .indexOf( match ) > -1;
  3972. },
  3973. ATTR: function( elem, match ) {
  3974. var name = match[1],
  3975. result = Sizzle.attr ?
  3976. Sizzle.attr( elem, name ) :
  3977. Expr.attrHandle[ name ] ?
  3978. Expr.attrHandle[ name ]( elem ) :
  3979. elem[ name ] != null ?
  3980. elem[ name ] :
  3981. elem.getAttribute( name ),
  3982. value = result + "",
  3983. type = match[2],
  3984. check = match[4];
  3985. return result == null ?
  3986. type === "!=" :
  3987. !type && Sizzle.attr ?
  3988. result != null :
  3989. type === "=" ?
  3990. value === check :
  3991. type === "*=" ?
  3992. value.indexOf(check) >= 0 :
  3993. type === "~=" ?
  3994. (" " + value + " ").indexOf(check) >= 0 :
  3995. !check ?
  3996. value && result !== false :
  3997. type === "!=" ?
  3998. value !== check :
  3999. type === "^=" ?
  4000. value.indexOf(check) === 0 :
  4001. type === "$=" ?
  4002. value.substr(value.length - check.length) === check :
  4003. type === "|=" ?
  4004. value === check || value.substr(0, check.length + 1) === check + "-" :
  4005. false;
  4006. },
  4007. POS: function( elem, match, i, array ) {
  4008. var name = match[2],
  4009. filter = Expr.setFilters[ name ];
  4010. if ( filter ) {
  4011. return filter( elem, i, match, array );
  4012. }
  4013. }
  4014. }
  4015. };
  4016. var origPOS = Expr.match.POS,
  4017. fescape = function(all, num){
  4018. return "\\" + (num - 0 + 1);
  4019. };
  4020. for ( var type in Expr.match ) {
  4021. Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
  4022. Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
  4023. }
  4024. // Expose origPOS
  4025. // "global" as in regardless of relation to brackets/parens
  4026. Expr.match.globalPOS = origPOS;
  4027. var makeArray = function( array, results ) {
  4028. array = Array.prototype.slice.call( array, 0 );
  4029. if ( results ) {
  4030. results.push.apply( results, array );
  4031. return results;
  4032. }
  4033. return array;
  4034. };
  4035. // Perform a simple check to determine if the browser is capable of
  4036. // converting a NodeList to an array using builtin methods.
  4037. // Also verifies that the returned array holds DOM nodes
  4038. // (which is not the case in the Blackberry browser)
  4039. try {
  4040. Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
  4041. // Provide a fallback method if it does not work
  4042. } catch( e ) {
  4043. makeArray = function( array, results ) {
  4044. var i = 0,
  4045. ret = results || [];
  4046. if ( toString.call(array) === "[object Array]" ) {
  4047. Array.prototype.push.apply( ret, array );
  4048. } else {
  4049. if ( typeof array.length === "number" ) {
  4050. for ( var l = array.length; i < l; i++ ) {
  4051. ret.push( array[i] );
  4052. }
  4053. } else {
  4054. for ( ; array[i]; i++ ) {
  4055. ret.push( array[i] );
  4056. }
  4057. }
  4058. }
  4059. return ret;
  4060. };
  4061. }
  4062. var sortOrder, siblingCheck;
  4063. if ( document.documentElement.compareDocumentPosition ) {
  4064. sortOrder = function( a, b ) {
  4065. if ( a === b ) {
  4066. hasDuplicate = true;
  4067. return 0;
  4068. }
  4069. if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
  4070. return a.compareDocumentPosition ? -1 : 1;
  4071. }
  4072. return a.compareDocumentPosition(b) & 4 ? -1 : 1;
  4073. };
  4074. } else {
  4075. sortOrder = function( a, b ) {
  4076. // The nodes are identical, we can exit early
  4077. if ( a === b ) {
  4078. hasDuplicate = true;
  4079. return 0;
  4080. // Fallback to using sourceIndex (in IE) if it's available on both nodes
  4081. } else if ( a.sourceIndex && b.sourceIndex ) {
  4082. return a.sourceIndex - b.sourceIndex;
  4083. }
  4084. var al, bl,
  4085. ap = [],
  4086. bp = [],
  4087. aup = a.parentNode,
  4088. bup = b.parentNode,
  4089. cur = aup;
  4090. // If the nodes are siblings (or identical) we can do a quick check
  4091. if ( aup === bup ) {
  4092. return siblingCheck( a, b );
  4093. // If no parents were found then the nodes are disconnected
  4094. } else if ( !aup ) {
  4095. return -1;
  4096. } else if ( !bup ) {
  4097. return 1;
  4098. }
  4099. // Otherwise they're somewhere else in the tree so we need
  4100. // to build up a full list of the parentNodes for comparison
  4101. while ( cur ) {
  4102. ap.unshift( cur );
  4103. cur = cur.parentNode;
  4104. }
  4105. cur = bup;
  4106. while ( cur ) {
  4107. bp.unshift( cur );
  4108. cur = cur.parentNode;
  4109. }
  4110. al = ap.length;
  4111. bl = bp.length;
  4112. // Start walking down the tree looking for a discrepancy
  4113. for ( var i = 0; i < al && i < bl; i++ ) {
  4114. if ( ap[i] !== bp[i] ) {
  4115. return siblingCheck( ap[i], bp[i] );
  4116. }
  4117. }
  4118. // We ended someplace up the tree so do a sibling check
  4119. return i === al ?
  4120. siblingCheck( a, bp[i], -1 ) :
  4121. siblingCheck( ap[i], b, 1 );
  4122. };
  4123. siblingCheck = function( a, b, ret ) {
  4124. if ( a === b ) {
  4125. return ret;
  4126. }
  4127. var cur = a.nextSibling;
  4128. while ( cur ) {
  4129. if ( cur === b ) {
  4130. return -1;
  4131. }
  4132. cur = cur.nextSibling;
  4133. }
  4134. return 1;
  4135. };
  4136. }
  4137. // Check to see if the browser returns elements by name when
  4138. // querying by getElementById (and provide a workaround)
  4139. (function(){
  4140. // We're going to inject a fake input element with a specified name
  4141. var form = document.createElement("div"),
  4142. id = "script" + (new Date()).getTime(),
  4143. root = document.documentElement;
  4144. form.innerHTML = "<a name='" + id + "'/>";
  4145. // Inject it into the root element, check its status, and remove it quickly
  4146. root.insertBefore( form, root.firstChild );
  4147. // The workaround has to do additional checks after a getElementById
  4148. // Which slows things down for other browsers (hence the branching)
  4149. if ( document.getElementById( id ) ) {
  4150. Expr.find.ID = function( match, context, isXML ) {
  4151. if ( typeof context.getElementById !== "undefined" && !isXML ) {
  4152. var m = context.getElementById(match[1]);
  4153. return m ?
  4154. m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
  4155. [m] :
  4156. undefined :
  4157. [];
  4158. }
  4159. };
  4160. Expr.filter.ID = function( elem, match ) {
  4161. var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
  4162. return elem.nodeType === 1 && node && node.nodeValue === match;
  4163. };
  4164. }
  4165. root.removeChild( form );
  4166. // release memory in IE
  4167. root = form = null;
  4168. })();
  4169. (function(){
  4170. // Check to see if the browser returns only elements
  4171. // when doing getElementsByTagName("*")
  4172. // Create a fake element
  4173. var div = document.createElement("div");
  4174. div.appendChild( document.createComment("") );
  4175. // Make sure no comments are found
  4176. if ( div.getElementsByTagName("*").length > 0 ) {
  4177. Expr.find.TAG = function( match, context ) {
  4178. var results = context.getElementsByTagName( match[1] );
  4179. // Filter out possible comments
  4180. if ( match[1] === "*" ) {
  4181. var tmp = [];
  4182. for ( var i = 0; results[i]; i++ ) {
  4183. if ( results[i].nodeType === 1 ) {
  4184. tmp.push( results[i] );
  4185. }
  4186. }
  4187. results = tmp;
  4188. }
  4189. return results;
  4190. };
  4191. }
  4192. // Check to see if an attribute returns normalized href attributes
  4193. div.innerHTML = "<a href='#'></a>";
  4194. if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
  4195. div.firstChild.getAttribute("href") !== "#" ) {
  4196. Expr.attrHandle.href = function( elem ) {
  4197. return elem.getAttribute( "href", 2 );
  4198. };
  4199. }
  4200. // release memory in IE
  4201. div = null;
  4202. })();
  4203. if ( document.querySelectorAll ) {
  4204. (function(){
  4205. var oldSizzle = Sizzle,
  4206. div = document.createElement("div"),
  4207. id = "__sizzle__";
  4208. div.innerHTML = "<p class='TEST'></p>";
  4209. // Safari can't handle uppercase or unicode characters when
  4210. // in quirks mode.
  4211. if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
  4212. return;
  4213. }
  4214. Sizzle = function( query, context, extra, seed ) {
  4215. context = context || document;
  4216. // Only use querySelectorAll on non-XML documents
  4217. // (ID selectors don't work in non-HTML documents)
  4218. if ( !seed && !Sizzle.isXML(context) ) {
  4219. // See if we find a selector to speed up
  4220. var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
  4221. if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
  4222. // Speed-up: Sizzle("TAG")
  4223. if ( match[1] ) {
  4224. return makeArray( context.getElementsByTagName( query ), extra );
  4225. // Speed-up: Sizzle(".CLASS")
  4226. } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
  4227. return makeArray( context.getElementsByClassName( match[2] ), extra );
  4228. }
  4229. }
  4230. if ( context.nodeType === 9 ) {
  4231. // Speed-up: Sizzle("body")
  4232. // The body element only exists once, optimize finding it
  4233. if ( query === "body" && context.body ) {
  4234. return makeArray( [ context.body ], extra );
  4235. // Speed-up: Sizzle("#ID")
  4236. } else if ( match && match[3] ) {
  4237. var elem = context.getElementById( match[3] );
  4238. // Check parentNode to catch when Blackberry 4.6 returns
  4239. // nodes that are no longer in the document #6963
  4240. if ( elem && elem.parentNode ) {
  4241. // Handle the case where IE and Opera return items
  4242. // by name instead of ID
  4243. if ( elem.id === match[3] ) {
  4244. return makeArray( [ elem ], extra );
  4245. }
  4246. } else {
  4247. return makeArray( [], extra );
  4248. }
  4249. }
  4250. try {
  4251. return makeArray( context.querySelectorAll(query), extra );
  4252. } catch(qsaError) {}
  4253. // qSA works strangely on Element-rooted queries
  4254. // We can work around this by specifying an extra ID on the root
  4255. // and working up from there (Thanks to Andrew Dupont for the technique)
  4256. // IE 8 doesn't work on object elements
  4257. } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
  4258. var oldContext = context,
  4259. old = context.getAttribute( "id" ),
  4260. nid = old || id,
  4261. hasParent = context.parentNode,
  4262. relativeHierarchySelector = /^\s*[+~]/.test( query );
  4263. if ( !old ) {
  4264. context.setAttribute( "id", nid );
  4265. } else {
  4266. nid = nid.replace( /'/g, "\\$&" );
  4267. }
  4268. if ( relativeHierarchySelector && hasParent ) {
  4269. context = context.parentNode;
  4270. }
  4271. try {
  4272. if ( !relativeHierarchySelector || hasParent ) {
  4273. return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
  4274. }
  4275. } catch(pseudoError) {
  4276. } finally {
  4277. if ( !old ) {
  4278. oldContext.removeAttribute( "id" );
  4279. }
  4280. }
  4281. }
  4282. }
  4283. return oldSizzle(query, context, extra, seed);
  4284. };
  4285. for ( var prop in oldSizzle ) {
  4286. Sizzle[ prop ] = oldSizzle[ prop ];
  4287. }
  4288. // release memory in IE
  4289. div = null;
  4290. })();
  4291. }
  4292. (function(){
  4293. var html = document.documentElement,
  4294. matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
  4295. if ( matches ) {
  4296. // Check to see if it's possible to do matchesSelector
  4297. // on a disconnected node (IE 9 fails this)
  4298. var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
  4299. pseudoWorks = false;
  4300. try {
  4301. // This should fail with an exception
  4302. // Gecko does not error, returns false instead
  4303. matches.call( document.documentElement, "[test!='']:sizzle" );
  4304. } catch( pseudoError ) {
  4305. pseudoWorks = true;
  4306. }
  4307. Sizzle.matchesSelector = function( node, expr ) {
  4308. // Make sure that attribute selectors are quoted
  4309. expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
  4310. if ( !Sizzle.isXML( node ) ) {
  4311. try {
  4312. if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
  4313. var ret = matches.call( node, expr );
  4314. // IE 9's matchesSelector returns false on disconnected nodes
  4315. if ( ret || !disconnectedMatch ||
  4316. // As well, disconnected nodes are said to be in a document
  4317. // fragment in IE 9, so check for that
  4318. node.document && node.document.nodeType !== 11 ) {
  4319. return ret;
  4320. }
  4321. }
  4322. } catch(e) {}
  4323. }
  4324. return Sizzle(expr, null, null, [node]).length > 0;
  4325. };
  4326. }
  4327. })();
  4328. (function(){
  4329. var div = document.createElement("div");
  4330. div.innerHTML = "<div class='test e'></div><div class='test'></div>";
  4331. // Opera can't find a second classname (in 9.6)
  4332. // Also, make sure that getElementsByClassName actually exists
  4333. if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
  4334. return;
  4335. }
  4336. // Safari caches class attributes, doesn't catch changes (in 3.2)
  4337. div.lastChild.className = "e";
  4338. if ( div.getElementsByClassName("e").length === 1 ) {
  4339. return;
  4340. }
  4341. Expr.order.splice(1, 0, "CLASS");
  4342. Expr.find.CLASS = function( match, context, isXML ) {
  4343. if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
  4344. return context.getElementsByClassName(match[1]);
  4345. }
  4346. };
  4347. // release memory in IE
  4348. div = null;
  4349. })();
  4350. function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
  4351. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  4352. var elem = checkSet[i];
  4353. if ( elem ) {
  4354. var match = false;
  4355. elem = elem[dir];
  4356. while ( elem ) {
  4357. if ( elem[ expando ] === doneName ) {
  4358. match = checkSet[elem.sizset];
  4359. break;
  4360. }
  4361. if ( elem.nodeType === 1 && !isXML ){
  4362. elem[ expando ] = doneName;
  4363. elem.sizset = i;
  4364. }
  4365. if ( elem.nodeName.toLowerCase() === cur ) {
  4366. match = elem;
  4367. break;
  4368. }
  4369. elem = elem[dir];
  4370. }
  4371. checkSet[i] = match;
  4372. }
  4373. }
  4374. }
  4375. function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
  4376. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  4377. var elem = checkSet[i];
  4378. if ( elem ) {
  4379. var match = false;
  4380. elem = elem[dir];
  4381. while ( elem ) {
  4382. if ( elem[ expando ] === doneName ) {
  4383. match = checkSet[elem.sizset];
  4384. break;
  4385. }
  4386. if ( elem.nodeType === 1 ) {
  4387. if ( !isXML ) {
  4388. elem[ expando ] = doneName;
  4389. elem.sizset = i;
  4390. }
  4391. if ( typeof cur !== "string" ) {
  4392. if ( elem === cur ) {
  4393. match = true;
  4394. break;
  4395. }
  4396. } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
  4397. match = elem;
  4398. break;
  4399. }
  4400. }
  4401. elem = elem[dir];
  4402. }
  4403. checkSet[i] = match;
  4404. }
  4405. }
  4406. }
  4407. if ( document.documentElement.contains ) {
  4408. Sizzle.contains = function( a, b ) {
  4409. return a !== b && (a.contains ? a.contains(b) : true);
  4410. };
  4411. } else if ( document.documentElement.compareDocumentPosition ) {
  4412. Sizzle.contains = function( a, b ) {
  4413. return !!(a.compareDocumentPosition(b) & 16);
  4414. };
  4415. } else {
  4416. Sizzle.contains = function() {
  4417. return false;
  4418. };
  4419. }
  4420. Sizzle.isXML = function( elem ) {
  4421. // documentElement is verified for cases where it doesn't yet exist
  4422. // (such as loading iframes in IE - #4833)
  4423. var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
  4424. return documentElement ? documentElement.nodeName !== "HTML" : false;
  4425. };
  4426. var posProcess = function( selector, context, seed ) {
  4427. var match,
  4428. tmpSet = [],
  4429. later = "",
  4430. root = context.nodeType ? [context] : context;
  4431. // Position selectors must be done after the filter
  4432. // And so must :not(positional) so we move all PSEUDOs to the end
  4433. while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
  4434. later += match[0];
  4435. selector = selector.replace( Expr.match.PSEUDO, "" );
  4436. }
  4437. selector = Expr.relative[selector] ? selector + "*" : selector;
  4438. for ( var i = 0, l = root.length; i < l; i++ ) {
  4439. Sizzle( selector, root[i], tmpSet, seed );
  4440. }
  4441. return Sizzle.filter( later, tmpSet );
  4442. };
  4443. // EXPOSE
  4444. // Override sizzle attribute retrieval
  4445. Sizzle.attr = jQuery.attr;
  4446. Sizzle.selectors.attrMap = {};
  4447. jQuery.find = Sizzle;
  4448. jQuery.expr = Sizzle.selectors;
  4449. jQuery.expr[":"] = jQuery.expr.filters;
  4450. jQuery.unique = Sizzle.uniqueSort;
  4451. jQuery.text = Sizzle.getText;
  4452. jQuery.isXMLDoc = Sizzle.isXML;
  4453. jQuery.contains = Sizzle.contains;
  4454. })();
  4455. var runtil = /Until$/,
  4456. rparentsprev = /^(?:parents|prevUntil|prevAll)/,
  4457. // Note: This RegExp should be improved, or likely pulled from Sizzle
  4458. rmultiselector = /,/,
  4459. isSimple = /^.[^:#\[\.,]*$/,
  4460. slice = Array.prototype.slice,
  4461. POS = jQuery.expr.match.globalPOS,
  4462. // methods guaranteed to produce a unique set when starting from a unique set
  4463. guaranteedUnique = {
  4464. children: true,
  4465. contents: true,
  4466. next: true,
  4467. prev: true
  4468. };
  4469. jQuery.fn.extend({
  4470. find: function( selector ) {
  4471. var self = this,
  4472. i, l;
  4473. if ( typeof selector !== "string" ) {
  4474. return jQuery( selector ).filter(function() {
  4475. for ( i = 0, l = self.length; i < l; i++ ) {
  4476. if ( jQuery.contains( self[ i ], this ) ) {
  4477. return true;
  4478. }
  4479. }
  4480. });
  4481. }
  4482. var ret = this.pushStack( "", "find", selector ),
  4483. length, n, r;
  4484. for ( i = 0, l = this.length; i < l; i++ ) {
  4485. length = ret.length;
  4486. jQuery.find( selector, this[i], ret );
  4487. if ( i > 0 ) {
  4488. // Make sure that the results are unique
  4489. for ( n = length; n < ret.length; n++ ) {
  4490. for ( r = 0; r < length; r++ ) {
  4491. if ( ret[r] === ret[n] ) {
  4492. ret.splice(n--, 1);
  4493. break;
  4494. }
  4495. }
  4496. }
  4497. }
  4498. }
  4499. return ret;
  4500. },
  4501. has: function( target ) {
  4502. var targets = jQuery( target );
  4503. return this.filter(function() {
  4504. for ( var i = 0, l = targets.length; i < l; i++ ) {
  4505. if ( jQuery.contains( this, targets[i] ) ) {
  4506. return true;
  4507. }
  4508. }
  4509. });
  4510. },
  4511. not: function( selector ) {
  4512. return this.pushStack( winnow(this, selector, false), "not", selector);
  4513. },
  4514. filter: function( selector ) {
  4515. return this.pushStack( winnow(this, selector, true), "filter", selector );
  4516. },
  4517. is: function( selector ) {
  4518. return !!selector && (
  4519. typeof selector === "string" ?
  4520. // If this is a positional selector, check membership in the returned set
  4521. // so $("p:first").is("p:last") won't return true for a doc with two "p".
  4522. POS.test( selector ) ?
  4523. jQuery( selector, this.context ).index( this[0] ) >= 0 :
  4524. jQuery.filter( selector, this ).length > 0 :
  4525. this.filter( selector ).length > 0 );
  4526. },
  4527. closest: function( selectors, context ) {
  4528. var ret = [], i, l, cur = this[0];
  4529. // Array (deprecated as of jQuery 1.7)
  4530. if ( jQuery.isArray( selectors ) ) {
  4531. var level = 1;
  4532. while ( cur && cur.ownerDocument && cur !== context ) {
  4533. for ( i = 0; i < selectors.length; i++ ) {
  4534. if ( jQuery( cur ).is( selectors[ i ] ) ) {
  4535. ret.push({ selector: selectors[ i ], elem: cur, level: level });
  4536. }
  4537. }
  4538. cur = cur.parentNode;
  4539. level++;
  4540. }
  4541. return ret;
  4542. }
  4543. // String
  4544. var pos = POS.test( selectors ) || typeof selectors !== "string" ?
  4545. jQuery( selectors, context || this.context ) :
  4546. 0;
  4547. for ( i = 0, l = this.length; i < l; i++ ) {
  4548. cur = this[i];
  4549. while ( cur ) {
  4550. if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
  4551. ret.push( cur );
  4552. break;
  4553. } else {
  4554. cur = cur.parentNode;
  4555. if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
  4556. break;
  4557. }
  4558. }
  4559. }
  4560. }
  4561. ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
  4562. return this.pushStack( ret, "closest", selectors );
  4563. },
  4564. // Determine the position of an element within
  4565. // the matched set of elements
  4566. index: function( elem ) {
  4567. // No argument, return index in parent
  4568. if ( !elem ) {
  4569. return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
  4570. }
  4571. // index in selector
  4572. if ( typeof elem === "string" ) {
  4573. return jQuery.inArray( this[0], jQuery( elem ) );
  4574. }
  4575. // Locate the position of the desired element
  4576. return jQuery.inArray(
  4577. // If it receives a jQuery object, the first element is used
  4578. elem.jquery ? elem[0] : elem, this );
  4579. },
  4580. add: function( selector, context ) {
  4581. var set = typeof selector === "string" ?
  4582. jQuery( selector, context ) :
  4583. jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
  4584. all = jQuery.merge( this.get(), set );
  4585. return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
  4586. all :
  4587. jQuery.unique( all ) );
  4588. },
  4589. andSelf: function() {
  4590. return this.add( this.prevObject );
  4591. }
  4592. });
  4593. // A painfully simple check to see if an element is disconnected
  4594. // from a document (should be improved, where feasible).
  4595. function isDisconnected( node ) {
  4596. return !node || !node.parentNode || node.parentNode.nodeType === 11;
  4597. }
  4598. jQuery.each({
  4599. parent: function( elem ) {
  4600. var parent = elem.parentNode;
  4601. return parent && parent.nodeType !== 11 ? parent : null;
  4602. },
  4603. parents: function( elem ) {
  4604. return jQuery.dir( elem, "parentNode" );
  4605. },
  4606. parentsUntil: function( elem, i, until ) {
  4607. return jQuery.dir( elem, "parentNode", until );
  4608. },
  4609. next: function( elem ) {
  4610. return jQuery.nth( elem, 2, "nextSibling" );
  4611. },
  4612. prev: function( elem ) {
  4613. return jQuery.nth( elem, 2, "previousSibling" );
  4614. },
  4615. nextAll: function( elem ) {
  4616. return jQuery.dir( elem, "nextSibling" );
  4617. },
  4618. prevAll: function( elem ) {
  4619. return jQuery.dir( elem, "previousSibling" );
  4620. },
  4621. nextUntil: function( elem, i, until ) {
  4622. return jQuery.dir( elem, "nextSibling", until );
  4623. },
  4624. prevUntil: function( elem, i, until ) {
  4625. return jQuery.dir( elem, "previousSibling", until );
  4626. },
  4627. siblings: function( elem ) {
  4628. return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
  4629. },
  4630. children: function( elem ) {
  4631. return jQuery.sibling( elem.firstChild );
  4632. },
  4633. contents: function( elem ) {
  4634. return jQuery.nodeName( elem, "iframe" ) ?
  4635. elem.contentDocument || elem.contentWindow.document :
  4636. jQuery.makeArray( elem.childNodes );
  4637. }
  4638. }, function( name, fn ) {
  4639. jQuery.fn[ name ] = function( until, selector ) {
  4640. var ret = jQuery.map( this, fn, until );
  4641. if ( !runtil.test( name ) ) {
  4642. selector = until;
  4643. }
  4644. if ( selector && typeof selector === "string" ) {
  4645. ret = jQuery.filter( selector, ret );
  4646. }
  4647. ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
  4648. if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
  4649. ret = ret.reverse();
  4650. }
  4651. return this.pushStack( ret, name, slice.call( arguments ).join(",") );
  4652. };
  4653. });
  4654. jQuery.extend({
  4655. filter: function( expr, elems, not ) {
  4656. if ( not ) {
  4657. expr = ":not(" + expr + ")";
  4658. }
  4659. return elems.length === 1 ?
  4660. jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
  4661. jQuery.find.matches(expr, elems);
  4662. },
  4663. dir: function( elem, dir, until ) {
  4664. var matched = [],
  4665. cur = elem[ dir ];
  4666. while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
  4667. if ( cur.nodeType === 1 ) {
  4668. matched.push( cur );
  4669. }
  4670. cur = cur[dir];
  4671. }
  4672. return matched;
  4673. },
  4674. nth: function( cur, result, dir, elem ) {
  4675. result = result || 1;
  4676. var num = 0;
  4677. for ( ; cur; cur = cur[dir] ) {
  4678. if ( cur.nodeType === 1 && ++num === result ) {
  4679. break;
  4680. }
  4681. }
  4682. return cur;
  4683. },
  4684. sibling: function( n, elem ) {
  4685. var r = [];
  4686. for ( ; n; n = n.nextSibling ) {
  4687. if ( n.nodeType === 1 && n !== elem ) {
  4688. r.push( n );
  4689. }
  4690. }
  4691. return r;
  4692. }
  4693. });
  4694. // Implement the identical functionality for filter and not
  4695. function winnow( elements, qualifier, keep ) {
  4696. // Can't pass null or undefined to indexOf in Firefox 4
  4697. // Set to 0 to skip string check
  4698. qualifier = qualifier || 0;
  4699. if ( jQuery.isFunction( qualifier ) ) {
  4700. return jQuery.grep(elements, function( elem, i ) {
  4701. var retVal = !!qualifier.call( elem, i, elem );
  4702. return retVal === keep;
  4703. });
  4704. } else if ( qualifier.nodeType ) {
  4705. return jQuery.grep(elements, function( elem, i ) {
  4706. return ( elem === qualifier ) === keep;
  4707. });
  4708. } else if ( typeof qualifier === "string" ) {
  4709. var filtered = jQuery.grep(elements, function( elem ) {
  4710. return elem.nodeType === 1;
  4711. });
  4712. if ( isSimple.test( qualifier ) ) {
  4713. return jQuery.filter(qualifier, filtered, !keep);
  4714. } else {
  4715. qualifier = jQuery.filter( qualifier, filtered );
  4716. }
  4717. }
  4718. return jQuery.grep(elements, function( elem, i ) {
  4719. return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
  4720. });
  4721. }
  4722. function createSafeFragment( document ) {
  4723. var list = nodeNames.split( "|" ),
  4724. safeFrag = document.createDocumentFragment();
  4725. if ( safeFrag.createElement ) {
  4726. while ( list.length ) {
  4727. safeFrag.createElement(
  4728. list.pop()
  4729. );
  4730. }
  4731. }
  4732. return safeFrag;
  4733. }
  4734. var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
  4735. "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
  4736. rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
  4737. rleadingWhitespace = /^\s+/,
  4738. rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
  4739. rtagName = /<([\w:]+)/,
  4740. rtbody = /<tbody/i,
  4741. rhtml = /<|&#?\w+;/,
  4742. rnoInnerhtml = /<(?:script|style)/i,
  4743. rnocache = /<(?:script|object|embed|option|style)/i,
  4744. rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
  4745. // checked="checked" or checked
  4746. rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
  4747. rscriptType = /\/(java|ecma)script/i,
  4748. rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
  4749. wrapMap = {
  4750. option: [ 1, "<select multiple='multiple'>", "</select>" ],
  4751. legend: [ 1, "<fieldset>", "</fieldset>" ],
  4752. thead: [ 1, "<table>", "</table>" ],
  4753. tr: [ 2, "<table><tbody>", "</tbody></table>" ],
  4754. td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
  4755. col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
  4756. area: [ 1, "<map>", "</map>" ],
  4757. _default: [ 0, "", "" ]
  4758. },
  4759. safeFragment = createSafeFragment( document );
  4760. wrapMap.optgroup = wrapMap.option;
  4761. wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
  4762. wrapMap.th = wrapMap.td;
  4763. // IE can't serialize <link> and <script> tags normally
  4764. if ( !jQuery.support.htmlSerialize ) {
  4765. wrapMap._default = [ 1, "div<div>", "</div>" ];
  4766. }
  4767. jQuery.fn.extend({
  4768. text: function( value ) {
  4769. return jQuery.access( this, function( value ) {
  4770. return value === undefined ?
  4771. jQuery.text( this ) :
  4772. this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
  4773. }, null, value, arguments.length );
  4774. },
  4775. wrapAll: function( html ) {
  4776. if ( jQuery.isFunction( html ) ) {
  4777. return this.each(function(i) {
  4778. jQuery(this).wrapAll( html.call(this, i) );
  4779. });
  4780. }
  4781. if ( this[0] ) {
  4782. // The elements to wrap the target around
  4783. var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
  4784. if ( this[0].parentNode ) {
  4785. wrap.insertBefore( this[0] );
  4786. }
  4787. wrap.map(function() {
  4788. var elem = this;
  4789. while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
  4790. elem = elem.firstChild;
  4791. }
  4792. return elem;
  4793. }).append( this );
  4794. }
  4795. return this;
  4796. },
  4797. wrapInner: function( html ) {
  4798. if ( jQuery.isFunction( html ) ) {
  4799. return this.each(function(i) {
  4800. jQuery(this).wrapInner( html.call(this, i) );
  4801. });
  4802. }
  4803. return this.each(function() {
  4804. var self = jQuery( this ),
  4805. contents = self.contents();
  4806. if ( contents.length ) {
  4807. contents.wrapAll( html );
  4808. } else {
  4809. self.append( html );
  4810. }
  4811. });
  4812. },
  4813. wrap: function( html ) {
  4814. var isFunction = jQuery.isFunction( html );
  4815. return this.each(function(i) {
  4816. jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
  4817. });
  4818. },
  4819. unwrap: function() {
  4820. return this.parent().each(function() {
  4821. if ( !jQuery.nodeName( this, "body" ) ) {
  4822. jQuery( this ).replaceWith( this.childNodes );
  4823. }
  4824. }).end();
  4825. },
  4826. append: function() {
  4827. return this.domManip(arguments, true, function( elem ) {
  4828. if ( this.nodeType === 1 ) {
  4829. this.appendChild( elem );
  4830. }
  4831. });
  4832. },
  4833. prepend: function() {
  4834. return this.domManip(arguments, true, function( elem ) {
  4835. if ( this.nodeType === 1 ) {
  4836. this.insertBefore( elem, this.firstChild );
  4837. }
  4838. });
  4839. },
  4840. before: function() {
  4841. if ( this[0] && this[0].parentNode ) {
  4842. return this.domManip(arguments, false, function( elem ) {
  4843. this.parentNode.insertBefore( elem, this );
  4844. });
  4845. } else if ( arguments.length ) {
  4846. var set = jQuery.clean( arguments );
  4847. set.push.apply( set, this.toArray() );
  4848. return this.pushStack( set, "before", arguments );
  4849. }
  4850. },
  4851. after: function() {
  4852. if ( this[0] && this[0].parentNode ) {
  4853. return this.domManip(arguments, false, function( elem ) {
  4854. this.parentNode.insertBefore( elem, this.nextSibling );
  4855. });
  4856. } else if ( arguments.length ) {
  4857. var set = this.pushStack( this, "after", arguments );
  4858. set.push.apply( set, jQuery.clean(arguments) );
  4859. return set;
  4860. }
  4861. },
  4862. // keepData is for internal use only--do not document
  4863. remove: function( selector, keepData ) {
  4864. for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
  4865. if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
  4866. if ( !keepData && elem.nodeType === 1 ) {
  4867. jQuery.cleanData( elem.getElementsByTagName("*") );
  4868. jQuery.cleanData( [ elem ] );
  4869. }
  4870. if ( elem.parentNode ) {
  4871. elem.parentNode.removeChild( elem );
  4872. }
  4873. }
  4874. }
  4875. return this;
  4876. },
  4877. empty: function() {
  4878. for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
  4879. // Remove element nodes and prevent memory leaks
  4880. if ( elem.nodeType === 1 ) {
  4881. jQuery.cleanData( elem.getElementsByTagName("*") );
  4882. }
  4883. // Remove any remaining nodes
  4884. while ( elem.firstChild ) {
  4885. elem.removeChild( elem.firstChild );
  4886. }
  4887. }
  4888. return this;
  4889. },
  4890. clone: function( dataAndEvents, deepDataAndEvents ) {
  4891. dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
  4892. deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
  4893. return this.map( function () {
  4894. return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
  4895. });
  4896. },
  4897. html: function( value ) {
  4898. return jQuery.access( this, function( value ) {
  4899. var elem = this[0] || {},
  4900. i = 0,
  4901. l = this.length;
  4902. if ( value === undefined ) {
  4903. return elem.nodeType === 1 ?
  4904. elem.innerHTML.replace( rinlinejQuery, "" ) :
  4905. null;
  4906. }
  4907. if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
  4908. ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
  4909. !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
  4910. value = value.replace( rxhtmlTag, "<$1></$2>" );
  4911. try {
  4912. for (; i < l; i++ ) {
  4913. // Remove element nodes and prevent memory leaks
  4914. elem = this[i] || {};
  4915. if ( elem.nodeType === 1 ) {
  4916. jQuery.cleanData( elem.getElementsByTagName( "*" ) );
  4917. elem.innerHTML = value;
  4918. }
  4919. }
  4920. elem = 0;
  4921. // If using innerHTML throws an exception, use the fallback method
  4922. } catch(e) {}
  4923. }
  4924. if ( elem ) {
  4925. this.empty().append( value );
  4926. }
  4927. }, null, value, arguments.length );
  4928. },
  4929. replaceWith: function( value ) {
  4930. if ( this[0] && this[0].parentNode ) {
  4931. // Make sure that the elements are removed from the DOM before they are inserted
  4932. // this can help fix replacing a parent with child elements
  4933. if ( jQuery.isFunction( value ) ) {
  4934. return this.each(function(i) {
  4935. var self = jQuery(this), old = self.html();
  4936. self.replaceWith( value.call( this, i, old ) );
  4937. });
  4938. }
  4939. if ( typeof value !== "string" ) {
  4940. value = jQuery( value ).detach();
  4941. }
  4942. return this.each(function() {
  4943. var next = this.nextSibling,
  4944. parent = this.parentNode;
  4945. jQuery( this ).remove();
  4946. if ( next ) {
  4947. jQuery(next).before( value );
  4948. } else {
  4949. jQuery(parent).append( value );
  4950. }
  4951. });
  4952. } else {
  4953. return this.length ?
  4954. this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
  4955. this;
  4956. }
  4957. },
  4958. detach: function( selector ) {
  4959. return this.remove( selector, true );
  4960. },
  4961. domManip: function( args, table, callback ) {
  4962. var results, first, fragment, parent,
  4963. value = args[0],
  4964. scripts = [];
  4965. // We can't cloneNode fragments that contain checked, in WebKit
  4966. if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
  4967. return this.each(function() {
  4968. jQuery(this).domManip( args, table, callback, true );
  4969. });
  4970. }
  4971. if ( jQuery.isFunction(value) ) {
  4972. return this.each(function(i) {
  4973. var self = jQuery(this);
  4974. args[0] = value.call(this, i, table ? self.html() : undefined);
  4975. self.domManip( args, table, callback );
  4976. });
  4977. }
  4978. if ( this[0] ) {
  4979. parent = value && value.parentNode;
  4980. // If we're in a fragment, just use that instead of building a new one
  4981. if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
  4982. results = { fragment: parent };
  4983. } else {
  4984. results = jQuery.buildFragment( args, this, scripts );
  4985. }
  4986. fragment = results.fragment;
  4987. if ( fragment.childNodes.length === 1 ) {
  4988. first = fragment = fragment.firstChild;
  4989. } else {
  4990. first = fragment.firstChild;
  4991. }
  4992. if ( first ) {
  4993. table = table && jQuery.nodeName( first, "tr" );
  4994. for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
  4995. callback.call(
  4996. table ?
  4997. root(this[i], first) :
  4998. this[i],
  4999. // Make sure that we do not leak memory by inadvertently discarding
  5000. // the original fragment (which might have attached data) instead of
  5001. // using it; in addition, use the original fragment object for the last
  5002. // item instead of first because it can end up being emptied incorrectly
  5003. // in certain situations (Bug #8070).
  5004. // Fragments from the fragment cache must always be cloned and never used
  5005. // in place.
  5006. results.cacheable || ( l > 1 && i < lastIndex ) ?
  5007. jQuery.clone( fragment, true, true ) :
  5008. fragment
  5009. );
  5010. }
  5011. }
  5012. if ( scripts.length ) {
  5013. jQuery.each( scripts, function( i, elem ) {
  5014. if ( elem.src ) {
  5015. jQuery.ajax({
  5016. type: "GET",
  5017. global: false,
  5018. url: elem.src,
  5019. async: false,
  5020. dataType: "script"
  5021. });
  5022. } else {
  5023. jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
  5024. }
  5025. if ( elem.parentNode ) {
  5026. elem.parentNode.removeChild( elem );
  5027. }
  5028. });
  5029. }
  5030. }
  5031. return this;
  5032. }
  5033. });
  5034. function root( elem, cur ) {
  5035. return jQuery.nodeName(elem, "table") ?
  5036. (elem.getElementsByTagName("tbody")[0] ||
  5037. elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
  5038. elem;
  5039. }
  5040. function cloneCopyEvent( src, dest ) {
  5041. if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
  5042. return;
  5043. }
  5044. var type, i, l,
  5045. oldData = jQuery._data( src ),
  5046. curData = jQuery._data( dest, oldData ),
  5047. events = oldData.events;
  5048. if ( events ) {
  5049. delete curData.handle;
  5050. curData.events = {};
  5051. for ( type in events ) {
  5052. for ( i = 0, l = events[ type ].length; i < l; i++ ) {
  5053. jQuery.event.add( dest, type, events[ type ][ i ] );
  5054. }
  5055. }
  5056. }
  5057. // make the cloned public data object a copy from the original
  5058. if ( curData.data ) {
  5059. curData.data = jQuery.extend( {}, curData.data );
  5060. }
  5061. }
  5062. function cloneFixAttributes( src, dest ) {
  5063. var nodeName;
  5064. // We do not need to do anything for non-Elements
  5065. if ( dest.nodeType !== 1 ) {
  5066. return;
  5067. }
  5068. // clearAttributes removes the attributes, which we don't want,
  5069. // but also removes the attachEvent events, which we *do* want
  5070. if ( dest.clearAttributes ) {
  5071. dest.clearAttributes();
  5072. }
  5073. // mergeAttributes, in contrast, only merges back on the
  5074. // original attributes, not the events
  5075. if ( dest.mergeAttributes ) {
  5076. dest.mergeAttributes( src );
  5077. }
  5078. nodeName = dest.nodeName.toLowerCase();
  5079. // IE6-8 fail to clone children inside object elements that use
  5080. // the proprietary classid attribute value (rather than the type
  5081. // attribute) to identify the type of content to display
  5082. if ( nodeName === "object" ) {
  5083. dest.outerHTML = src.outerHTML;
  5084. } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
  5085. // IE6-8 fails to persist the checked state of a cloned checkbox
  5086. // or radio button. Worse, IE6-7 fail to give the cloned element
  5087. // a checked appearance if the defaultChecked value isn't also set
  5088. if ( src.checked ) {
  5089. dest.defaultChecked = dest.checked = src.checked;
  5090. }
  5091. // IE6-7 get confused and end up setting the value of a cloned
  5092. // checkbox/radio button to an empty string instead of "on"
  5093. if ( dest.value !== src.value ) {
  5094. dest.value = src.value;
  5095. }
  5096. // IE6-8 fails to return the selected option to the default selected
  5097. // state when cloning options
  5098. } else if ( nodeName === "option" ) {
  5099. dest.selected = src.defaultSelected;
  5100. // IE6-8 fails to set the defaultValue to the correct value when
  5101. // cloning other types of input fields
  5102. } else if ( nodeName === "input" || nodeName === "textarea" ) {
  5103. dest.defaultValue = src.defaultValue;
  5104. // IE blanks contents when cloning scripts
  5105. } else if ( nodeName === "script" && dest.text !== src.text ) {
  5106. dest.text = src.text;
  5107. }
  5108. // Event data gets referenced instead of copied if the expando
  5109. // gets copied too
  5110. dest.removeAttribute( jQuery.expando );
  5111. // Clear flags for bubbling special change/submit events, they must
  5112. // be reattached when the newly cloned events are first activated
  5113. dest.removeAttribute( "_submit_attached" );
  5114. dest.removeAttribute( "_change_attached" );
  5115. }
  5116. jQuery.buildFragment = function( args, nodes, scripts ) {
  5117. var fragment, cacheable, cacheresults, doc,
  5118. first = args[ 0 ];
  5119. // nodes may contain either an explicit document object,
  5120. // a jQuery collection or context object.
  5121. // If nodes[0] contains a valid object to assign to doc
  5122. if ( nodes && nodes[0] ) {
  5123. doc = nodes[0].ownerDocument || nodes[0];
  5124. }
  5125. // Ensure that an attr object doesn't incorrectly stand in as a document object
  5126. // Chrome and Firefox seem to allow this to occur and will throw exception
  5127. // Fixes #8950
  5128. if ( !doc.createDocumentFragment ) {
  5129. doc = document;
  5130. }
  5131. // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
  5132. // Cloning options loses the selected state, so don't cache them
  5133. // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
  5134. // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
  5135. // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
  5136. if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
  5137. first.charAt(0) === "<" && !rnocache.test( first ) &&
  5138. (jQuery.support.checkClone || !rchecked.test( first )) &&
  5139. (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
  5140. cacheable = true;
  5141. cacheresults = jQuery.fragments[ first ];
  5142. if ( cacheresults && cacheresults !== 1 ) {
  5143. fragment = cacheresults;
  5144. }
  5145. }
  5146. if ( !fragment ) {
  5147. fragment = doc.createDocumentFragment();
  5148. jQuery.clean( args, doc, fragment, scripts );
  5149. }
  5150. if ( cacheable ) {
  5151. jQuery.fragments[ first ] = cacheresults ? fragment : 1;
  5152. }
  5153. return { fragment: fragment, cacheable: cacheable };
  5154. };
  5155. jQuery.fragments = {};
  5156. jQuery.each({
  5157. appendTo: "append",
  5158. prependTo: "prepend",
  5159. insertBefore: "before",
  5160. insertAfter: "after",
  5161. replaceAll: "replaceWith"
  5162. }, function( name, original ) {
  5163. jQuery.fn[ name ] = function( selector ) {
  5164. var ret = [],
  5165. insert = jQuery( selector ),
  5166. parent = this.length === 1 && this[0].parentNode;
  5167. if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
  5168. insert[ original ]( this[0] );
  5169. return this;
  5170. } else {
  5171. for ( var i = 0, l = insert.length; i < l; i++ ) {
  5172. var elems = ( i > 0 ? this.clone(true) : this ).get();
  5173. jQuery( insert[i] )[ original ]( elems );
  5174. ret = ret.concat( elems );
  5175. }
  5176. return this.pushStack( ret, name, insert.selector );
  5177. }
  5178. };
  5179. });
  5180. function getAll( elem ) {
  5181. if ( typeof elem.getElementsByTagName !== "undefined" ) {
  5182. return elem.getElementsByTagName( "*" );
  5183. } else if ( typeof elem.querySelectorAll !== "undefined" ) {
  5184. return elem.querySelectorAll( "*" );
  5185. } else {
  5186. return [];
  5187. }
  5188. }
  5189. // Used in clean, fixes the defaultChecked property
  5190. function fixDefaultChecked( elem ) {
  5191. if ( elem.type === "checkbox" || elem.type === "radio" ) {
  5192. elem.defaultChecked = elem.checked;
  5193. }
  5194. }
  5195. // Finds all inputs and passes them to fixDefaultChecked
  5196. function findInputs( elem ) {
  5197. var nodeName = ( elem.nodeName || "" ).toLowerCase();
  5198. if ( nodeName === "input" ) {
  5199. fixDefaultChecked( elem );
  5200. // Skip scripts, get other children
  5201. } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
  5202. jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
  5203. }
  5204. }
  5205. // Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js
  5206. function shimCloneNode( elem ) {
  5207. var div = document.createElement( "div" );
  5208. safeFragment.appendChild( div );
  5209. div.innerHTML = elem.outerHTML;
  5210. return div.firstChild;
  5211. }
  5212. jQuery.extend({
  5213. clone: function( elem, dataAndEvents, deepDataAndEvents ) {
  5214. var srcElements,
  5215. destElements,
  5216. i,
  5217. // IE<=8 does not properly clone detached, unknown element nodes
  5218. clone = jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ?
  5219. elem.cloneNode( true ) :
  5220. shimCloneNode( elem );
  5221. if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
  5222. (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
  5223. // IE copies events bound via attachEvent when using cloneNode.
  5224. // Calling detachEvent on the clone will also remove the events
  5225. // from the original. In order to get around this, we use some
  5226. // proprietary methods to clear the events. Thanks to MooTools
  5227. // guys for this hotness.
  5228. cloneFixAttributes( elem, clone );
  5229. // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
  5230. srcElements = getAll( elem );
  5231. destElements = getAll( clone );
  5232. // Weird iteration because IE will replace the length property
  5233. // with an element if you are cloning the body and one of the
  5234. // elements on the page has a name or id of "length"
  5235. for ( i = 0; srcElements[i]; ++i ) {
  5236. // Ensure that the destination node is not null; Fixes #9587
  5237. if ( destElements[i] ) {
  5238. cloneFixAttributes( srcElements[i], destElements[i] );
  5239. }
  5240. }
  5241. }
  5242. // Copy the events from the original to the clone
  5243. if ( dataAndEvents ) {
  5244. cloneCopyEvent( elem, clone );
  5245. if ( deepDataAndEvents ) {
  5246. srcElements = getAll( elem );
  5247. destElements = getAll( clone );
  5248. for ( i = 0; srcElements[i]; ++i ) {
  5249. cloneCopyEvent( srcElements[i], destElements[i] );
  5250. }
  5251. }
  5252. }
  5253. srcElements = destElements = null;
  5254. // Return the cloned set
  5255. return clone;
  5256. },
  5257. clean: function( elems, context, fragment, scripts ) {
  5258. var checkScriptType, script, j,
  5259. ret = [];
  5260. context = context || document;
  5261. // !context.createElement fails in IE with an error but returns typeof 'object'
  5262. if ( typeof context.createElement === "undefined" ) {
  5263. context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
  5264. }
  5265. for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
  5266. if ( typeof elem === "number" ) {
  5267. elem += "";
  5268. }
  5269. if ( !elem ) {
  5270. continue;
  5271. }
  5272. // Convert html string into DOM nodes
  5273. if ( typeof elem === "string" ) {
  5274. if ( !rhtml.test( elem ) ) {
  5275. elem = context.createTextNode( elem );
  5276. } else {
  5277. // Fix "XHTML"-style tags in all browsers
  5278. elem = elem.replace(rxhtmlTag, "<$1></$2>");
  5279. // Trim whitespace, otherwise indexOf won't work as expected
  5280. var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
  5281. wrap = wrapMap[ tag ] || wrapMap._default,
  5282. depth = wrap[0],
  5283. div = context.createElement("div"),
  5284. safeChildNodes = safeFragment.childNodes,
  5285. remove;
  5286. // Append wrapper element to unknown element safe doc fragment
  5287. if ( context === document ) {
  5288. // Use the fragment we've already created for this document
  5289. safeFragment.appendChild( div );
  5290. } else {
  5291. // Use a fragment created with the owner document
  5292. createSafeFragment( context ).appendChild( div );
  5293. }
  5294. // Go to html and back, then peel off extra wrappers
  5295. div.innerHTML = wrap[1] + elem + wrap[2];
  5296. // Move to the right depth
  5297. while ( depth-- ) {
  5298. div = div.lastChild;
  5299. }
  5300. // Remove IE's autoinserted <tbody> from table fragments
  5301. if ( !jQuery.support.tbody ) {
  5302. // String was a <table>, *may* have spurious <tbody>
  5303. var hasBody = rtbody.test(elem),
  5304. tbody = tag === "table" && !hasBody ?
  5305. div.firstChild && div.firstChild.childNodes :
  5306. // String was a bare <thead> or <tfoot>
  5307. wrap[1] === "<table>" && !hasBody ?
  5308. div.childNodes :
  5309. [];
  5310. for ( j = tbody.length - 1; j >= 0 ; --j ) {
  5311. if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
  5312. tbody[ j ].parentNode.removeChild( tbody[ j ] );
  5313. }
  5314. }
  5315. }
  5316. // IE completely kills leading whitespace when innerHTML is used
  5317. if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
  5318. div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
  5319. }
  5320. elem = div.childNodes;
  5321. // Clear elements from DocumentFragment (safeFragment or otherwise)
  5322. // to avoid hoarding elements. Fixes #11356
  5323. if ( div ) {
  5324. div.parentNode.removeChild( div );
  5325. // Guard against -1 index exceptions in FF3.6
  5326. if ( safeChildNodes.length > 0 ) {
  5327. remove = safeChildNodes[ safeChildNodes.length - 1 ];
  5328. if ( remove && remove.parentNode ) {
  5329. remove.parentNode.removeChild( remove );
  5330. }
  5331. }
  5332. }
  5333. }
  5334. }
  5335. // Resets defaultChecked for any radios and checkboxes
  5336. // about to be appended to the DOM in IE 6/7 (#8060)
  5337. var len;
  5338. if ( !jQuery.support.appendChecked ) {
  5339. if ( elem[0] && typeof (len = elem.length) === "number" ) {
  5340. for ( j = 0; j < len; j++ ) {
  5341. findInputs( elem[j] );
  5342. }
  5343. } else {
  5344. findInputs( elem );
  5345. }
  5346. }
  5347. if ( elem.nodeType ) {
  5348. ret.push( elem );
  5349. } else {
  5350. ret = jQuery.merge( ret, elem );
  5351. }
  5352. }
  5353. if ( fragment ) {
  5354. checkScriptType = function( elem ) {
  5355. return !elem.type || rscriptType.test( elem.type );
  5356. };
  5357. for ( i = 0; ret[i]; i++ ) {
  5358. script = ret[i];
  5359. if ( scripts && jQuery.nodeName( script, "script" ) && (!script.type || rscriptType.test( script.type )) ) {
  5360. scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script );
  5361. } else {
  5362. if ( script.nodeType === 1 ) {
  5363. var jsTags = jQuery.grep( script.getElementsByTagName( "script" ), checkScriptType );
  5364. ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
  5365. }
  5366. fragment.appendChild( script );
  5367. }
  5368. }
  5369. }
  5370. return ret;
  5371. },
  5372. cleanData: function( elems ) {
  5373. var data, id,
  5374. cache = jQuery.cache,
  5375. special = jQuery.event.special,
  5376. deleteExpando = jQuery.support.deleteExpando;
  5377. for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
  5378. if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
  5379. continue;
  5380. }
  5381. id = elem[ jQuery.expando ];
  5382. if ( id ) {
  5383. data = cache[ id ];
  5384. if ( data && data.events ) {
  5385. for ( var type in data.events ) {
  5386. if ( special[ type ] ) {
  5387. jQuery.event.remove( elem, type );
  5388. // This is a shortcut to avoid jQuery.event.remove's overhead
  5389. } else {
  5390. jQuery.removeEvent( elem, type, data.handle );
  5391. }
  5392. }
  5393. // Null the DOM reference to avoid IE6/7/8 leak (#7054)
  5394. if ( data.handle ) {
  5395. data.handle.elem = null;
  5396. }
  5397. }
  5398. if ( deleteExpando ) {
  5399. delete elem[ jQuery.expando ];
  5400. } else if ( elem.removeAttribute ) {
  5401. elem.removeAttribute( jQuery.expando );
  5402. }
  5403. delete cache[ id ];
  5404. }
  5405. }
  5406. }
  5407. });
  5408. var ralpha = /alpha\([^)]*\)/i,
  5409. ropacity = /opacity=([^)]*)/,
  5410. // fixed for IE9, see #8346
  5411. rupper = /([A-Z]|^ms)/g,
  5412. rnum = /^[\-+]?(?:\d*\.)?\d+$/i,
  5413. rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,
  5414. rrelNum = /^([\-+])=([\-+.\de]+)/,
  5415. rmargin = /^margin/,
  5416. cssShow = { position: "absolute", visibility: "hidden", display: "block" },
  5417. // order is important!
  5418. cssExpand = [ "Top", "Right", "Bottom", "Left" ],
  5419. curCSS,
  5420. getComputedStyle,
  5421. currentStyle;
  5422. jQuery.fn.css = function( name, value ) {
  5423. return jQuery.access( this, function( elem, name, value ) {
  5424. return value !== undefined ?
  5425. jQuery.style( elem, name, value ) :
  5426. jQuery.css( elem, name );
  5427. }, name, value, arguments.length > 1 );
  5428. };
  5429. jQuery.extend({
  5430. // Add in style property hooks for overriding the default
  5431. // behavior of getting and setting a style property
  5432. cssHooks: {
  5433. opacity: {
  5434. get: function( elem, computed ) {
  5435. if ( computed ) {
  5436. // We should always get a number back from opacity
  5437. var ret = curCSS( elem, "opacity" );
  5438. return ret === "" ? "1" : ret;
  5439. } else {
  5440. return elem.style.opacity;
  5441. }
  5442. }
  5443. }
  5444. },
  5445. // Exclude the following css properties to add px
  5446. cssNumber: {
  5447. "fillOpacity": true,
  5448. "fontWeight": true,
  5449. "lineHeight": true,
  5450. "opacity": true,
  5451. "orphans": true,
  5452. "widows": true,
  5453. "zIndex": true,
  5454. "zoom": true
  5455. },
  5456. // Add in properties whose names you wish to fix before
  5457. // setting or getting the value
  5458. cssProps: {
  5459. // normalize float css property
  5460. "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
  5461. },
  5462. // Get and set the style property on a DOM Node
  5463. style: function( elem, name, value, extra ) {
  5464. // Don't set styles on text and comment nodes
  5465. if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
  5466. return;
  5467. }
  5468. // Make sure that we're working with the right name
  5469. var ret, type, origName = jQuery.camelCase( name ),
  5470. style = elem.style, hooks = jQuery.cssHooks[ origName ];
  5471. name = jQuery.cssProps[ origName ] || origName;
  5472. // Check if we're setting a value
  5473. if ( value !== undefined ) {
  5474. type = typeof value;
  5475. // convert relative number strings (+= or -=) to relative numbers. #7345
  5476. if ( type === "string" && (ret = rrelNum.exec( value )) ) {
  5477. value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
  5478. // Fixes bug #9237
  5479. type = "number";
  5480. }
  5481. // Make sure that NaN and null values aren't set. See: #7116
  5482. if ( value == null || type === "number" && isNaN( value ) ) {
  5483. return;
  5484. }
  5485. // If a number was passed in, add 'px' to the (except for certain CSS properties)
  5486. if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
  5487. value += "px";
  5488. }
  5489. // If a hook was provided, use that value, otherwise just set the specified value
  5490. if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
  5491. // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
  5492. // Fixes bug #5509
  5493. try {
  5494. style[ name ] = value;
  5495. } catch(e) {}
  5496. }
  5497. } else {
  5498. // If a hook was provided get the non-computed value from there
  5499. if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
  5500. return ret;
  5501. }
  5502. // Otherwise just get the value from the style object
  5503. return style[ name ];
  5504. }
  5505. },
  5506. css: function( elem, name, extra ) {
  5507. var ret, hooks;
  5508. // Make sure that we're working with the right name
  5509. name = jQuery.camelCase( name );
  5510. hooks = jQuery.cssHooks[ name ];
  5511. name = jQuery.cssProps[ name ] || name;
  5512. // cssFloat needs a special treatment
  5513. if ( name === "cssFloat" ) {
  5514. name = "float";
  5515. }
  5516. // If a hook was provided get the computed value from there
  5517. if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
  5518. return ret;
  5519. // Otherwise, if a way to get the computed value exists, use that
  5520. } else if ( curCSS ) {
  5521. return curCSS( elem, name );
  5522. }
  5523. },
  5524. // A method for quickly swapping in/out CSS properties to get correct calculations
  5525. swap: function( elem, options, callback ) {
  5526. var old = {},
  5527. ret, name;
  5528. // Remember the old values, and insert the new ones
  5529. for ( name in options ) {
  5530. old[ name ] = elem.style[ name ];
  5531. elem.style[ name ] = options[ name ];
  5532. }
  5533. ret = callback.call( elem );
  5534. // Revert the old values
  5535. for ( name in options ) {
  5536. elem.style[ name ] = old[ name ];
  5537. }
  5538. return ret;
  5539. }
  5540. });
  5541. // DEPRECATED in 1.3, Use jQuery.css() instead
  5542. jQuery.curCSS = jQuery.css;
  5543. if ( document.defaultView && document.defaultView.getComputedStyle ) {
  5544. getComputedStyle = function( elem, name ) {
  5545. var ret, defaultView, computedStyle, width,
  5546. style = elem.style;
  5547. name = name.replace( rupper, "-$1" ).toLowerCase();
  5548. if ( (defaultView = elem.ownerDocument.defaultView) &&
  5549. (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
  5550. ret = computedStyle.getPropertyValue( name );
  5551. if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
  5552. ret = jQuery.style( elem, name );
  5553. }
  5554. }
  5555. // A tribute to the "awesome hack by Dean Edwards"
  5556. // WebKit uses "computed value (percentage if specified)" instead of "used value" for margins
  5557. // which is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
  5558. if ( !jQuery.support.pixelMargin && computedStyle && rmargin.test( name ) && rnumnonpx.test( ret ) ) {
  5559. width = style.width;
  5560. style.width = ret;
  5561. ret = computedStyle.width;
  5562. style.width = width;
  5563. }
  5564. return ret;
  5565. };
  5566. }
  5567. if ( document.documentElement.currentStyle ) {
  5568. currentStyle = function( elem, name ) {
  5569. var left, rsLeft, uncomputed,
  5570. ret = elem.currentStyle && elem.currentStyle[ name ],
  5571. style = elem.style;
  5572. // Avoid setting ret to empty string here
  5573. // so we don't default to auto
  5574. if ( ret == null && style && (uncomputed = style[ name ]) ) {
  5575. ret = uncomputed;
  5576. }
  5577. // From the awesome hack by Dean Edwards
  5578. // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
  5579. // If we're not dealing with a regular pixel number
  5580. // but a number that has a weird ending, we need to convert it to pixels
  5581. if ( rnumnonpx.test( ret ) ) {
  5582. // Remember the original values
  5583. left = style.left;
  5584. rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
  5585. // Put in the new values to get a computed value out
  5586. if ( rsLeft ) {
  5587. elem.runtimeStyle.left = elem.currentStyle.left;
  5588. }
  5589. style.left = name === "fontSize" ? "1em" : ret;
  5590. ret = style.pixelLeft + "px";
  5591. // Revert the changed values
  5592. style.left = left;
  5593. if ( rsLeft ) {
  5594. elem.runtimeStyle.left = rsLeft;
  5595. }
  5596. }
  5597. return ret === "" ? "auto" : ret;
  5598. };
  5599. }
  5600. curCSS = getComputedStyle || currentStyle;
  5601. function getWidthOrHeight( elem, name, extra ) {
  5602. // Start with offset property
  5603. var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
  5604. i = name === "width" ? 1 : 0,
  5605. len = 4;
  5606. if ( val > 0 ) {
  5607. if ( extra !== "border" ) {
  5608. for ( ; i < len; i += 2 ) {
  5609. if ( !extra ) {
  5610. val -= parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
  5611. }
  5612. if ( extra === "margin" ) {
  5613. val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;
  5614. } else {
  5615. val -= parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
  5616. }
  5617. }
  5618. }
  5619. return val + "px";
  5620. }
  5621. // Fall back to computed then uncomputed css if necessary
  5622. val = curCSS( elem, name );
  5623. if ( val < 0 || val == null ) {
  5624. val = elem.style[ name ];
  5625. }
  5626. // Computed unit is not pixels. Stop here and return.
  5627. if ( rnumnonpx.test(val) ) {
  5628. return val;
  5629. }
  5630. // Normalize "", auto, and prepare for extra
  5631. val = parseFloat( val ) || 0;
  5632. // Add padding, border, margin
  5633. if ( extra ) {
  5634. for ( ; i < len; i += 2 ) {
  5635. val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
  5636. if ( extra !== "padding" ) {
  5637. val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
  5638. }
  5639. if ( extra === "margin" ) {
  5640. val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;
  5641. }
  5642. }
  5643. }
  5644. return val + "px";
  5645. }
  5646. jQuery.each([ "height", "width" ], function( i, name ) {
  5647. jQuery.cssHooks[ name ] = {
  5648. get: function( elem, computed, extra ) {
  5649. if ( computed ) {
  5650. if ( elem.offsetWidth !== 0 ) {
  5651. return getWidthOrHeight( elem, name, extra );
  5652. } else {
  5653. return jQuery.swap( elem, cssShow, function() {
  5654. return getWidthOrHeight( elem, name, extra );
  5655. });
  5656. }
  5657. }
  5658. },
  5659. set: function( elem, value ) {
  5660. return rnum.test( value ) ?
  5661. value + "px" :
  5662. value;
  5663. }
  5664. };
  5665. });
  5666. if ( !jQuery.support.opacity ) {
  5667. jQuery.cssHooks.opacity = {
  5668. get: function( elem, computed ) {
  5669. // IE uses filters for opacity
  5670. return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
  5671. ( parseFloat( RegExp.$1 ) / 100 ) + "" :
  5672. computed ? "1" : "";
  5673. },
  5674. set: function( elem, value ) {
  5675. var style = elem.style,
  5676. currentStyle = elem.currentStyle,
  5677. opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
  5678. filter = currentStyle && currentStyle.filter || style.filter || "";
  5679. // IE has trouble with opacity if it does not have layout
  5680. // Force it by setting the zoom level
  5681. style.zoom = 1;
  5682. // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
  5683. if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
  5684. // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
  5685. // if "filter:" is present at all, clearType is disabled, we want to avoid this
  5686. // style.removeAttribute is IE Only, but so apparently is this code path...
  5687. style.removeAttribute( "filter" );
  5688. // if there there is no filter style applied in a css rule, we are done
  5689. if ( currentStyle && !currentStyle.filter ) {
  5690. return;
  5691. }
  5692. }
  5693. // otherwise, set new filter values
  5694. style.filter = ralpha.test( filter ) ?
  5695. filter.replace( ralpha, opacity ) :
  5696. filter + " " + opacity;
  5697. }
  5698. };
  5699. }
  5700. jQuery(function() {
  5701. // This hook cannot be added until DOM ready because the support test
  5702. // for it is not run until after DOM ready
  5703. if ( !jQuery.support.reliableMarginRight ) {
  5704. jQuery.cssHooks.marginRight = {
  5705. get: function( elem, computed ) {
  5706. // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
  5707. // Work around by temporarily setting element display to inline-block
  5708. return jQuery.swap( elem, { "display": "inline-block" }, function() {
  5709. if ( computed ) {
  5710. return curCSS( elem, "margin-right" );
  5711. } else {
  5712. return elem.style.marginRight;
  5713. }
  5714. });
  5715. }
  5716. };
  5717. }
  5718. });
  5719. if ( jQuery.expr && jQuery.expr.filters ) {
  5720. jQuery.expr.filters.hidden = function( elem ) {
  5721. var width = elem.offsetWidth,
  5722. height = elem.offsetHeight;
  5723. return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
  5724. };
  5725. jQuery.expr.filters.visible = function( elem ) {
  5726. return !jQuery.expr.filters.hidden( elem );
  5727. };
  5728. }
  5729. // These hooks are used by animate to expand properties
  5730. jQuery.each({
  5731. margin: "",
  5732. padding: "",
  5733. border: "Width"
  5734. }, function( prefix, suffix ) {
  5735. jQuery.cssHooks[ prefix + suffix ] = {
  5736. expand: function( value ) {
  5737. var i,
  5738. // assumes a single number if not a string
  5739. parts = typeof value === "string" ? value.split(" ") : [ value ],
  5740. expanded = {};
  5741. for ( i = 0; i < 4; i++ ) {
  5742. expanded[ prefix + cssExpand[ i ] + suffix ] =
  5743. parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
  5744. }
  5745. return expanded;
  5746. }
  5747. };
  5748. });
  5749. var r20 = /%20/g,
  5750. rbracket = /\[\]$/,
  5751. rCRLF = /\r?\n/g,
  5752. rhash = /#.*$/,
  5753. rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
  5754. rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
  5755. // #7653, #8125, #8152: local protocol detection
  5756. rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
  5757. rnoContent = /^(?:GET|HEAD)$/,
  5758. rprotocol = /^\/\//,
  5759. rquery = /\?/,
  5760. rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
  5761. rselectTextarea = /^(?:select|textarea)/i,
  5762. rspacesAjax = /\s+/,
  5763. rts = /([?&])_=[^&]*/,
  5764. rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
  5765. // Keep a copy of the old load method
  5766. _load = jQuery.fn.load,
  5767. /* Prefilters
  5768. * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
  5769. * 2) These are called:
  5770. * - BEFORE asking for a transport
  5771. * - AFTER param serialization (s.data is a string if s.processData is true)
  5772. * 3) key is the dataType
  5773. * 4) the catchall symbol "*" can be used
  5774. * 5) execution will start with transport dataType and THEN continue down to "*" if needed
  5775. */
  5776. prefilters = {},
  5777. /* Transports bindings
  5778. * 1) key is the dataType
  5779. * 2) the catchall symbol "*" can be used
  5780. * 3) selection will start with transport dataType and THEN go to "*" if needed
  5781. */
  5782. transports = {},
  5783. // Document location
  5784. ajaxLocation,
  5785. // Document location segments
  5786. ajaxLocParts,
  5787. // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
  5788. allTypes = ["*/"] + ["*"];
  5789. // #8138, IE may throw an exception when accessing
  5790. // a field from window.location if document.domain has been set
  5791. try {
  5792. ajaxLocation = location.href;
  5793. } catch( e ) {
  5794. // Use the href attribute of an A element
  5795. // since IE will modify it given document.location
  5796. ajaxLocation = document.createElement( "a" );
  5797. ajaxLocation.href = "";
  5798. ajaxLocation = ajaxLocation.href;
  5799. }
  5800. // Segment location into parts
  5801. ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
  5802. // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
  5803. function addToPrefiltersOrTransports( structure ) {
  5804. // dataTypeExpression is optional and defaults to "*"
  5805. return function( dataTypeExpression, func ) {
  5806. if ( typeof dataTypeExpression !== "string" ) {
  5807. func = dataTypeExpression;
  5808. dataTypeExpression = "*";
  5809. }
  5810. if ( jQuery.isFunction( func ) ) {
  5811. var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
  5812. i = 0,
  5813. length = dataTypes.length,
  5814. dataType,
  5815. list,
  5816. placeBefore;
  5817. // For each dataType in the dataTypeExpression
  5818. for ( ; i < length; i++ ) {
  5819. dataType = dataTypes[ i ];
  5820. // We control if we're asked to add before
  5821. // any existing element
  5822. placeBefore = /^\+/.test( dataType );
  5823. if ( placeBefore ) {
  5824. dataType = dataType.substr( 1 ) || "*";
  5825. }
  5826. list = structure[ dataType ] = structure[ dataType ] || [];
  5827. // then we add to the structure accordingly
  5828. list[ placeBefore ? "unshift" : "push" ]( func );
  5829. }
  5830. }
  5831. };
  5832. }
  5833. // Base inspection function for prefilters and transports
  5834. function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
  5835. dataType /* internal */, inspected /* internal */ ) {
  5836. dataType = dataType || options.dataTypes[ 0 ];
  5837. inspected = inspected || {};
  5838. inspected[ dataType ] = true;
  5839. var list = structure[ dataType ],
  5840. i = 0,
  5841. length = list ? list.length : 0,
  5842. executeOnly = ( structure === prefilters ),
  5843. selection;
  5844. for ( ; i < length && ( executeOnly || !selection ); i++ ) {
  5845. selection = list[ i ]( options, originalOptions, jqXHR );
  5846. // If we got redirected to another dataType
  5847. // we try there if executing only and not done already
  5848. if ( typeof selection === "string" ) {
  5849. if ( !executeOnly || inspected[ selection ] ) {
  5850. selection = undefined;
  5851. } else {
  5852. options.dataTypes.unshift( selection );
  5853. selection = inspectPrefiltersOrTransports(
  5854. structure, options, originalOptions, jqXHR, selection, inspected );
  5855. }
  5856. }
  5857. }
  5858. // If we're only executing or nothing was selected
  5859. // we try the catchall dataType if not done already
  5860. if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
  5861. selection = inspectPrefiltersOrTransports(
  5862. structure, options, originalOptions, jqXHR, "*", inspected );
  5863. }
  5864. // unnecessary when only executing (prefilters)
  5865. // but it'll be ignored by the caller in that case
  5866. return selection;
  5867. }
  5868. // A special extend for ajax options
  5869. // that takes "flat" options (not to be deep extended)
  5870. // Fixes #9887
  5871. function ajaxExtend( target, src ) {
  5872. var key, deep,
  5873. flatOptions = jQuery.ajaxSettings.flatOptions || {};
  5874. for ( key in src ) {
  5875. if ( src[ key ] !== undefined ) {
  5876. ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
  5877. }
  5878. }
  5879. if ( deep ) {
  5880. jQuery.extend( true, target, deep );
  5881. }
  5882. }
  5883. jQuery.fn.extend({
  5884. load: function( url, params, callback ) {
  5885. if ( typeof url !== "string" && _load ) {
  5886. return _load.apply( this, arguments );
  5887. // Don't do a request if no elements are being requested
  5888. } else if ( !this.length ) {
  5889. return this;
  5890. }
  5891. var off = url.indexOf( " " );
  5892. if ( off >= 0 ) {
  5893. var selector = url.slice( off, url.length );
  5894. url = url.slice( 0, off );
  5895. }
  5896. // Default to a GET request
  5897. var type = "GET";
  5898. // If the second parameter was provided
  5899. if ( params ) {
  5900. // If it's a function
  5901. if ( jQuery.isFunction( params ) ) {
  5902. // We assume that it's the callback
  5903. callback = params;
  5904. params = undefined;
  5905. // Otherwise, build a param string
  5906. } else if ( typeof params === "object" ) {
  5907. params = jQuery.param( params, jQuery.ajaxSettings.traditional );
  5908. type = "POST";
  5909. }
  5910. }
  5911. var self = this;
  5912. // Request the remote document
  5913. jQuery.ajax({
  5914. url: url,
  5915. type: type,
  5916. dataType: "html",
  5917. data: params,
  5918. // Complete callback (responseText is used internally)
  5919. complete: function( jqXHR, status, responseText ) {
  5920. // Store the response as specified by the jqXHR object
  5921. responseText = jqXHR.responseText;
  5922. // If successful, inject the HTML into all the matched elements
  5923. if ( jqXHR.isResolved() ) {
  5924. // #4825: Get the actual response in case
  5925. // a dataFilter is present in ajaxSettings
  5926. jqXHR.done(function( r ) {
  5927. responseText = r;
  5928. });
  5929. // See if a selector was specified
  5930. self.html( selector ?
  5931. // Create a dummy div to hold the results
  5932. jQuery("<div>")
  5933. // inject the contents of the document in, removing the scripts
  5934. // to avoid any 'Permission Denied' errors in IE
  5935. .append(responseText.replace(rscript, ""))
  5936. // Locate the specified elements
  5937. .find(selector) :
  5938. // If not, just inject the full result
  5939. responseText );
  5940. }
  5941. if ( callback ) {
  5942. self.each( callback, [ responseText, status, jqXHR ] );
  5943. }
  5944. }
  5945. });
  5946. return this;
  5947. },
  5948. serialize: function() {
  5949. return jQuery.param( this.serializeArray() );
  5950. },
  5951. serializeArray: function() {
  5952. return this.map(function(){
  5953. return this.elements ? jQuery.makeArray( this.elements ) : this;
  5954. })
  5955. .filter(function(){
  5956. return this.name && !this.disabled &&
  5957. ( this.checked || rselectTextarea.test( this.nodeName ) ||
  5958. rinput.test( this.type ) );
  5959. })
  5960. .map(function( i, elem ){
  5961. var val = jQuery( this ).val();
  5962. return val == null ?
  5963. null :
  5964. jQuery.isArray( val ) ?
  5965. jQuery.map( val, function( val, i ){
  5966. return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
  5967. }) :
  5968. { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
  5969. }).get();
  5970. }
  5971. });
  5972. // Attach a bunch of functions for handling common AJAX events
  5973. jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
  5974. jQuery.fn[ o ] = function( f ){
  5975. return this.on( o, f );
  5976. };
  5977. });
  5978. jQuery.each( [ "get", "post" ], function( i, method ) {
  5979. jQuery[ method ] = function( url, data, callback, type ) {
  5980. // shift arguments if data argument was omitted
  5981. if ( jQuery.isFunction( data ) ) {
  5982. type = type || callback;
  5983. callback = data;
  5984. data = undefined;
  5985. }
  5986. return jQuery.ajax({
  5987. type: method,
  5988. url: url,
  5989. data: data,
  5990. success: callback,
  5991. dataType: type
  5992. });
  5993. };
  5994. });
  5995. jQuery.extend({
  5996. getScript: function( url, callback ) {
  5997. return jQuery.get( url, undefined, callback, "script" );
  5998. },
  5999. getJSON: function( url, data, callback ) {
  6000. return jQuery.get( url, data, callback, "json" );
  6001. },
  6002. // Creates a full fledged settings object into target
  6003. // with both ajaxSettings and settings fields.
  6004. // If target is omitted, writes into ajaxSettings.
  6005. ajaxSetup: function( target, settings ) {
  6006. if ( settings ) {
  6007. // Building a settings object
  6008. ajaxExtend( target, jQuery.ajaxSettings );
  6009. } else {
  6010. // Extending ajaxSettings
  6011. settings = target;
  6012. target = jQuery.ajaxSettings;
  6013. }
  6014. ajaxExtend( target, settings );
  6015. return target;
  6016. },
  6017. ajaxSettings: {
  6018. url: ajaxLocation,
  6019. isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
  6020. global: true,
  6021. type: "GET",
  6022. contentType: "application/x-www-form-urlencoded; charset=UTF-8",
  6023. processData: true,
  6024. async: true,
  6025. /*
  6026. timeout: 0,
  6027. data: null,
  6028. dataType: null,
  6029. username: null,
  6030. password: null,
  6031. cache: null,
  6032. traditional: false,
  6033. headers: {},
  6034. */
  6035. accepts: {
  6036. xml: "application/xml, text/xml",
  6037. html: "text/html",
  6038. text: "text/plain",
  6039. json: "application/json, text/javascript",
  6040. "*": allTypes
  6041. },
  6042. contents: {
  6043. xml: /xml/,
  6044. html: /html/,
  6045. json: /json/
  6046. },
  6047. responseFields: {
  6048. xml: "responseXML",
  6049. text: "responseText"
  6050. },
  6051. // List of data converters
  6052. // 1) key format is "source_type destination_type" (a single space in-between)
  6053. // 2) the catchall symbol "*" can be used for source_type
  6054. converters: {
  6055. // Convert anything to text
  6056. "* text": window.String,
  6057. // Text to html (true = no transformation)
  6058. "text html": true,
  6059. // Evaluate text as a json expression
  6060. "text json": jQuery.parseJSON,
  6061. // Parse text as xml
  6062. "text xml": jQuery.parseXML
  6063. },
  6064. // For options that shouldn't be deep extended:
  6065. // you can add your own custom options here if
  6066. // and when you create one that shouldn't be
  6067. // deep extended (see ajaxExtend)
  6068. flatOptions: {
  6069. context: true,
  6070. url: true
  6071. }
  6072. },
  6073. ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
  6074. ajaxTransport: addToPrefiltersOrTransports( transports ),
  6075. // Main method
  6076. ajax: function( url, options ) {
  6077. // If url is an object, simulate pre-1.5 signature
  6078. if ( typeof url === "object" ) {
  6079. options = url;
  6080. url = undefined;
  6081. }
  6082. // Force options to be an object
  6083. options = options || {};
  6084. var // Create the final options object
  6085. s = jQuery.ajaxSetup( {}, options ),
  6086. // Callbacks context
  6087. callbackContext = s.context || s,
  6088. // Context for global events
  6089. // It's the callbackContext if one was provided in the options
  6090. // and if it's a DOM node or a jQuery collection
  6091. globalEventContext = callbackContext !== s &&
  6092. ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
  6093. jQuery( callbackContext ) : jQuery.event,
  6094. // Deferreds
  6095. deferred = jQuery.Deferred(),
  6096. completeDeferred = jQuery.Callbacks( "once memory" ),
  6097. // Status-dependent callbacks
  6098. statusCode = s.statusCode || {},
  6099. // ifModified key
  6100. ifModifiedKey,
  6101. // Headers (they are sent all at once)
  6102. requestHeaders = {},
  6103. requestHeadersNames = {},
  6104. // Response headers
  6105. responseHeadersString,
  6106. responseHeaders,
  6107. // transport
  6108. transport,
  6109. // timeout handle
  6110. timeoutTimer,
  6111. // Cross-domain detection vars
  6112. parts,
  6113. // The jqXHR state
  6114. state = 0,
  6115. // To know if global events are to be dispatched
  6116. fireGlobals,
  6117. // Loop variable
  6118. i,
  6119. // Fake xhr
  6120. jqXHR = {
  6121. readyState: 0,
  6122. // Caches the header
  6123. setRequestHeader: function( name, value ) {
  6124. if ( !state ) {
  6125. var lname = name.toLowerCase();
  6126. name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
  6127. requestHeaders[ name ] = value;
  6128. }
  6129. return this;
  6130. },
  6131. // Raw string
  6132. getAllResponseHeaders: function() {
  6133. return state === 2 ? responseHeadersString : null;
  6134. },
  6135. // Builds headers hashtable if needed
  6136. getResponseHeader: function( key ) {
  6137. var match;
  6138. if ( state === 2 ) {
  6139. if ( !responseHeaders ) {
  6140. responseHeaders = {};
  6141. while( ( match = rheaders.exec( responseHeadersString ) ) ) {
  6142. responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
  6143. }
  6144. }
  6145. match = responseHeaders[ key.toLowerCase() ];
  6146. }
  6147. return match === undefined ? null : match;
  6148. },
  6149. // Overrides response content-type header
  6150. overrideMimeType: function( type ) {
  6151. if ( !state ) {
  6152. s.mimeType = type;
  6153. }
  6154. return this;
  6155. },
  6156. // Cancel the request
  6157. abort: function( statusText ) {
  6158. statusText = statusText || "abort";
  6159. if ( transport ) {
  6160. transport.abort( statusText );
  6161. }
  6162. done( 0, statusText );
  6163. return this;
  6164. }
  6165. };
  6166. // Callback for when everything is done
  6167. // It is defined here because jslint complains if it is declared
  6168. // at the end of the function (which would be more logical and readable)
  6169. function done( status, nativeStatusText, responses, headers ) {
  6170. // Called once
  6171. if ( state === 2 ) {
  6172. return;
  6173. }
  6174. // State is "done" now
  6175. state = 2;
  6176. // Clear timeout if it exists
  6177. if ( timeoutTimer ) {
  6178. clearTimeout( timeoutTimer );
  6179. }
  6180. // Dereference transport for early garbage collection
  6181. // (no matter how long the jqXHR object will be used)
  6182. transport = undefined;
  6183. // Cache response headers
  6184. responseHeadersString = headers || "";
  6185. // Set readyState
  6186. jqXHR.readyState = status > 0 ? 4 : 0;
  6187. var isSuccess,
  6188. success,
  6189. error,
  6190. statusText = nativeStatusText,
  6191. response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
  6192. lastModified,
  6193. etag;
  6194. // If successful, handle type chaining
  6195. if ( status >= 200 && status < 300 || status === 304 ) {
  6196. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  6197. if ( s.ifModified ) {
  6198. if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
  6199. jQuery.lastModified[ ifModifiedKey ] = lastModified;
  6200. }
  6201. if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
  6202. jQuery.etag[ ifModifiedKey ] = etag;
  6203. }
  6204. }
  6205. // If not modified
  6206. if ( status === 304 ) {
  6207. statusText = "notmodified";
  6208. isSuccess = true;
  6209. // If we have data
  6210. } else {
  6211. try {
  6212. success = ajaxConvert( s, response );
  6213. statusText = "success";
  6214. isSuccess = true;
  6215. } catch(e) {
  6216. // We have a parsererror
  6217. statusText = "parsererror";
  6218. error = e;
  6219. }
  6220. }
  6221. } else {
  6222. // We extract error from statusText
  6223. // then normalize statusText and status for non-aborts
  6224. error = statusText;
  6225. if ( !statusText || status ) {
  6226. statusText = "error";
  6227. if ( status < 0 ) {
  6228. status = 0;
  6229. }
  6230. }
  6231. }
  6232. // Set data for the fake xhr object
  6233. jqXHR.status = status;
  6234. jqXHR.statusText = "" + ( nativeStatusText || statusText );
  6235. // Success/Error
  6236. if ( isSuccess ) {
  6237. deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
  6238. } else {
  6239. deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
  6240. }
  6241. // Status-dependent callbacks
  6242. jqXHR.statusCode( statusCode );
  6243. statusCode = undefined;
  6244. if ( fireGlobals ) {
  6245. globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
  6246. [ jqXHR, s, isSuccess ? success : error ] );
  6247. }
  6248. // Complete
  6249. completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
  6250. if ( fireGlobals ) {
  6251. globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
  6252. // Handle the global AJAX counter
  6253. if ( !( --jQuery.active ) ) {
  6254. jQuery.event.trigger( "ajaxStop" );
  6255. }
  6256. }
  6257. }
  6258. // Attach deferreds
  6259. deferred.promise( jqXHR );
  6260. jqXHR.success = jqXHR.done;
  6261. jqXHR.error = jqXHR.fail;
  6262. jqXHR.complete = completeDeferred.add;
  6263. // Status-dependent callbacks
  6264. jqXHR.statusCode = function( map ) {
  6265. if ( map ) {
  6266. var tmp;
  6267. if ( state < 2 ) {
  6268. for ( tmp in map ) {
  6269. statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
  6270. }
  6271. } else {
  6272. tmp = map[ jqXHR.status ];
  6273. jqXHR.then( tmp, tmp );
  6274. }
  6275. }
  6276. return this;
  6277. };
  6278. // Remove hash character (#7531: and string promotion)
  6279. // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
  6280. // We also use the url parameter if available
  6281. s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
  6282. // Extract dataTypes list
  6283. s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
  6284. // Determine if a cross-domain request is in order
  6285. if ( s.crossDomain == null ) {
  6286. parts = rurl.exec( s.url.toLowerCase() );
  6287. s.crossDomain = !!( parts &&
  6288. ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
  6289. ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
  6290. ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
  6291. );
  6292. }
  6293. // Convert data if not already a string
  6294. if ( s.data && s.processData && typeof s.data !== "string" ) {
  6295. s.data = jQuery.param( s.data, s.traditional );
  6296. }
  6297. // Apply prefilters
  6298. inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
  6299. // If request was aborted inside a prefilter, stop there
  6300. if ( state === 2 ) {
  6301. return false;
  6302. }
  6303. // We can fire global events as of now if asked to
  6304. fireGlobals = s.global;
  6305. // Uppercase the type
  6306. s.type = s.type.toUpperCase();
  6307. // Determine if request has content
  6308. s.hasContent = !rnoContent.test( s.type );
  6309. // Watch for a new set of requests
  6310. if ( fireGlobals && jQuery.active++ === 0 ) {
  6311. jQuery.event.trigger( "ajaxStart" );
  6312. }
  6313. // More options handling for requests with no content
  6314. if ( !s.hasContent ) {
  6315. // If data is available, append data to url
  6316. if ( s.data ) {
  6317. s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
  6318. // #9682: remove data so that it's not used in an eventual retry
  6319. delete s.data;
  6320. }
  6321. // Get ifModifiedKey before adding the anti-cache parameter
  6322. ifModifiedKey = s.url;
  6323. // Add anti-cache in url if needed
  6324. if ( s.cache === false ) {
  6325. var ts = jQuery.now(),
  6326. // try replacing _= if it is there
  6327. ret = s.url.replace( rts, "$1_=" + ts );
  6328. // if nothing was replaced, add timestamp to the end
  6329. s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
  6330. }
  6331. }
  6332. // Set the correct header, if data is being sent
  6333. if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
  6334. jqXHR.setRequestHeader( "Content-Type", s.contentType );
  6335. }
  6336. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  6337. if ( s.ifModified ) {
  6338. ifModifiedKey = ifModifiedKey || s.url;
  6339. if ( jQuery.lastModified[ ifModifiedKey ] ) {
  6340. jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
  6341. }
  6342. if ( jQuery.etag[ ifModifiedKey ] ) {
  6343. jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
  6344. }
  6345. }
  6346. // Set the Accepts header for the server, depending on the dataType
  6347. jqXHR.setRequestHeader(
  6348. "Accept",
  6349. s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
  6350. s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
  6351. s.accepts[ "*" ]
  6352. );
  6353. // Check for headers option
  6354. for ( i in s.headers ) {
  6355. jqXHR.setRequestHeader( i, s.headers[ i ] );
  6356. }
  6357. // Allow custom headers/mimetypes and early abort
  6358. if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
  6359. // Abort if not done already
  6360. jqXHR.abort();
  6361. return false;
  6362. }
  6363. // Install callbacks on deferreds
  6364. for ( i in { success: 1, error: 1, complete: 1 } ) {
  6365. jqXHR[ i ]( s[ i ] );
  6366. }
  6367. // Get transport
  6368. transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
  6369. // If no transport, we auto-abort
  6370. if ( !transport ) {
  6371. done( -1, "No Transport" );
  6372. } else {
  6373. jqXHR.readyState = 1;
  6374. // Send global event
  6375. if ( fireGlobals ) {
  6376. globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
  6377. }
  6378. // Timeout
  6379. if ( s.async && s.timeout > 0 ) {
  6380. timeoutTimer = setTimeout( function(){
  6381. jqXHR.abort( "timeout" );
  6382. }, s.timeout );
  6383. }
  6384. try {
  6385. state = 1;
  6386. transport.send( requestHeaders, done );
  6387. } catch (e) {
  6388. // Propagate exception as error if not done
  6389. if ( state < 2 ) {
  6390. done( -1, e );
  6391. // Simply rethrow otherwise
  6392. } else {
  6393. throw e;
  6394. }
  6395. }
  6396. }
  6397. return jqXHR;
  6398. },
  6399. // Serialize an array of form elements or a set of
  6400. // key/values into a query string
  6401. param: function( a, traditional ) {
  6402. var s = [],
  6403. add = function( key, value ) {
  6404. // If value is a function, invoke it and return its value
  6405. value = jQuery.isFunction( value ) ? value() : value;
  6406. s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
  6407. };
  6408. // Set traditional to true for jQuery <= 1.3.2 behavior.
  6409. if ( traditional === undefined ) {
  6410. traditional = jQuery.ajaxSettings.traditional;
  6411. }
  6412. // If an array was passed in, assume that it is an array of form elements.
  6413. if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
  6414. // Serialize the form elements
  6415. jQuery.each( a, function() {
  6416. add( this.name, this.value );
  6417. });
  6418. } else {
  6419. // If traditional, encode the "old" way (the way 1.3.2 or older
  6420. // did it), otherwise encode params recursively.
  6421. for ( var prefix in a ) {
  6422. buildParams( prefix, a[ prefix ], traditional, add );
  6423. }
  6424. }
  6425. // Return the resulting serialization
  6426. return s.join( "&" ).replace( r20, "+" );
  6427. }
  6428. });
  6429. function buildParams( prefix, obj, traditional, add ) {
  6430. if ( jQuery.isArray( obj ) ) {
  6431. // Serialize array item.
  6432. jQuery.each( obj, function( i, v ) {
  6433. if ( traditional || rbracket.test( prefix ) ) {
  6434. // Treat each array item as a scalar.
  6435. add( prefix, v );
  6436. } else {
  6437. // If array item is non-scalar (array or object), encode its
  6438. // numeric index to resolve deserialization ambiguity issues.
  6439. // Note that rack (as of 1.0.0) can't currently deserialize
  6440. // nested arrays properly, and attempting to do so may cause
  6441. // a server error. Possible fixes are to modify rack's
  6442. // deserialization algorithm or to provide an option or flag
  6443. // to force array serialization to be shallow.
  6444. buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
  6445. }
  6446. });
  6447. } else if ( !traditional && jQuery.type( obj ) === "object" ) {
  6448. // Serialize object item.
  6449. for ( var name in obj ) {
  6450. buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
  6451. }
  6452. } else {
  6453. // Serialize scalar item.
  6454. add( prefix, obj );
  6455. }
  6456. }
  6457. // This is still on the jQuery object... for now
  6458. // Want to move this to jQuery.ajax some day
  6459. jQuery.extend({
  6460. // Counter for holding the number of active queries
  6461. active: 0,
  6462. // Last-Modified header cache for next request
  6463. lastModified: {},
  6464. etag: {}
  6465. });
  6466. /* Handles responses to an ajax request:
  6467. * - sets all responseXXX fields accordingly
  6468. * - finds the right dataType (mediates between content-type and expected dataType)
  6469. * - returns the corresponding response
  6470. */
  6471. function ajaxHandleResponses( s, jqXHR, responses ) {
  6472. var contents = s.contents,
  6473. dataTypes = s.dataTypes,
  6474. responseFields = s.responseFields,
  6475. ct,
  6476. type,
  6477. finalDataType,
  6478. firstDataType;
  6479. // Fill responseXXX fields
  6480. for ( type in responseFields ) {
  6481. if ( type in responses ) {
  6482. jqXHR[ responseFields[type] ] = responses[ type ];
  6483. }
  6484. }
  6485. // Remove auto dataType and get content-type in the process
  6486. while( dataTypes[ 0 ] === "*" ) {
  6487. dataTypes.shift();
  6488. if ( ct === undefined ) {
  6489. ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
  6490. }
  6491. }
  6492. // Check if we're dealing with a known content-type
  6493. if ( ct ) {
  6494. for ( type in contents ) {
  6495. if ( contents[ type ] && contents[ type ].test( ct ) ) {
  6496. dataTypes.unshift( type );
  6497. break;
  6498. }
  6499. }
  6500. }
  6501. // Check to see if we have a response for the expected dataType
  6502. if ( dataTypes[ 0 ] in responses ) {
  6503. finalDataType = dataTypes[ 0 ];
  6504. } else {
  6505. // Try convertible dataTypes
  6506. for ( type in responses ) {
  6507. if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
  6508. finalDataType = type;
  6509. break;
  6510. }
  6511. if ( !firstDataType ) {
  6512. firstDataType = type;
  6513. }
  6514. }
  6515. // Or just use first one
  6516. finalDataType = finalDataType || firstDataType;
  6517. }
  6518. // If we found a dataType
  6519. // We add the dataType to the list if needed
  6520. // and return the corresponding response
  6521. if ( finalDataType ) {
  6522. if ( finalDataType !== dataTypes[ 0 ] ) {
  6523. dataTypes.unshift( finalDataType );
  6524. }
  6525. return responses[ finalDataType ];
  6526. }
  6527. }
  6528. // Chain conversions given the request and the original response
  6529. function ajaxConvert( s, response ) {
  6530. // Apply the dataFilter if provided
  6531. if ( s.dataFilter ) {
  6532. response = s.dataFilter( response, s.dataType );
  6533. }
  6534. var dataTypes = s.dataTypes,
  6535. converters = {},
  6536. i,
  6537. key,
  6538. length = dataTypes.length,
  6539. tmp,
  6540. // Current and previous dataTypes
  6541. current = dataTypes[ 0 ],
  6542. prev,
  6543. // Conversion expression
  6544. conversion,
  6545. // Conversion function
  6546. conv,
  6547. // Conversion functions (transitive conversion)
  6548. conv1,
  6549. conv2;
  6550. // For each dataType in the chain
  6551. for ( i = 1; i < length; i++ ) {
  6552. // Create converters map
  6553. // with lowercased keys
  6554. if ( i === 1 ) {
  6555. for ( key in s.converters ) {
  6556. if ( typeof key === "string" ) {
  6557. converters[ key.toLowerCase() ] = s.converters[ key ];
  6558. }
  6559. }
  6560. }
  6561. // Get the dataTypes
  6562. prev = current;
  6563. current = dataTypes[ i ];
  6564. // If current is auto dataType, update it to prev
  6565. if ( current === "*" ) {
  6566. current = prev;
  6567. // If no auto and dataTypes are actually different
  6568. } else if ( prev !== "*" && prev !== current ) {
  6569. // Get the converter
  6570. conversion = prev + " " + current;
  6571. conv = converters[ conversion ] || converters[ "* " + current ];
  6572. // If there is no direct converter, search transitively
  6573. if ( !conv ) {
  6574. conv2 = undefined;
  6575. for ( conv1 in converters ) {
  6576. tmp = conv1.split( " " );
  6577. if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
  6578. conv2 = converters[ tmp[1] + " " + current ];
  6579. if ( conv2 ) {
  6580. conv1 = converters[ conv1 ];
  6581. if ( conv1 === true ) {
  6582. conv = conv2;
  6583. } else if ( conv2 === true ) {
  6584. conv = conv1;
  6585. }
  6586. break;
  6587. }
  6588. }
  6589. }
  6590. }
  6591. // If we found no converter, dispatch an error
  6592. if ( !( conv || conv2 ) ) {
  6593. jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
  6594. }
  6595. // If found converter is not an equivalence
  6596. if ( conv !== true ) {
  6597. // Convert with 1 or 2 converters accordingly
  6598. response = conv ? conv( response ) : conv2( conv1(response) );
  6599. }
  6600. }
  6601. }
  6602. return response;
  6603. }
  6604. var jsc = jQuery.now(),
  6605. jsre = /(\=)\?(&|$)|\?\?/i;
  6606. // Default jsonp settings
  6607. jQuery.ajaxSetup({
  6608. jsonp: "callback",
  6609. jsonpCallback: function() {
  6610. return jQuery.expando + "_" + ( jsc++ );
  6611. }
  6612. });
  6613. // Detect, normalize options and install callbacks for jsonp requests
  6614. jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
  6615. var inspectData = ( typeof s.data === "string" ) && /^application\/x\-www\-form\-urlencoded/.test( s.contentType );
  6616. if ( s.dataTypes[ 0 ] === "jsonp" ||
  6617. s.jsonp !== false && ( jsre.test( s.url ) ||
  6618. inspectData && jsre.test( s.data ) ) ) {
  6619. var responseContainer,
  6620. jsonpCallback = s.jsonpCallback =
  6621. jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
  6622. previous = window[ jsonpCallback ],
  6623. url = s.url,
  6624. data = s.data,
  6625. replace = "$1" + jsonpCallback + "$2";
  6626. if ( s.jsonp !== false ) {
  6627. url = url.replace( jsre, replace );
  6628. if ( s.url === url ) {
  6629. if ( inspectData ) {
  6630. data = data.replace( jsre, replace );
  6631. }
  6632. if ( s.data === data ) {
  6633. // Add callback manually
  6634. url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
  6635. }
  6636. }
  6637. }
  6638. s.url = url;
  6639. s.data = data;
  6640. // Install callback
  6641. window[ jsonpCallback ] = function( response ) {
  6642. responseContainer = [ response ];
  6643. };
  6644. // Clean-up function
  6645. jqXHR.always(function() {
  6646. // Set callback back to previous value
  6647. window[ jsonpCallback ] = previous;
  6648. // Call if it was a function and we have a response
  6649. if ( responseContainer && jQuery.isFunction( previous ) ) {
  6650. window[ jsonpCallback ]( responseContainer[ 0 ] );
  6651. }
  6652. });
  6653. // Use data converter to retrieve json after script execution
  6654. s.converters["script json"] = function() {
  6655. if ( !responseContainer ) {
  6656. jQuery.error( jsonpCallback + " was not called" );
  6657. }
  6658. return responseContainer[ 0 ];
  6659. };
  6660. // force json dataType
  6661. s.dataTypes[ 0 ] = "json";
  6662. // Delegate to script
  6663. return "script";
  6664. }
  6665. });
  6666. // Install script dataType
  6667. jQuery.ajaxSetup({
  6668. accepts: {
  6669. script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
  6670. },
  6671. contents: {
  6672. script: /javascript|ecmascript/
  6673. },
  6674. converters: {
  6675. "text script": function( text ) {
  6676. jQuery.globalEval( text );
  6677. return text;
  6678. }
  6679. }
  6680. });
  6681. // Handle cache's special case and global
  6682. jQuery.ajaxPrefilter( "script", function( s ) {
  6683. if ( s.cache === undefined ) {
  6684. s.cache = false;
  6685. }
  6686. if ( s.crossDomain ) {
  6687. s.type = "GET";
  6688. s.global = false;
  6689. }
  6690. });
  6691. // Bind script tag hack transport
  6692. jQuery.ajaxTransport( "script", function(s) {
  6693. // This transport only deals with cross domain requests
  6694. if ( s.crossDomain ) {
  6695. var script,
  6696. head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
  6697. return {
  6698. send: function( _, callback ) {
  6699. script = document.createElement( "script" );
  6700. script.async = "async";
  6701. if ( s.scriptCharset ) {
  6702. script.charset = s.scriptCharset;
  6703. }
  6704. script.src = s.url;
  6705. // Attach handlers for all browsers
  6706. script.onload = script.onreadystatechange = function( _, isAbort ) {
  6707. if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
  6708. // Handle memory leak in IE
  6709. script.onload = script.onreadystatechange = null;
  6710. // Remove the script
  6711. if ( head && script.parentNode ) {
  6712. head.removeChild( script );
  6713. }
  6714. // Dereference the script
  6715. script = undefined;
  6716. // Callback if not abort
  6717. if ( !isAbort ) {
  6718. callback( 200, "success" );
  6719. }
  6720. }
  6721. };
  6722. // Use insertBefore instead of appendChild to circumvent an IE6 bug.
  6723. // This arises when a base node is used (#2709 and #4378).
  6724. head.insertBefore( script, head.firstChild );
  6725. },
  6726. abort: function() {
  6727. if ( script ) {
  6728. script.onload( 0, 1 );
  6729. }
  6730. }
  6731. };
  6732. }
  6733. });
  6734. var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
  6735. xhrOnUnloadAbort = window.ActiveXObject ? function() {
  6736. // Abort all pending requests
  6737. for ( var key in xhrCallbacks ) {
  6738. xhrCallbacks[ key ]( 0, 1 );
  6739. }
  6740. } : false,
  6741. xhrId = 0,
  6742. xhrCallbacks;
  6743. // Functions to create xhrs
  6744. function createStandardXHR() {
  6745. try {
  6746. return new window.XMLHttpRequest();
  6747. } catch( e ) {}
  6748. }
  6749. function createActiveXHR() {
  6750. try {
  6751. return new window.ActiveXObject( "Microsoft.XMLHTTP" );
  6752. } catch( e ) {}
  6753. }
  6754. // Create the request object
  6755. // (This is still attached to ajaxSettings for backward compatibility)
  6756. jQuery.ajaxSettings.xhr = window.ActiveXObject ?
  6757. /* Microsoft failed to properly
  6758. * implement the XMLHttpRequest in IE7 (can't request local files),
  6759. * so we use the ActiveXObject when it is available
  6760. * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
  6761. * we need a fallback.
  6762. */
  6763. function() {
  6764. return !this.isLocal && createStandardXHR() || createActiveXHR();
  6765. } :
  6766. // For all other browsers, use the standard XMLHttpRequest object
  6767. createStandardXHR;
  6768. // Determine support properties
  6769. (function( xhr ) {
  6770. jQuery.extend( jQuery.support, {
  6771. ajax: !!xhr,
  6772. cors: !!xhr && ( "withCredentials" in xhr )
  6773. });
  6774. })( jQuery.ajaxSettings.xhr() );
  6775. // Create transport if the browser can provide an xhr
  6776. if ( jQuery.support.ajax ) {
  6777. jQuery.ajaxTransport(function( s ) {
  6778. // Cross domain only allowed if supported through XMLHttpRequest
  6779. if ( !s.crossDomain || jQuery.support.cors ) {
  6780. var callback;
  6781. return {
  6782. send: function( headers, complete ) {
  6783. // Get a new xhr
  6784. var xhr = s.xhr(),
  6785. handle,
  6786. i;
  6787. // Open the socket
  6788. // Passing null username, generates a login popup on Opera (#2865)
  6789. if ( s.username ) {
  6790. xhr.open( s.type, s.url, s.async, s.username, s.password );
  6791. } else {
  6792. xhr.open( s.type, s.url, s.async );
  6793. }
  6794. // Apply custom fields if provided
  6795. if ( s.xhrFields ) {
  6796. for ( i in s.xhrFields ) {
  6797. xhr[ i ] = s.xhrFields[ i ];
  6798. }
  6799. }
  6800. // Override mime type if needed
  6801. if ( s.mimeType && xhr.overrideMimeType ) {
  6802. xhr.overrideMimeType( s.mimeType );
  6803. }
  6804. // X-Requested-With header
  6805. // For cross-domain requests, seeing as conditions for a preflight are
  6806. // akin to a jigsaw puzzle, we simply never set it to be sure.
  6807. // (it can always be set on a per-request basis or even using ajaxSetup)
  6808. // For same-domain requests, won't change header if already provided.
  6809. if ( !s.crossDomain && !headers["X-Requested-With"] ) {
  6810. headers[ "X-Requested-With" ] = "XMLHttpRequest";
  6811. }
  6812. // Need an extra try/catch for cross domain requests in Firefox 3
  6813. try {
  6814. for ( i in headers ) {
  6815. xhr.setRequestHeader( i, headers[ i ] );
  6816. }
  6817. } catch( _ ) {}
  6818. // Do send the request
  6819. // This may raise an exception which is actually
  6820. // handled in jQuery.ajax (so no try/catch here)
  6821. xhr.send( ( s.hasContent && s.data ) || null );
  6822. // Listener
  6823. callback = function( _, isAbort ) {
  6824. var status,
  6825. statusText,
  6826. responseHeaders,
  6827. responses,
  6828. xml;
  6829. // Firefox throws exceptions when accessing properties
  6830. // of an xhr when a network error occured
  6831. // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
  6832. try {
  6833. // Was never called and is aborted or complete
  6834. if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
  6835. // Only called once
  6836. callback = undefined;
  6837. // Do not keep as active anymore
  6838. if ( handle ) {
  6839. xhr.onreadystatechange = jQuery.noop;
  6840. if ( xhrOnUnloadAbort ) {
  6841. delete xhrCallbacks[ handle ];
  6842. }
  6843. }
  6844. // If it's an abort
  6845. if ( isAbort ) {
  6846. // Abort it manually if needed
  6847. if ( xhr.readyState !== 4 ) {
  6848. xhr.abort();
  6849. }
  6850. } else {
  6851. status = xhr.status;
  6852. responseHeaders = xhr.getAllResponseHeaders();
  6853. responses = {};
  6854. xml = xhr.responseXML;
  6855. // Construct response list
  6856. if ( xml && xml.documentElement /* #4958 */ ) {
  6857. responses.xml = xml;
  6858. }
  6859. // When requesting binary data, IE6-9 will throw an exception
  6860. // on any attempt to access responseText (#11426)
  6861. try {
  6862. responses.text = xhr.responseText;
  6863. } catch( _ ) {
  6864. }
  6865. // Firefox throws an exception when accessing
  6866. // statusText for faulty cross-domain requests
  6867. try {
  6868. statusText = xhr.statusText;
  6869. } catch( e ) {
  6870. // We normalize with Webkit giving an empty statusText
  6871. statusText = "";
  6872. }
  6873. // Filter status for non standard behaviors
  6874. // If the request is local and we have data: assume a success
  6875. // (success with no data won't get notified, that's the best we
  6876. // can do given current implementations)
  6877. if ( !status && s.isLocal && !s.crossDomain ) {
  6878. status = responses.text ? 200 : 404;
  6879. // IE - #1450: sometimes returns 1223 when it should be 204
  6880. } else if ( status === 1223 ) {
  6881. status = 204;
  6882. }
  6883. }
  6884. }
  6885. } catch( firefoxAccessException ) {
  6886. if ( !isAbort ) {
  6887. complete( -1, firefoxAccessException );
  6888. }
  6889. }
  6890. // Call complete if needed
  6891. if ( responses ) {
  6892. complete( status, statusText, responses, responseHeaders );
  6893. }
  6894. };
  6895. // if we're in sync mode or it's in cache
  6896. // and has been retrieved directly (IE6 & IE7)
  6897. // we need to manually fire the callback
  6898. if ( !s.async || xhr.readyState === 4 ) {
  6899. callback();
  6900. } else {
  6901. handle = ++xhrId;
  6902. if ( xhrOnUnloadAbort ) {
  6903. // Create the active xhrs callbacks list if needed
  6904. // and attach the unload handler
  6905. if ( !xhrCallbacks ) {
  6906. xhrCallbacks = {};
  6907. jQuery( window ).unload( xhrOnUnloadAbort );
  6908. }
  6909. // Add to list of active xhrs callbacks
  6910. xhrCallbacks[ handle ] = callback;
  6911. }
  6912. xhr.onreadystatechange = callback;
  6913. }
  6914. },
  6915. abort: function() {
  6916. if ( callback ) {
  6917. callback(0,1);
  6918. }
  6919. }
  6920. };
  6921. }
  6922. });
  6923. }
  6924. var elemdisplay = {},
  6925. iframe, iframeDoc,
  6926. rfxtypes = /^(?:toggle|show|hide)$/,
  6927. rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
  6928. timerId,
  6929. fxAttrs = [
  6930. // height animations
  6931. [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
  6932. // width animations
  6933. [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
  6934. // opacity animations
  6935. [ "opacity" ]
  6936. ],
  6937. fxNow;
  6938. jQuery.fn.extend({
  6939. show: function( speed, easing, callback ) {
  6940. var elem, display;
  6941. if ( speed || speed === 0 ) {
  6942. return this.animate( genFx("show", 3), speed, easing, callback );
  6943. } else {
  6944. for ( var i = 0, j = this.length; i < j; i++ ) {
  6945. elem = this[ i ];
  6946. if ( elem.style ) {
  6947. display = elem.style.display;
  6948. // Reset the inline display of this element to learn if it is
  6949. // being hidden by cascaded rules or not
  6950. if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
  6951. display = elem.style.display = "";
  6952. }
  6953. // Set elements which have been overridden with display: none
  6954. // in a stylesheet to whatever the default browser style is
  6955. // for such an element
  6956. if ( (display === "" && jQuery.css(elem, "display") === "none") ||
  6957. !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
  6958. jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
  6959. }
  6960. }
  6961. }
  6962. // Set the display of most of the elements in a second loop
  6963. // to avoid the constant reflow
  6964. for ( i = 0; i < j; i++ ) {
  6965. elem = this[ i ];
  6966. if ( elem.style ) {
  6967. display = elem.style.display;
  6968. if ( display === "" || display === "none" ) {
  6969. elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
  6970. }
  6971. }
  6972. }
  6973. return this;
  6974. }
  6975. },
  6976. hide: function( speed, easing, callback ) {
  6977. if ( speed || speed === 0 ) {
  6978. return this.animate( genFx("hide", 3), speed, easing, callback);
  6979. } else {
  6980. var elem, display,
  6981. i = 0,
  6982. j = this.length;
  6983. for ( ; i < j; i++ ) {
  6984. elem = this[i];
  6985. if ( elem.style ) {
  6986. display = jQuery.css( elem, "display" );
  6987. if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
  6988. jQuery._data( elem, "olddisplay", display );
  6989. }
  6990. }
  6991. }
  6992. // Set the display of the elements in a second loop
  6993. // to avoid the constant reflow
  6994. for ( i = 0; i < j; i++ ) {
  6995. if ( this[i].style ) {
  6996. this[i].style.display = "none";
  6997. }
  6998. }
  6999. return this;
  7000. }
  7001. },
  7002. // Save the old toggle function
  7003. _toggle: jQuery.fn.toggle,
  7004. toggle: function( fn, fn2, callback ) {
  7005. var bool = typeof fn === "boolean";
  7006. if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
  7007. this._toggle.apply( this, arguments );
  7008. } else if ( fn == null || bool ) {
  7009. this.each(function() {
  7010. var state = bool ? fn : jQuery(this).is(":hidden");
  7011. jQuery(this)[ state ? "show" : "hide" ]();
  7012. });
  7013. } else {
  7014. this.animate(genFx("toggle", 3), fn, fn2, callback);
  7015. }
  7016. return this;
  7017. },
  7018. fadeTo: function( speed, to, easing, callback ) {
  7019. return this.filter(":hidden").css("opacity", 0).show().end()
  7020. .animate({opacity: to}, speed, easing, callback);
  7021. },
  7022. animate: function( prop, speed, easing, callback ) {
  7023. var optall = jQuery.speed( speed, easing, callback );
  7024. if ( jQuery.isEmptyObject( prop ) ) {
  7025. return this.each( optall.complete, [ false ] );
  7026. }
  7027. // Do not change referenced properties as per-property easing will be lost
  7028. prop = jQuery.extend( {}, prop );
  7029. function doAnimation() {
  7030. // XXX 'this' does not always have a nodeName when running the
  7031. // test suite
  7032. if ( optall.queue === false ) {
  7033. jQuery._mark( this );
  7034. }
  7035. var opt = jQuery.extend( {}, optall ),
  7036. isElement = this.nodeType === 1,
  7037. hidden = isElement && jQuery(this).is(":hidden"),
  7038. name, val, p, e, hooks, replace,
  7039. parts, start, end, unit,
  7040. method;
  7041. // will store per property easing and be used to determine when an animation is complete
  7042. opt.animatedProperties = {};
  7043. // first pass over propertys to expand / normalize
  7044. for ( p in prop ) {
  7045. name = jQuery.camelCase( p );
  7046. if ( p !== name ) {
  7047. prop[ name ] = prop[ p ];
  7048. delete prop[ p ];
  7049. }
  7050. if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
  7051. replace = hooks.expand( prop[ name ] );
  7052. delete prop[ name ];
  7053. // not quite $.extend, this wont overwrite keys already present.
  7054. // also - reusing 'p' from above because we have the correct "name"
  7055. for ( p in replace ) {
  7056. if ( ! ( p in prop ) ) {
  7057. prop[ p ] = replace[ p ];
  7058. }
  7059. }
  7060. }
  7061. }
  7062. for ( name in prop ) {
  7063. val = prop[ name ];
  7064. // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
  7065. if ( jQuery.isArray( val ) ) {
  7066. opt.animatedProperties[ name ] = val[ 1 ];
  7067. val = prop[ name ] = val[ 0 ];
  7068. } else {
  7069. opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
  7070. }
  7071. if ( val === "hide" && hidden || val === "show" && !hidden ) {
  7072. return opt.complete.call( this );
  7073. }
  7074. if ( isElement && ( name === "height" || name === "width" ) ) {
  7075. // Make sure that nothing sneaks out
  7076. // Record all 3 overflow attributes because IE does not
  7077. // change the overflow attribute when overflowX and
  7078. // overflowY are set to the same value
  7079. opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
  7080. // Set display property to inline-block for height/width
  7081. // animations on inline elements that are having width/height animated
  7082. if ( jQuery.css( this, "display" ) === "inline" &&
  7083. jQuery.css( this, "float" ) === "none" ) {
  7084. // inline-level elements accept inline-block;
  7085. // block-level elements need to be inline with layout
  7086. if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
  7087. this.style.display = "inline-block";
  7088. } else {
  7089. this.style.zoom = 1;
  7090. }
  7091. }
  7092. }
  7093. }
  7094. if ( opt.overflow != null ) {
  7095. this.style.overflow = "hidden";
  7096. }
  7097. for ( p in prop ) {
  7098. e = new jQuery.fx( this, opt, p );
  7099. val = prop[ p ];
  7100. if ( rfxtypes.test( val ) ) {
  7101. // Tracks whether to show or hide based on private
  7102. // data attached to the element
  7103. method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
  7104. if ( method ) {
  7105. jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
  7106. e[ method ]();
  7107. } else {
  7108. e[ val ]();
  7109. }
  7110. } else {
  7111. parts = rfxnum.exec( val );
  7112. start = e.cur();
  7113. if ( parts ) {
  7114. end = parseFloat( parts[2] );
  7115. unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
  7116. // We need to compute starting value
  7117. if ( unit !== "px" ) {
  7118. jQuery.style( this, p, (end || 1) + unit);
  7119. start = ( (end || 1) / e.cur() ) * start;
  7120. jQuery.style( this, p, start + unit);
  7121. }
  7122. // If a +=/-= token was provided, we're doing a relative animation
  7123. if ( parts[1] ) {
  7124. end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
  7125. }
  7126. e.custom( start, end, unit );
  7127. } else {
  7128. e.custom( start, val, "" );
  7129. }
  7130. }
  7131. }
  7132. // For JS strict compliance
  7133. return true;
  7134. }
  7135. return optall.queue === false ?
  7136. this.each( doAnimation ) :
  7137. this.queue( optall.queue, doAnimation );
  7138. },
  7139. stop: function( type, clearQueue, gotoEnd ) {
  7140. if ( typeof type !== "string" ) {
  7141. gotoEnd = clearQueue;
  7142. clearQueue = type;
  7143. type = undefined;
  7144. }
  7145. if ( clearQueue && type !== false ) {
  7146. this.queue( type || "fx", [] );
  7147. }
  7148. return this.each(function() {
  7149. var index,
  7150. hadTimers = false,
  7151. timers = jQuery.timers,
  7152. data = jQuery._data( this );
  7153. // clear marker counters if we know they won't be
  7154. if ( !gotoEnd ) {
  7155. jQuery._unmark( true, this );
  7156. }
  7157. function stopQueue( elem, data, index ) {
  7158. var hooks = data[ index ];
  7159. jQuery.removeData( elem, index, true );
  7160. hooks.stop( gotoEnd );
  7161. }
  7162. if ( type == null ) {
  7163. for ( index in data ) {
  7164. if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
  7165. stopQueue( this, data, index );
  7166. }
  7167. }
  7168. } else if ( data[ index = type + ".run" ] && data[ index ].stop ){
  7169. stopQueue( this, data, index );
  7170. }
  7171. for ( index = timers.length; index--; ) {
  7172. if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
  7173. if ( gotoEnd ) {
  7174. // force the next step to be the last
  7175. timers[ index ]( true );
  7176. } else {
  7177. timers[ index ].saveState();
  7178. }
  7179. hadTimers = true;
  7180. timers.splice( index, 1 );
  7181. }
  7182. }
  7183. // start the next in the queue if the last step wasn't forced
  7184. // timers currently will call their complete callbacks, which will dequeue
  7185. // but only if they were gotoEnd
  7186. if ( !( gotoEnd && hadTimers ) ) {
  7187. jQuery.dequeue( this, type );
  7188. }
  7189. });
  7190. }
  7191. });
  7192. // Animations created synchronously will run synchronously
  7193. function createFxNow() {
  7194. setTimeout( clearFxNow, 0 );
  7195. return ( fxNow = jQuery.now() );
  7196. }
  7197. function clearFxNow() {
  7198. fxNow = undefined;
  7199. }
  7200. // Generate parameters to create a standard animation
  7201. function genFx( type, num ) {
  7202. var obj = {};
  7203. jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
  7204. obj[ this ] = type;
  7205. });
  7206. return obj;
  7207. }
  7208. // Generate shortcuts for custom animations
  7209. jQuery.each({
  7210. slideDown: genFx( "show", 1 ),
  7211. slideUp: genFx( "hide", 1 ),
  7212. slideToggle: genFx( "toggle", 1 ),
  7213. fadeIn: { opacity: "show" },
  7214. fadeOut: { opacity: "hide" },
  7215. fadeToggle: { opacity: "toggle" }
  7216. }, function( name, props ) {
  7217. jQuery.fn[ name ] = function( speed, easing, callback ) {
  7218. return this.animate( props, speed, easing, callback );
  7219. };
  7220. });
  7221. jQuery.extend({
  7222. speed: function( speed, easing, fn ) {
  7223. var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
  7224. complete: fn || !fn && easing ||
  7225. jQuery.isFunction( speed ) && speed,
  7226. duration: speed,
  7227. easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
  7228. };
  7229. opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
  7230. opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
  7231. // normalize opt.queue - true/undefined/null -> "fx"
  7232. if ( opt.queue == null || opt.queue === true ) {
  7233. opt.queue = "fx";
  7234. }
  7235. // Queueing
  7236. opt.old = opt.complete;
  7237. opt.complete = function( noUnmark ) {
  7238. if ( jQuery.isFunction( opt.old ) ) {
  7239. opt.old.call( this );
  7240. }
  7241. if ( opt.queue ) {
  7242. jQuery.dequeue( this, opt.queue );
  7243. } else if ( noUnmark !== false ) {
  7244. jQuery._unmark( this );
  7245. }
  7246. };
  7247. return opt;
  7248. },
  7249. easing: {
  7250. linear: function( p ) {
  7251. return p;
  7252. },
  7253. swing: function( p ) {
  7254. return ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;
  7255. }
  7256. },
  7257. timers: [],
  7258. fx: function( elem, options, prop ) {
  7259. this.options = options;
  7260. this.elem = elem;
  7261. this.prop = prop;
  7262. options.orig = options.orig || {};
  7263. }
  7264. });
  7265. jQuery.fx.prototype = {
  7266. // Simple function for setting a style value
  7267. update: function() {
  7268. if ( this.options.step ) {
  7269. this.options.step.call( this.elem, this.now, this );
  7270. }
  7271. ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
  7272. },
  7273. // Get the current size
  7274. cur: function() {
  7275. if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
  7276. return this.elem[ this.prop ];
  7277. }
  7278. var parsed,
  7279. r = jQuery.css( this.elem, this.prop );
  7280. // Empty strings, null, undefined and "auto" are converted to 0,
  7281. // complex values such as "rotate(1rad)" are returned as is,
  7282. // simple values such as "10px" are parsed to Float.
  7283. return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
  7284. },
  7285. // Start an animation from one number to another
  7286. custom: function( from, to, unit ) {
  7287. var self = this,
  7288. fx = jQuery.fx;
  7289. this.startTime = fxNow || createFxNow();
  7290. this.end = to;
  7291. this.now = this.start = from;
  7292. this.pos = this.state = 0;
  7293. this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
  7294. function t( gotoEnd ) {
  7295. return self.step( gotoEnd );
  7296. }
  7297. t.queue = this.options.queue;
  7298. t.elem = this.elem;
  7299. t.saveState = function() {
  7300. if ( jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
  7301. if ( self.options.hide ) {
  7302. jQuery._data( self.elem, "fxshow" + self.prop, self.start );
  7303. } else if ( self.options.show ) {
  7304. jQuery._data( self.elem, "fxshow" + self.prop, self.end );
  7305. }
  7306. }
  7307. };
  7308. if ( t() && jQuery.timers.push(t) && !timerId ) {
  7309. timerId = setInterval( fx.tick, fx.interval );
  7310. }
  7311. },
  7312. // Simple 'show' function
  7313. show: function() {
  7314. var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
  7315. // Remember where we started, so that we can go back to it later
  7316. this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
  7317. this.options.show = true;
  7318. // Begin the animation
  7319. // Make sure that we start at a small width/height to avoid any flash of content
  7320. if ( dataShow !== undefined ) {
  7321. // This show is picking up where a previous hide or show left off
  7322. this.custom( this.cur(), dataShow );
  7323. } else {
  7324. this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
  7325. }
  7326. // Start by showing the element
  7327. jQuery( this.elem ).show();
  7328. },
  7329. // Simple 'hide' function
  7330. hide: function() {
  7331. // Remember where we started, so that we can go back to it later
  7332. this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
  7333. this.options.hide = true;
  7334. // Begin the animation
  7335. this.custom( this.cur(), 0 );
  7336. },
  7337. // Each step of an animation
  7338. step: function( gotoEnd ) {
  7339. var p, n, complete,
  7340. t = fxNow || createFxNow(),
  7341. done = true,
  7342. elem = this.elem,
  7343. options = this.options;
  7344. if ( gotoEnd || t >= options.duration + this.startTime ) {
  7345. this.now = this.end;
  7346. this.pos = this.state = 1;
  7347. this.update();
  7348. options.animatedProperties[ this.prop ] = true;
  7349. for ( p in options.animatedProperties ) {
  7350. if ( options.animatedProperties[ p ] !== true ) {
  7351. done = false;
  7352. }
  7353. }
  7354. if ( done ) {
  7355. // Reset the overflow
  7356. if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
  7357. jQuery.each( [ "", "X", "Y" ], function( index, value ) {
  7358. elem.style[ "overflow" + value ] = options.overflow[ index ];
  7359. });
  7360. }
  7361. // Hide the element if the "hide" operation was done
  7362. if ( options.hide ) {
  7363. jQuery( elem ).hide();
  7364. }
  7365. // Reset the properties, if the item has been hidden or shown
  7366. if ( options.hide || options.show ) {
  7367. for ( p in options.animatedProperties ) {
  7368. jQuery.style( elem, p, options.orig[ p ] );
  7369. jQuery.removeData( elem, "fxshow" + p, true );
  7370. // Toggle data is no longer needed
  7371. jQuery.removeData( elem, "toggle" + p, true );
  7372. }
  7373. }
  7374. // Execute the complete function
  7375. // in the event that the complete function throws an exception
  7376. // we must ensure it won't be called twice. #5684
  7377. complete = options.complete;
  7378. if ( complete ) {
  7379. options.complete = false;
  7380. complete.call( elem );
  7381. }
  7382. }
  7383. return false;
  7384. } else {
  7385. // classical easing cannot be used with an Infinity duration
  7386. if ( options.duration == Infinity ) {
  7387. this.now = t;
  7388. } else {
  7389. n = t - this.startTime;
  7390. this.state = n / options.duration;
  7391. // Perform the easing function, defaults to swing
  7392. this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
  7393. this.now = this.start + ( (this.end - this.start) * this.pos );
  7394. }
  7395. // Perform the next step of the animation
  7396. this.update();
  7397. }
  7398. return true;
  7399. }
  7400. };
  7401. jQuery.extend( jQuery.fx, {
  7402. tick: function() {
  7403. var timer,
  7404. timers = jQuery.timers,
  7405. i = 0;
  7406. for ( ; i < timers.length; i++ ) {
  7407. timer = timers[ i ];
  7408. // Checks the timer has not already been removed
  7409. if ( !timer() && timers[ i ] === timer ) {
  7410. timers.splice( i--, 1 );
  7411. }
  7412. }
  7413. if ( !timers.length ) {
  7414. jQuery.fx.stop();
  7415. }
  7416. },
  7417. interval: 13,
  7418. stop: function() {
  7419. clearInterval( timerId );
  7420. timerId = null;
  7421. },
  7422. speeds: {
  7423. slow: 600,
  7424. fast: 200,
  7425. // Default speed
  7426. _default: 400
  7427. },
  7428. step: {
  7429. opacity: function( fx ) {
  7430. jQuery.style( fx.elem, "opacity", fx.now );
  7431. },
  7432. _default: function( fx ) {
  7433. if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
  7434. fx.elem.style[ fx.prop ] = fx.now + fx.unit;
  7435. } else {
  7436. fx.elem[ fx.prop ] = fx.now;
  7437. }
  7438. }
  7439. }
  7440. });
  7441. // Ensure props that can't be negative don't go there on undershoot easing
  7442. jQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {
  7443. // exclude marginTop, marginLeft, marginBottom and marginRight from this list
  7444. if ( prop.indexOf( "margin" ) ) {
  7445. jQuery.fx.step[ prop ] = function( fx ) {
  7446. jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
  7447. };
  7448. }
  7449. });
  7450. if ( jQuery.expr && jQuery.expr.filters ) {
  7451. jQuery.expr.filters.animated = function( elem ) {
  7452. return jQuery.grep(jQuery.timers, function( fn ) {
  7453. return elem === fn.elem;
  7454. }).length;
  7455. };
  7456. }
  7457. // Try to restore the default display value of an element
  7458. function defaultDisplay( nodeName ) {
  7459. if ( !elemdisplay[ nodeName ] ) {
  7460. var body = document.body,
  7461. elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
  7462. display = elem.css( "display" );
  7463. elem.remove();
  7464. // If the simple way fails,
  7465. // get element's real default display by attaching it to a temp iframe
  7466. if ( display === "none" || display === "" ) {
  7467. // No iframe to use yet, so create it
  7468. if ( !iframe ) {
  7469. iframe = document.createElement( "iframe" );
  7470. iframe.frameBorder = iframe.width = iframe.height = 0;
  7471. }
  7472. body.appendChild( iframe );
  7473. // Create a cacheable copy of the iframe document on first call.
  7474. // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
  7475. // document to it; WebKit & Firefox won't allow reusing the iframe document.
  7476. if ( !iframeDoc || !iframe.createElement ) {
  7477. iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
  7478. iframeDoc.write( ( jQuery.support.boxModel ? "<!doctype html>" : "" ) + "<html><body>" );
  7479. iframeDoc.close();
  7480. }
  7481. elem = iframeDoc.createElement( nodeName );
  7482. iframeDoc.body.appendChild( elem );
  7483. display = jQuery.css( elem, "display" );
  7484. body.removeChild( iframe );
  7485. }
  7486. // Store the correct default display
  7487. elemdisplay[ nodeName ] = display;
  7488. }
  7489. return elemdisplay[ nodeName ];
  7490. }
  7491. var getOffset,
  7492. rtable = /^t(?:able|d|h)$/i,
  7493. rroot = /^(?:body|html)$/i;
  7494. if ( "getBoundingClientRect" in document.documentElement ) {
  7495. getOffset = function( elem, doc, docElem, box ) {
  7496. try {
  7497. box = elem.getBoundingClientRect();
  7498. } catch(e) {}
  7499. // Make sure we're not dealing with a disconnected DOM node
  7500. if ( !box || !jQuery.contains( docElem, elem ) ) {
  7501. return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
  7502. }
  7503. var body = doc.body,
  7504. win = getWindow( doc ),
  7505. clientTop = docElem.clientTop || body.clientTop || 0,
  7506. clientLeft = docElem.clientLeft || body.clientLeft || 0,
  7507. scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
  7508. scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
  7509. top = box.top + scrollTop - clientTop,
  7510. left = box.left + scrollLeft - clientLeft;
  7511. return { top: top, left: left };
  7512. };
  7513. } else {
  7514. getOffset = function( elem, doc, docElem ) {
  7515. var computedStyle,
  7516. offsetParent = elem.offsetParent,
  7517. prevOffsetParent = elem,
  7518. body = doc.body,
  7519. defaultView = doc.defaultView,
  7520. prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
  7521. top = elem.offsetTop,
  7522. left = elem.offsetLeft;
  7523. while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
  7524. if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
  7525. break;
  7526. }
  7527. computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
  7528. top -= elem.scrollTop;
  7529. left -= elem.scrollLeft;
  7530. if ( elem === offsetParent ) {
  7531. top += elem.offsetTop;
  7532. left += elem.offsetLeft;
  7533. if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
  7534. top += parseFloat( computedStyle.borderTopWidth ) || 0;
  7535. left += parseFloat( computedStyle.borderLeftWidth ) || 0;
  7536. }
  7537. prevOffsetParent = offsetParent;
  7538. offsetParent = elem.offsetParent;
  7539. }
  7540. if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
  7541. top += parseFloat( computedStyle.borderTopWidth ) || 0;
  7542. left += parseFloat( computedStyle.borderLeftWidth ) || 0;
  7543. }
  7544. prevComputedStyle = computedStyle;
  7545. }
  7546. if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
  7547. top += body.offsetTop;
  7548. left += body.offsetLeft;
  7549. }
  7550. if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
  7551. top += Math.max( docElem.scrollTop, body.scrollTop );
  7552. left += Math.max( docElem.scrollLeft, body.scrollLeft );
  7553. }
  7554. return { top: top, left: left };
  7555. };
  7556. }
  7557. jQuery.fn.offset = function( options ) {
  7558. if ( arguments.length ) {
  7559. return options === undefined ?
  7560. this :
  7561. this.each(function( i ) {
  7562. jQuery.offset.setOffset( this, options, i );
  7563. });
  7564. }
  7565. var elem = this[0],
  7566. doc = elem && elem.ownerDocument;
  7567. if ( !doc ) {
  7568. return null;
  7569. }
  7570. if ( elem === doc.body ) {
  7571. return jQuery.offset.bodyOffset( elem );
  7572. }
  7573. return getOffset( elem, doc, doc.documentElement );
  7574. };
  7575. jQuery.offset = {
  7576. bodyOffset: function( body ) {
  7577. var top = body.offsetTop,
  7578. left = body.offsetLeft;
  7579. if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
  7580. top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
  7581. left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
  7582. }
  7583. return { top: top, left: left };
  7584. },
  7585. setOffset: function( elem, options, i ) {
  7586. var position = jQuery.css( elem, "position" );
  7587. // set position first, in-case top/left are set even on static elem
  7588. if ( position === "static" ) {
  7589. elem.style.position = "relative";
  7590. }
  7591. var curElem = jQuery( elem ),
  7592. curOffset = curElem.offset(),
  7593. curCSSTop = jQuery.css( elem, "top" ),
  7594. curCSSLeft = jQuery.css( elem, "left" ),
  7595. calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
  7596. props = {}, curPosition = {}, curTop, curLeft;
  7597. // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
  7598. if ( calculatePosition ) {
  7599. curPosition = curElem.position();
  7600. curTop = curPosition.top;
  7601. curLeft = curPosition.left;
  7602. } else {
  7603. curTop = parseFloat( curCSSTop ) || 0;
  7604. curLeft = parseFloat( curCSSLeft ) || 0;
  7605. }
  7606. if ( jQuery.isFunction( options ) ) {
  7607. options = options.call( elem, i, curOffset );
  7608. }
  7609. if ( options.top != null ) {
  7610. props.top = ( options.top - curOffset.top ) + curTop;
  7611. }
  7612. if ( options.left != null ) {
  7613. props.left = ( options.left - curOffset.left ) + curLeft;
  7614. }
  7615. if ( "using" in options ) {
  7616. options.using.call( elem, props );
  7617. } else {
  7618. curElem.css( props );
  7619. }
  7620. }
  7621. };
  7622. jQuery.fn.extend({
  7623. position: function() {
  7624. if ( !this[0] ) {
  7625. return null;
  7626. }
  7627. var elem = this[0],
  7628. // Get *real* offsetParent
  7629. offsetParent = this.offsetParent(),
  7630. // Get correct offsets
  7631. offset = this.offset(),
  7632. parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
  7633. // Subtract element margins
  7634. // note: when an element has margin: auto the offsetLeft and marginLeft
  7635. // are the same in Safari causing offset.left to incorrectly be 0
  7636. offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
  7637. offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
  7638. // Add offsetParent borders
  7639. parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
  7640. parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
  7641. // Subtract the two offsets
  7642. return {
  7643. top: offset.top - parentOffset.top,
  7644. left: offset.left - parentOffset.left
  7645. };
  7646. },
  7647. offsetParent: function() {
  7648. return this.map(function() {
  7649. var offsetParent = this.offsetParent || document.body;
  7650. while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
  7651. offsetParent = offsetParent.offsetParent;
  7652. }
  7653. return offsetParent;
  7654. });
  7655. }
  7656. });
  7657. // Create scrollLeft and scrollTop methods
  7658. jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
  7659. var top = /Y/.test( prop );
  7660. jQuery.fn[ method ] = function( val ) {
  7661. return jQuery.access( this, function( elem, method, val ) {
  7662. var win = getWindow( elem );
  7663. if ( val === undefined ) {
  7664. return win ? (prop in win) ? win[ prop ] :
  7665. jQuery.support.boxModel && win.document.documentElement[ method ] ||
  7666. win.document.body[ method ] :
  7667. elem[ method ];
  7668. }
  7669. if ( win ) {
  7670. win.scrollTo(
  7671. !top ? val : jQuery( win ).scrollLeft(),
  7672. top ? val : jQuery( win ).scrollTop()
  7673. );
  7674. } else {
  7675. elem[ method ] = val;
  7676. }
  7677. }, method, val, arguments.length, null );
  7678. };
  7679. });
  7680. function getWindow( elem ) {
  7681. return jQuery.isWindow( elem ) ?
  7682. elem :
  7683. elem.nodeType === 9 ?
  7684. elem.defaultView || elem.parentWindow :
  7685. false;
  7686. }
  7687. // Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
  7688. jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
  7689. var clientProp = "client" + name,
  7690. scrollProp = "scroll" + name,
  7691. offsetProp = "offset" + name;
  7692. // innerHeight and innerWidth
  7693. jQuery.fn[ "inner" + name ] = function() {
  7694. var elem = this[0];
  7695. return elem ?
  7696. elem.style ?
  7697. parseFloat( jQuery.css( elem, type, "padding" ) ) :
  7698. this[ type ]() :
  7699. null;
  7700. };
  7701. // outerHeight and outerWidth
  7702. jQuery.fn[ "outer" + name ] = function( margin ) {
  7703. var elem = this[0];
  7704. return elem ?
  7705. elem.style ?
  7706. parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
  7707. this[ type ]() :
  7708. null;
  7709. };
  7710. jQuery.fn[ type ] = function( value ) {
  7711. return jQuery.access( this, function( elem, type, value ) {
  7712. var doc, docElemProp, orig, ret;
  7713. if ( jQuery.isWindow( elem ) ) {
  7714. // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
  7715. doc = elem.document;
  7716. docElemProp = doc.documentElement[ clientProp ];
  7717. return jQuery.support.boxModel && docElemProp ||
  7718. doc.body && doc.body[ clientProp ] || docElemProp;
  7719. }
  7720. // Get document width or height
  7721. if ( elem.nodeType === 9 ) {
  7722. // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
  7723. doc = elem.documentElement;
  7724. // when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]
  7725. // so we can't use max, as it'll choose the incorrect offset[Width/Height]
  7726. // instead we use the correct client[Width/Height]
  7727. // support:IE6
  7728. if ( doc[ clientProp ] >= doc[ scrollProp ] ) {
  7729. return doc[ clientProp ];
  7730. }
  7731. return Math.max(
  7732. elem.body[ scrollProp ], doc[ scrollProp ],
  7733. elem.body[ offsetProp ], doc[ offsetProp ]
  7734. );
  7735. }
  7736. // Get width or height on the element
  7737. if ( value === undefined ) {
  7738. orig = jQuery.css( elem, type );
  7739. ret = parseFloat( orig );
  7740. return jQuery.isNumeric( ret ) ? ret : orig;
  7741. }
  7742. // Set the width or height on the element
  7743. jQuery( elem ).css( type, value );
  7744. }, type, value, arguments.length, null );
  7745. };
  7746. });
  7747. // Expose jQuery to the global object
  7748. window.jQuery = window.$ = jQuery;
  7749. // Expose jQuery as an AMD module, but only for AMD loaders that
  7750. // understand the issues with loading multiple versions of jQuery
  7751. // in a page that all might call define(). The loader will indicate
  7752. // they have special allowances for multiple jQuery versions by
  7753. // specifying define.amd.jQuery = true. Register as a named module,
  7754. // since jQuery can be concatenated with other files that may use define,
  7755. // but not use a proper concatenation script that understands anonymous
  7756. // AMD modules. A named AMD is safest and most robust way to register.
  7757. // Lowercase jquery is used because AMD module names are derived from
  7758. // file names, and jQuery is normally delivered in a lowercase file name.
  7759. // Do this after creating the global so that if an AMD module wants to call
  7760. // noConflict to hide this version of jQuery, it will work.
  7761. if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
  7762. define( "jquery", [], function () { return jQuery; } );
  7763. }
  7764. })( window );
  7765. /**
  7766. * @license AngularJS v1.0.6
  7767. * (c) 2010-2012 Google, Inc. http://angularjs.org
  7768. * License: MIT
  7769. */
  7770. (function(window, document){
  7771. var _jQuery = window.jQuery.noConflict(true);
  7772. ////////////////////////////////////
  7773. /**
  7774. * @ngdoc function
  7775. * @name angular.lowercase
  7776. * @function
  7777. *
  7778. * @description Converts the specified string to lowercase.
  7779. * @param {string} string String to be converted to lowercase.
  7780. * @returns {string} Lowercased string.
  7781. */
  7782. var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
  7783. /**
  7784. * @ngdoc function
  7785. * @name angular.uppercase
  7786. * @function
  7787. *
  7788. * @description Converts the specified string to uppercase.
  7789. * @param {string} string String to be converted to uppercase.
  7790. * @returns {string} Uppercased string.
  7791. */
  7792. var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
  7793. var manualLowercase = function(s) {
  7794. return isString(s)
  7795. ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
  7796. : s;
  7797. };
  7798. var manualUppercase = function(s) {
  7799. return isString(s)
  7800. ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
  7801. : s;
  7802. };
  7803. // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
  7804. // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
  7805. // with correct but slower alternatives.
  7806. if ('i' !== 'I'.toLowerCase()) {
  7807. lowercase = manualLowercase;
  7808. uppercase = manualUppercase;
  7809. }
  7810. var /** holds major version number for IE or NaN for real browsers */
  7811. msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]),
  7812. jqLite, // delay binding since jQuery could be loaded after us.
  7813. jQuery, // delay binding
  7814. slice = [].slice,
  7815. push = [].push,
  7816. toString = Object.prototype.toString,
  7817. /** @name angular */
  7818. angular = window.angular || (window.angular = {}),
  7819. angularModule,
  7820. nodeName_,
  7821. uid = ['0', '0', '0'];
  7822. /**
  7823. * @ngdoc function
  7824. * @name angular.forEach
  7825. * @function
  7826. *
  7827. * @description
  7828. * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
  7829. * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
  7830. * is the value of an object property or an array element and `key` is the object property key or
  7831. * array element index. Specifying a `context` for the function is optional.
  7832. *
  7833. * Note: this function was previously known as `angular.foreach`.
  7834. *
  7835. <pre>
  7836. var values = {name: 'misko', gender: 'male'};
  7837. var log = [];
  7838. angular.forEach(values, function(value, key){
  7839. this.push(key + ': ' + value);
  7840. }, log);
  7841. expect(log).toEqual(['name: misko', 'gender:male']);
  7842. </pre>
  7843. *
  7844. * @param {Object|Array} obj Object to iterate over.
  7845. * @param {Function} iterator Iterator function.
  7846. * @param {Object=} context Object to become context (`this`) for the iterator function.
  7847. * @returns {Object|Array} Reference to `obj`.
  7848. */
  7849. /**
  7850. * @private
  7851. * @param {*} obj
  7852. * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
  7853. */
  7854. function isArrayLike(obj) {
  7855. if (!obj || (typeof obj.length !== 'number')) return false;
  7856. // We have on object which has length property. Should we treat it as array?
  7857. if (typeof obj.hasOwnProperty != 'function' &&
  7858. typeof obj.constructor != 'function') {
  7859. // This is here for IE8: it is a bogus object treat it as array;
  7860. return true;
  7861. } else {
  7862. return obj instanceof JQLite || // JQLite
  7863. (jQuery && obj instanceof jQuery) || // jQuery
  7864. toString.call(obj) !== '[object Object]' || // some browser native object
  7865. typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
  7866. }
  7867. }
  7868. function forEach(obj, iterator, context) {
  7869. var key;
  7870. if (obj) {
  7871. if (isFunction(obj)){
  7872. for (key in obj) {
  7873. if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
  7874. iterator.call(context, obj[key], key);
  7875. }
  7876. }
  7877. } else if (obj.forEach && obj.forEach !== forEach) {
  7878. obj.forEach(iterator, context);
  7879. } else if (isArrayLike(obj)) {
  7880. for (key = 0; key < obj.length; key++)
  7881. iterator.call(context, obj[key], key);
  7882. } else {
  7883. for (key in obj) {
  7884. if (obj.hasOwnProperty(key)) {
  7885. iterator.call(context, obj[key], key);
  7886. }
  7887. }
  7888. }
  7889. }
  7890. return obj;
  7891. }
  7892. function sortedKeys(obj) {
  7893. var keys = [];
  7894. for (var key in obj) {
  7895. if (obj.hasOwnProperty(key)) {
  7896. keys.push(key);
  7897. }
  7898. }
  7899. return keys.sort();
  7900. }
  7901. function forEachSorted(obj, iterator, context) {
  7902. var keys = sortedKeys(obj);
  7903. for ( var i = 0; i < keys.length; i++) {
  7904. iterator.call(context, obj[keys[i]], keys[i]);
  7905. }
  7906. return keys;
  7907. }
  7908. /**
  7909. * when using forEach the params are value, key, but it is often useful to have key, value.
  7910. * @param {function(string, *)} iteratorFn
  7911. * @returns {function(*, string)}
  7912. */
  7913. function reverseParams(iteratorFn) {
  7914. return function(value, key) { iteratorFn(key, value) };
  7915. }
  7916. /**
  7917. * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
  7918. * characters such as '012ABC'. The reason why we are not using simply a number counter is that
  7919. * the number string gets longer over time, and it can also overflow, where as the nextId
  7920. * will grow much slower, it is a string, and it will never overflow.
  7921. *
  7922. * @returns an unique alpha-numeric string
  7923. */
  7924. function nextUid() {
  7925. var index = uid.length;
  7926. var digit;
  7927. while(index) {
  7928. index--;
  7929. digit = uid[index].charCodeAt(0);
  7930. if (digit == 57 /*'9'*/) {
  7931. uid[index] = 'A';
  7932. return uid.join('');
  7933. }
  7934. if (digit == 90 /*'Z'*/) {
  7935. uid[index] = '0';
  7936. } else {
  7937. uid[index] = String.fromCharCode(digit + 1);
  7938. return uid.join('');
  7939. }
  7940. }
  7941. uid.unshift('0');
  7942. return uid.join('');
  7943. }
  7944. /**
  7945. * @ngdoc function
  7946. * @name angular.extend
  7947. * @function
  7948. *
  7949. * @description
  7950. * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
  7951. * to `dst`. You can specify multiple `src` objects.
  7952. *
  7953. * @param {Object} dst Destination object.
  7954. * @param {...Object} src Source object(s).
  7955. */
  7956. function extend(dst) {
  7957. forEach(arguments, function(obj){
  7958. if (obj !== dst) {
  7959. forEach(obj, function(value, key){
  7960. dst[key] = value;
  7961. });
  7962. }
  7963. });
  7964. return dst;
  7965. }
  7966. function int(str) {
  7967. return parseInt(str, 10);
  7968. }
  7969. function inherit(parent, extra) {
  7970. return extend(new (extend(function() {}, {prototype:parent}))(), extra);
  7971. }
  7972. /**
  7973. * @ngdoc function
  7974. * @name angular.noop
  7975. * @function
  7976. *
  7977. * @description
  7978. * A function that performs no operations. This function can be useful when writing code in the
  7979. * functional style.
  7980. <pre>
  7981. function foo(callback) {
  7982. var result = calculateResult();
  7983. (callback || angular.noop)(result);
  7984. }
  7985. </pre>
  7986. */
  7987. function noop() {}
  7988. noop.$inject = [];
  7989. /**
  7990. * @ngdoc function
  7991. * @name angular.identity
  7992. * @function
  7993. *
  7994. * @description
  7995. * A function that returns its first argument. This function is useful when writing code in the
  7996. * functional style.
  7997. *
  7998. <pre>
  7999. function transformer(transformationFn, value) {
  8000. return (transformationFn || identity)(value);
  8001. };
  8002. </pre>
  8003. */
  8004. function identity($) {return $;}
  8005. identity.$inject = [];
  8006. function valueFn(value) {return function() {return value;};}
  8007. /**
  8008. * @ngdoc function
  8009. * @name angular.isUndefined
  8010. * @function
  8011. *
  8012. * @description
  8013. * Determines if a reference is undefined.
  8014. *
  8015. * @param {*} value Reference to check.
  8016. * @returns {boolean} True if `value` is undefined.
  8017. */
  8018. function isUndefined(value){return typeof value == 'undefined';}
  8019. /**
  8020. * @ngdoc function
  8021. * @name angular.isDefined
  8022. * @function
  8023. *
  8024. * @description
  8025. * Determines if a reference is defined.
  8026. *
  8027. * @param {*} value Reference to check.
  8028. * @returns {boolean} True if `value` is defined.
  8029. */
  8030. function isDefined(value){return typeof value != 'undefined';}
  8031. /**
  8032. * @ngdoc function
  8033. * @name angular.isObject
  8034. * @function
  8035. *
  8036. * @description
  8037. * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
  8038. * considered to be objects.
  8039. *
  8040. * @param {*} value Reference to check.
  8041. * @returns {boolean} True if `value` is an `Object` but not `null`.
  8042. */
  8043. function isObject(value){return value != null && typeof value == 'object';}
  8044. /**
  8045. * @ngdoc function
  8046. * @name angular.isString
  8047. * @function
  8048. *
  8049. * @description
  8050. * Determines if a reference is a `String`.
  8051. *
  8052. * @param {*} value Reference to check.
  8053. * @returns {boolean} True if `value` is a `String`.
  8054. */
  8055. function isString(value){return typeof value == 'string';}
  8056. /**
  8057. * @ngdoc function
  8058. * @name angular.isNumber
  8059. * @function
  8060. *
  8061. * @description
  8062. * Determines if a reference is a `Number`.
  8063. *
  8064. * @param {*} value Reference to check.
  8065. * @returns {boolean} True if `value` is a `Number`.
  8066. */
  8067. function isNumber(value){return typeof value == 'number';}
  8068. /**
  8069. * @ngdoc function
  8070. * @name angular.isDate
  8071. * @function
  8072. *
  8073. * @description
  8074. * Determines if a value is a date.
  8075. *
  8076. * @param {*} value Reference to check.
  8077. * @returns {boolean} True if `value` is a `Date`.
  8078. */
  8079. function isDate(value){
  8080. return toString.apply(value) == '[object Date]';
  8081. }
  8082. /**
  8083. * @ngdoc function
  8084. * @name angular.isArray
  8085. * @function
  8086. *
  8087. * @description
  8088. * Determines if a reference is an `Array`.
  8089. *
  8090. * @param {*} value Reference to check.
  8091. * @returns {boolean} True if `value` is an `Array`.
  8092. */
  8093. function isArray(value) {
  8094. return toString.apply(value) == '[object Array]';
  8095. }
  8096. /**
  8097. * @ngdoc function
  8098. * @name angular.isFunction
  8099. * @function
  8100. *
  8101. * @description
  8102. * Determines if a reference is a `Function`.
  8103. *
  8104. * @param {*} value Reference to check.
  8105. * @returns {boolean} True if `value` is a `Function`.
  8106. */
  8107. function isFunction(value){return typeof value == 'function';}
  8108. /**
  8109. * Checks if `obj` is a window object.
  8110. *
  8111. * @private
  8112. * @param {*} obj Object to check
  8113. * @returns {boolean} True if `obj` is a window obj.
  8114. */
  8115. function isWindow(obj) {
  8116. return obj && obj.document && obj.location && obj.alert && obj.setInterval;
  8117. }
  8118. function isScope(obj) {
  8119. return obj && obj.$evalAsync && obj.$watch;
  8120. }
  8121. function isFile(obj) {
  8122. return toString.apply(obj) === '[object File]';
  8123. }
  8124. function isBoolean(value) {
  8125. return typeof value == 'boolean';
  8126. }
  8127. function trim(value) {
  8128. return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
  8129. }
  8130. /**
  8131. * @ngdoc function
  8132. * @name angular.isElement
  8133. * @function
  8134. *
  8135. * @description
  8136. * Determines if a reference is a DOM element (or wrapped jQuery element).
  8137. *
  8138. * @param {*} value Reference to check.
  8139. * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
  8140. */
  8141. function isElement(node) {
  8142. return node &&
  8143. (node.nodeName // we are a direct element
  8144. || (node.bind && node.find)); // we have a bind and find method part of jQuery API
  8145. }
  8146. /**
  8147. * @param str 'key1,key2,...'
  8148. * @returns {object} in the form of {key1:true, key2:true, ...}
  8149. */
  8150. function makeMap(str){
  8151. var obj = {}, items = str.split(","), i;
  8152. for ( i = 0; i < items.length; i++ )
  8153. obj[ items[i] ] = true;
  8154. return obj;
  8155. }
  8156. if (msie < 9) {
  8157. nodeName_ = function(element) {
  8158. element = element.nodeName ? element : element[0];
  8159. return (element.scopeName && element.scopeName != 'HTML')
  8160. ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
  8161. };
  8162. } else {
  8163. nodeName_ = function(element) {
  8164. return element.nodeName ? element.nodeName : element[0].nodeName;
  8165. };
  8166. }
  8167. function map(obj, iterator, context) {
  8168. var results = [];
  8169. forEach(obj, function(value, index, list) {
  8170. results.push(iterator.call(context, value, index, list));
  8171. });
  8172. return results;
  8173. }
  8174. /**
  8175. * @description
  8176. * Determines the number of elements in an array, the number of properties an object has, or
  8177. * the length of a string.
  8178. *
  8179. * Note: This function is used to augment the Object type in Angular expressions. See
  8180. * {@link angular.Object} for more information about Angular arrays.
  8181. *
  8182. * @param {Object|Array|string} obj Object, array, or string to inspect.
  8183. * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
  8184. * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
  8185. */
  8186. function size(obj, ownPropsOnly) {
  8187. var size = 0, key;
  8188. if (isArray(obj) || isString(obj)) {
  8189. return obj.length;
  8190. } else if (isObject(obj)){
  8191. for (key in obj)
  8192. if (!ownPropsOnly || obj.hasOwnProperty(key))
  8193. size++;
  8194. }
  8195. return size;
  8196. }
  8197. function includes(array, obj) {
  8198. return indexOf(array, obj) != -1;
  8199. }
  8200. function indexOf(array, obj) {
  8201. if (array.indexOf) return array.indexOf(obj);
  8202. for ( var i = 0; i < array.length; i++) {
  8203. if (obj === array[i]) return i;
  8204. }
  8205. return -1;
  8206. }
  8207. function arrayRemove(array, value) {
  8208. var index = indexOf(array, value);
  8209. if (index >=0)
  8210. array.splice(index, 1);
  8211. return value;
  8212. }
  8213. function isLeafNode (node) {
  8214. if (node) {
  8215. switch (node.nodeName) {
  8216. case "OPTION":
  8217. case "PRE":
  8218. case "TITLE":
  8219. return true;
  8220. }
  8221. }
  8222. return false;
  8223. }
  8224. /**
  8225. * @ngdoc function
  8226. * @name angular.copy
  8227. * @function
  8228. *
  8229. * @description
  8230. * Creates a deep copy of `source`, which should be an object or an array.
  8231. *
  8232. * * If no destination is supplied, a copy of the object or array is created.
  8233. * * If a destination is provided, all of its elements (for array) or properties (for objects)
  8234. * are deleted and then all elements/properties from the source are copied to it.
  8235. * * If `source` is not an object or array, `source` is returned.
  8236. *
  8237. * Note: this function is used to augment the Object type in Angular expressions. See
  8238. * {@link ng.$filter} for more information about Angular arrays.
  8239. *
  8240. * @param {*} source The source that will be used to make a copy.
  8241. * Can be any type, including primitives, `null`, and `undefined`.
  8242. * @param {(Object|Array)=} destination Destination into which the source is copied. If
  8243. * provided, must be of the same type as `source`.
  8244. * @returns {*} The copy or updated `destination`, if `destination` was specified.
  8245. */
  8246. function copy(source, destination){
  8247. if (isWindow(source) || isScope(source)) throw Error("Can't copy Window or Scope");
  8248. if (!destination) {
  8249. destination = source;
  8250. if (source) {
  8251. if (isArray(source)) {
  8252. destination = copy(source, []);
  8253. } else if (isDate(source)) {
  8254. destination = new Date(source.getTime());
  8255. } else if (isObject(source)) {
  8256. destination = copy(source, {});
  8257. }
  8258. }
  8259. } else {
  8260. if (source === destination) throw Error("Can't copy equivalent objects or arrays");
  8261. if (isArray(source)) {
  8262. destination.length = 0;
  8263. for ( var i = 0; i < source.length; i++) {
  8264. destination.push(copy(source[i]));
  8265. }
  8266. } else {
  8267. forEach(destination, function(value, key){
  8268. delete destination[key];
  8269. });
  8270. for ( var key in source) {
  8271. destination[key] = copy(source[key]);
  8272. }
  8273. }
  8274. }
  8275. return destination;
  8276. }
  8277. /**
  8278. * Create a shallow copy of an object
  8279. */
  8280. function shallowCopy(src, dst) {
  8281. dst = dst || {};
  8282. for(var key in src) {
  8283. if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
  8284. dst[key] = src[key];
  8285. }
  8286. }
  8287. return dst;
  8288. }
  8289. /**
  8290. * @ngdoc function
  8291. * @name angular.equals
  8292. * @function
  8293. *
  8294. * @description
  8295. * Determines if two objects or two values are equivalent. Supports value types, arrays and
  8296. * objects.
  8297. *
  8298. * Two objects or values are considered equivalent if at least one of the following is true:
  8299. *
  8300. * * Both objects or values pass `===` comparison.
  8301. * * Both objects or values are of the same type and all of their properties pass `===` comparison.
  8302. * * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal)
  8303. *
  8304. * During a property comparision, properties of `function` type and properties with names
  8305. * that begin with `$` are ignored.
  8306. *
  8307. * Scope and DOMWindow objects are being compared only be identify (`===`).
  8308. *
  8309. * @param {*} o1 Object or value to compare.
  8310. * @param {*} o2 Object or value to compare.
  8311. * @returns {boolean} True if arguments are equal.
  8312. */
  8313. function equals(o1, o2) {
  8314. if (o1 === o2) return true;
  8315. if (o1 === null || o2 === null) return false;
  8316. if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
  8317. var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
  8318. if (t1 == t2) {
  8319. if (t1 == 'object') {
  8320. if (isArray(o1)) {
  8321. if ((length = o1.length) == o2.length) {
  8322. for(key=0; key<length; key++) {
  8323. if (!equals(o1[key], o2[key])) return false;
  8324. }
  8325. return true;
  8326. }
  8327. } else if (isDate(o1)) {
  8328. return isDate(o2) && o1.getTime() == o2.getTime();
  8329. } else {
  8330. if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2)) return false;
  8331. keySet = {};
  8332. for(key in o1) {
  8333. if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
  8334. if (!equals(o1[key], o2[key])) return false;
  8335. keySet[key] = true;
  8336. }
  8337. for(key in o2) {
  8338. if (!keySet[key] &&
  8339. key.charAt(0) !== '$' &&
  8340. o2[key] !== undefined &&
  8341. !isFunction(o2[key])) return false;
  8342. }
  8343. return true;
  8344. }
  8345. }
  8346. }
  8347. return false;
  8348. }
  8349. function concat(array1, array2, index) {
  8350. return array1.concat(slice.call(array2, index));
  8351. }
  8352. function sliceArgs(args, startIndex) {
  8353. return slice.call(args, startIndex || 0);
  8354. }
  8355. /**
  8356. * @ngdoc function
  8357. * @name angular.bind
  8358. * @function
  8359. *
  8360. * @description
  8361. * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
  8362. * `fn`). You can supply optional `args` that are are prebound to the function. This feature is also
  8363. * known as [function currying](http://en.wikipedia.org/wiki/Currying).
  8364. *
  8365. * @param {Object} self Context which `fn` should be evaluated in.
  8366. * @param {function()} fn Function to be bound.
  8367. * @param {...*} args Optional arguments to be prebound to the `fn` function call.
  8368. * @returns {function()} Function that wraps the `fn` with all the specified bindings.
  8369. */
  8370. function bind(self, fn) {
  8371. var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
  8372. if (isFunction(fn) && !(fn instanceof RegExp)) {
  8373. return curryArgs.length
  8374. ? function() {
  8375. return arguments.length
  8376. ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
  8377. : fn.apply(self, curryArgs);
  8378. }
  8379. : function() {
  8380. return arguments.length
  8381. ? fn.apply(self, arguments)
  8382. : fn.call(self);
  8383. };
  8384. } else {
  8385. // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
  8386. return fn;
  8387. }
  8388. }
  8389. function toJsonReplacer(key, value) {
  8390. var val = value;
  8391. if (/^\$+/.test(key)) {
  8392. val = undefined;
  8393. } else if (isWindow(value)) {
  8394. val = '$WINDOW';
  8395. } else if (value && document === value) {
  8396. val = '$DOCUMENT';
  8397. } else if (isScope(value)) {
  8398. val = '$SCOPE';
  8399. }
  8400. return val;
  8401. }
  8402. /**
  8403. * @ngdoc function
  8404. * @name angular.toJson
  8405. * @function
  8406. *
  8407. * @description
  8408. * Serializes input into a JSON-formatted string.
  8409. *
  8410. * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
  8411. * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
  8412. * @returns {string} Jsonified string representing `obj`.
  8413. */
  8414. function toJson(obj, pretty) {
  8415. return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
  8416. }
  8417. /**
  8418. * @ngdoc function
  8419. * @name angular.fromJson
  8420. * @function
  8421. *
  8422. * @description
  8423. * Deserializes a JSON string.
  8424. *
  8425. * @param {string} json JSON string to deserialize.
  8426. * @returns {Object|Array|Date|string|number} Deserialized thingy.
  8427. */
  8428. function fromJson(json) {
  8429. return isString(json)
  8430. ? JSON.parse(json)
  8431. : json;
  8432. }
  8433. function toBoolean(value) {
  8434. if (value && value.length !== 0) {
  8435. var v = lowercase("" + value);
  8436. value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
  8437. } else {
  8438. value = false;
  8439. }
  8440. return value;
  8441. }
  8442. /**
  8443. * @returns {string} Returns the string representation of the element.
  8444. */
  8445. function startingTag(element) {
  8446. element = jqLite(element).clone();
  8447. try {
  8448. // turns out IE does not let you set .html() on elements which
  8449. // are not allowed to have children. So we just ignore it.
  8450. element.html('');
  8451. } catch(e) {}
  8452. // As Per DOM Standards
  8453. var TEXT_NODE = 3;
  8454. var elemHtml = jqLite('<div>').append(element).html();
  8455. try {
  8456. return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
  8457. elemHtml.
  8458. match(/^(<[^>]+>)/)[1].
  8459. replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
  8460. } catch(e) {
  8461. return lowercase(elemHtml);
  8462. }
  8463. }
  8464. /////////////////////////////////////////////////
  8465. /**
  8466. * Parses an escaped url query string into key-value pairs.
  8467. * @returns Object.<(string|boolean)>
  8468. */
  8469. function parseKeyValue(/**string*/keyValue) {
  8470. var obj = {}, key_value, key;
  8471. forEach((keyValue || "").split('&'), function(keyValue){
  8472. if (keyValue) {
  8473. key_value = keyValue.split('=');
  8474. key = decodeURIComponent(key_value[0]);
  8475. obj[key] = isDefined(key_value[1]) ? decodeURIComponent(key_value[1]) : true;
  8476. }
  8477. });
  8478. return obj;
  8479. }
  8480. function toKeyValue(obj) {
  8481. var parts = [];
  8482. forEach(obj, function(value, key) {
  8483. parts.push(encodeUriQuery(key, true) + (value === true ? '' : '=' + encodeUriQuery(value, true)));
  8484. });
  8485. return parts.length ? parts.join('&') : '';
  8486. }
  8487. /**
  8488. * We need our custom method because encodeURIComponent is too agressive and doesn't follow
  8489. * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
  8490. * segments:
  8491. * segment = *pchar
  8492. * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
  8493. * pct-encoded = "%" HEXDIG HEXDIG
  8494. * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
  8495. * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
  8496. * / "*" / "+" / "," / ";" / "="
  8497. */
  8498. function encodeUriSegment(val) {
  8499. return encodeUriQuery(val, true).
  8500. replace(/%26/gi, '&').
  8501. replace(/%3D/gi, '=').
  8502. replace(/%2B/gi, '+');
  8503. }
  8504. /**
  8505. * This method is intended for encoding *key* or *value* parts of query component. We need a custom
  8506. * method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be
  8507. * encoded per http://tools.ietf.org/html/rfc3986:
  8508. * query = *( pchar / "/" / "?" )
  8509. * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
  8510. * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
  8511. * pct-encoded = "%" HEXDIG HEXDIG
  8512. * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
  8513. * / "*" / "+" / "," / ";" / "="
  8514. */
  8515. function encodeUriQuery(val, pctEncodeSpaces) {
  8516. return encodeURIComponent(val).
  8517. replace(/%40/gi, '@').
  8518. replace(/%3A/gi, ':').
  8519. replace(/%24/g, '$').
  8520. replace(/%2C/gi, ',').
  8521. replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
  8522. }
  8523. /**
  8524. * @ngdoc directive
  8525. * @name ng.directive:ngApp
  8526. *
  8527. * @element ANY
  8528. * @param {angular.Module} ngApp an optional application
  8529. * {@link angular.module module} name to load.
  8530. *
  8531. * @description
  8532. *
  8533. * Use this directive to auto-bootstrap on application. Only
  8534. * one directive can be used per HTML document. The directive
  8535. * designates the root of the application and is typically placed
  8536. * at the root of the page.
  8537. *
  8538. * In the example below if the `ngApp` directive would not be placed
  8539. * on the `html` element then the document would not be compiled
  8540. * and the `{{ 1+2 }}` would not be resolved to `3`.
  8541. *
  8542. * `ngApp` is the easiest way to bootstrap an application.
  8543. *
  8544. <doc:example>
  8545. <doc:source>
  8546. I can add: 1 + 2 = {{ 1+2 }}
  8547. </doc:source>
  8548. </doc:example>
  8549. *
  8550. */
  8551. function angularInit(element, bootstrap) {
  8552. var elements = [element],
  8553. appElement,
  8554. module,
  8555. names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
  8556. NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
  8557. function append(element) {
  8558. element && elements.push(element);
  8559. }
  8560. forEach(names, function(name) {
  8561. names[name] = true;
  8562. append(document.getElementById(name));
  8563. name = name.replace(':', '\\:');
  8564. if (element.querySelectorAll) {
  8565. forEach(element.querySelectorAll('.' + name), append);
  8566. forEach(element.querySelectorAll('.' + name + '\\:'), append);
  8567. forEach(element.querySelectorAll('[' + name + ']'), append);
  8568. }
  8569. });
  8570. forEach(elements, function(element) {
  8571. if (!appElement) {
  8572. var className = ' ' + element.className + ' ';
  8573. var match = NG_APP_CLASS_REGEXP.exec(className);
  8574. if (match) {
  8575. appElement = element;
  8576. module = (match[2] || '').replace(/\s+/g, ',');
  8577. } else {
  8578. forEach(element.attributes, function(attr) {
  8579. if (!appElement && names[attr.name]) {
  8580. appElement = element;
  8581. module = attr.value;
  8582. }
  8583. });
  8584. }
  8585. }
  8586. });
  8587. if (appElement) {
  8588. bootstrap(appElement, module ? [module] : []);
  8589. }
  8590. }
  8591. /**
  8592. * @ngdoc function
  8593. * @name angular.bootstrap
  8594. * @description
  8595. * Use this function to manually start up angular application.
  8596. *
  8597. * See: {@link guide/bootstrap Bootstrap}
  8598. *
  8599. * @param {Element} element DOM element which is the root of angular application.
  8600. * @param {Array<String|Function>=} modules an array of module declarations. See: {@link angular.module modules}
  8601. * @returns {AUTO.$injector} Returns the newly created injector for this app.
  8602. */
  8603. function bootstrap(element, modules) {
  8604. var resumeBootstrapInternal = function() {
  8605. element = jqLite(element);
  8606. modules = modules || [];
  8607. modules.unshift(['$provide', function($provide) {
  8608. $provide.value('$rootElement', element);
  8609. }]);
  8610. modules.unshift('ng');
  8611. var injector = createInjector(modules);
  8612. injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
  8613. function(scope, element, compile, injector) {
  8614. scope.$apply(function() {
  8615. element.data('$injector', injector);
  8616. compile(element)(scope);
  8617. });
  8618. }]
  8619. );
  8620. return injector;
  8621. };
  8622. var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
  8623. if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
  8624. return resumeBootstrapInternal();
  8625. }
  8626. window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
  8627. angular.resumeBootstrap = function(extraModules) {
  8628. forEach(extraModules, function(module) {
  8629. modules.push(module);
  8630. });
  8631. resumeBootstrapInternal();
  8632. };
  8633. }
  8634. var SNAKE_CASE_REGEXP = /[A-Z]/g;
  8635. function snake_case(name, separator){
  8636. separator = separator || '_';
  8637. return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
  8638. return (pos ? separator : '') + letter.toLowerCase();
  8639. });
  8640. }
  8641. function bindJQuery() {
  8642. // bind to jQuery if present;
  8643. jQuery = window.jQuery;
  8644. // reset to jQuery or default to us.
  8645. if (jQuery) {
  8646. jqLite = jQuery;
  8647. extend(jQuery.fn, {
  8648. scope: JQLitePrototype.scope,
  8649. controller: JQLitePrototype.controller,
  8650. injector: JQLitePrototype.injector,
  8651. inheritedData: JQLitePrototype.inheritedData
  8652. });
  8653. JQLitePatchJQueryRemove('remove', true);
  8654. JQLitePatchJQueryRemove('empty');
  8655. JQLitePatchJQueryRemove('html');
  8656. } else {
  8657. jqLite = JQLite;
  8658. }
  8659. angular.element = jqLite;
  8660. }
  8661. /**
  8662. * throw error of the argument is falsy.
  8663. */
  8664. function assertArg(arg, name, reason) {
  8665. if (!arg) {
  8666. throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
  8667. }
  8668. return arg;
  8669. }
  8670. function assertArgFn(arg, name, acceptArrayAnnotation) {
  8671. if (acceptArrayAnnotation && isArray(arg)) {
  8672. arg = arg[arg.length - 1];
  8673. }
  8674. assertArg(isFunction(arg), name, 'not a function, got ' +
  8675. (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
  8676. return arg;
  8677. }
  8678. /**
  8679. * @ngdoc interface
  8680. * @name angular.Module
  8681. * @description
  8682. *
  8683. * Interface for configuring angular {@link angular.module modules}.
  8684. */
  8685. function setupModuleLoader(window) {
  8686. function ensure(obj, name, factory) {
  8687. return obj[name] || (obj[name] = factory());
  8688. }
  8689. return ensure(ensure(window, 'angular', Object), 'module', function() {
  8690. /** @type {Object.<string, angular.Module>} */
  8691. var modules = {};
  8692. /**
  8693. * @ngdoc function
  8694. * @name angular.module
  8695. * @description
  8696. *
  8697. * The `angular.module` is a global place for creating and registering Angular modules. All
  8698. * modules (angular core or 3rd party) that should be available to an application must be
  8699. * registered using this mechanism.
  8700. *
  8701. *
  8702. * # Module
  8703. *
  8704. * A module is a collocation of services, directives, filters, and configuration information. Module
  8705. * is used to configure the {@link AUTO.$injector $injector}.
  8706. *
  8707. * <pre>
  8708. * // Create a new module
  8709. * var myModule = angular.module('myModule', []);
  8710. *
  8711. * // register a new service
  8712. * myModule.value('appName', 'MyCoolApp');
  8713. *
  8714. * // configure existing services inside initialization blocks.
  8715. * myModule.config(function($locationProvider) {
  8716. * // Configure existing providers
  8717. * $locationProvider.hashPrefix('!');
  8718. * });
  8719. * </pre>
  8720. *
  8721. * Then you can create an injector and load your modules like this:
  8722. *
  8723. * <pre>
  8724. * var injector = angular.injector(['ng', 'MyModule'])
  8725. * </pre>
  8726. *
  8727. * However it's more likely that you'll just use
  8728. * {@link ng.directive:ngApp ngApp} or
  8729. * {@link angular.bootstrap} to simplify this process for you.
  8730. *
  8731. * @param {!string} name The name of the module to create or retrieve.
  8732. * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
  8733. * the module is being retrieved for further configuration.
  8734. * @param {Function} configFn Optional configuration function for the module. Same as
  8735. * {@link angular.Module#config Module#config()}.
  8736. * @returns {module} new module with the {@link angular.Module} api.
  8737. */
  8738. return function module(name, requires, configFn) {
  8739. if (requires && modules.hasOwnProperty(name)) {
  8740. modules[name] = null;
  8741. }
  8742. return ensure(modules, name, function() {
  8743. if (!requires) {
  8744. throw Error('No module: ' + name);
  8745. }
  8746. /** @type {!Array.<Array.<*>>} */
  8747. var invokeQueue = [];
  8748. /** @type {!Array.<Function>} */
  8749. var runBlocks = [];
  8750. var config = invokeLater('$injector', 'invoke');
  8751. /** @type {angular.Module} */
  8752. var moduleInstance = {
  8753. // Private state
  8754. _invokeQueue: invokeQueue,
  8755. _runBlocks: runBlocks,
  8756. /**
  8757. * @ngdoc property
  8758. * @name angular.Module#requires
  8759. * @propertyOf angular.Module
  8760. * @returns {Array.<string>} List of module names which must be loaded before this module.
  8761. * @description
  8762. * Holds the list of modules which the injector will load before the current module is loaded.
  8763. */
  8764. requires: requires,
  8765. /**
  8766. * @ngdoc property
  8767. * @name angular.Module#name
  8768. * @propertyOf angular.Module
  8769. * @returns {string} Name of the module.
  8770. * @description
  8771. */
  8772. name: name,
  8773. /**
  8774. * @ngdoc method
  8775. * @name angular.Module#provider
  8776. * @methodOf angular.Module
  8777. * @param {string} name service name
  8778. * @param {Function} providerType Construction function for creating new instance of the service.
  8779. * @description
  8780. * See {@link AUTO.$provide#provider $provide.provider()}.
  8781. */
  8782. provider: invokeLater('$provide', 'provider'),
  8783. /**
  8784. * @ngdoc method
  8785. * @name angular.Module#factory
  8786. * @methodOf angular.Module
  8787. * @param {string} name service name
  8788. * @param {Function} providerFunction Function for creating new instance of the service.
  8789. * @description
  8790. * See {@link AUTO.$provide#factory $provide.factory()}.
  8791. */
  8792. factory: invokeLater('$provide', 'factory'),
  8793. /**
  8794. * @ngdoc method
  8795. * @name angular.Module#service
  8796. * @methodOf angular.Module
  8797. * @param {string} name service name
  8798. * @param {Function} constructor A constructor function that will be instantiated.
  8799. * @description
  8800. * See {@link AUTO.$provide#service $provide.service()}.
  8801. */
  8802. service: invokeLater('$provide', 'service'),
  8803. /**
  8804. * @ngdoc method
  8805. * @name angular.Module#value
  8806. * @methodOf angular.Module
  8807. * @param {string} name service name
  8808. * @param {*} object Service instance object.
  8809. * @description
  8810. * See {@link AUTO.$provide#value $provide.value()}.
  8811. */
  8812. value: invokeLater('$provide', 'value'),
  8813. /**
  8814. * @ngdoc method
  8815. * @name angular.Module#constant
  8816. * @methodOf angular.Module
  8817. * @param {string} name constant name
  8818. * @param {*} object Constant value.
  8819. * @description
  8820. * Because the constant are fixed, they get applied before other provide methods.
  8821. * See {@link AUTO.$provide#constant $provide.constant()}.
  8822. */
  8823. constant: invokeLater('$provide', 'constant', 'unshift'),
  8824. /**
  8825. * @ngdoc method
  8826. * @name angular.Module#filter
  8827. * @methodOf angular.Module
  8828. * @param {string} name Filter name.
  8829. * @param {Function} filterFactory Factory function for creating new instance of filter.
  8830. * @description
  8831. * See {@link ng.$filterProvider#register $filterProvider.register()}.
  8832. */
  8833. filter: invokeLater('$filterProvider', 'register'),
  8834. /**
  8835. * @ngdoc method
  8836. * @name angular.Module#controller
  8837. * @methodOf angular.Module
  8838. * @param {string} name Controller name.
  8839. * @param {Function} constructor Controller constructor function.
  8840. * @description
  8841. * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
  8842. */
  8843. controller: invokeLater('$controllerProvider', 'register'),
  8844. /**
  8845. * @ngdoc method
  8846. * @name angular.Module#directive
  8847. * @methodOf angular.Module
  8848. * @param {string} name directive name
  8849. * @param {Function} directiveFactory Factory function for creating new instance of
  8850. * directives.
  8851. * @description
  8852. * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
  8853. */
  8854. directive: invokeLater('$compileProvider', 'directive'),
  8855. /**
  8856. * @ngdoc method
  8857. * @name angular.Module#config
  8858. * @methodOf angular.Module
  8859. * @param {Function} configFn Execute this function on module load. Useful for service
  8860. * configuration.
  8861. * @description
  8862. * Use this method to register work which needs to be performed on module loading.
  8863. */
  8864. config: config,
  8865. /**
  8866. * @ngdoc method
  8867. * @name angular.Module#run
  8868. * @methodOf angular.Module
  8869. * @param {Function} initializationFn Execute this function after injector creation.
  8870. * Useful for application initialization.
  8871. * @description
  8872. * Use this method to register work which should be performed when the injector is done
  8873. * loading all modules.
  8874. */
  8875. run: function(block) {
  8876. runBlocks.push(block);
  8877. return this;
  8878. }
  8879. };
  8880. if (configFn) {
  8881. config(configFn);
  8882. }
  8883. return moduleInstance;
  8884. /**
  8885. * @param {string} provider
  8886. * @param {string} method
  8887. * @param {String=} insertMethod
  8888. * @returns {angular.Module}
  8889. */
  8890. function invokeLater(provider, method, insertMethod) {
  8891. return function() {
  8892. invokeQueue[insertMethod || 'push']([provider, method, arguments]);
  8893. return moduleInstance;
  8894. }
  8895. }
  8896. });
  8897. };
  8898. });
  8899. }
  8900. /**
  8901. * @ngdoc property
  8902. * @name angular.version
  8903. * @description
  8904. * An object that contains information about the current AngularJS version. This object has the
  8905. * following properties:
  8906. *
  8907. * - `full` – `{string}` – Full version string, such as "0.9.18".
  8908. * - `major` – `{number}` – Major version number, such as "0".
  8909. * - `minor` – `{number}` – Minor version number, such as "9".
  8910. * - `dot` – `{number}` – Dot version number, such as "18".
  8911. * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
  8912. */
  8913. var version = {
  8914. full: '1.0.6', // all of these placeholder strings will be replaced by grunt's
  8915. major: 1, // package task
  8916. minor: 0,
  8917. dot: 6,
  8918. codeName: 'universal-irreversibility'
  8919. };
  8920. function publishExternalAPI(angular){
  8921. extend(angular, {
  8922. 'bootstrap': bootstrap,
  8923. 'copy': copy,
  8924. 'extend': extend,
  8925. 'equals': equals,
  8926. 'element': jqLite,
  8927. 'forEach': forEach,
  8928. 'injector': createInjector,
  8929. 'noop':noop,
  8930. 'bind':bind,
  8931. 'toJson': toJson,
  8932. 'fromJson': fromJson,
  8933. 'identity':identity,
  8934. 'isUndefined': isUndefined,
  8935. 'isDefined': isDefined,
  8936. 'isString': isString,
  8937. 'isFunction': isFunction,
  8938. 'isObject': isObject,
  8939. 'isNumber': isNumber,
  8940. 'isElement': isElement,
  8941. 'isArray': isArray,
  8942. 'version': version,
  8943. 'isDate': isDate,
  8944. 'lowercase': lowercase,
  8945. 'uppercase': uppercase,
  8946. 'callbacks': {counter: 0}
  8947. });
  8948. angularModule = setupModuleLoader(window);
  8949. try {
  8950. angularModule('ngLocale');
  8951. } catch (e) {
  8952. angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
  8953. }
  8954. angularModule('ng', ['ngLocale'], ['$provide',
  8955. function ngModule($provide) {
  8956. $provide.provider('$compile', $CompileProvider).
  8957. directive({
  8958. a: htmlAnchorDirective,
  8959. input: inputDirective,
  8960. textarea: inputDirective,
  8961. form: formDirective,
  8962. script: scriptDirective,
  8963. select: selectDirective,
  8964. style: styleDirective,
  8965. option: optionDirective,
  8966. ngBind: ngBindDirective,
  8967. ngBindHtmlUnsafe: ngBindHtmlUnsafeDirective,
  8968. ngBindTemplate: ngBindTemplateDirective,
  8969. ngClass: ngClassDirective,
  8970. ngClassEven: ngClassEvenDirective,
  8971. ngClassOdd: ngClassOddDirective,
  8972. ngCsp: ngCspDirective,
  8973. ngCloak: ngCloakDirective,
  8974. ngController: ngControllerDirective,
  8975. ngForm: ngFormDirective,
  8976. ngHide: ngHideDirective,
  8977. ngInclude: ngIncludeDirective,
  8978. ngInit: ngInitDirective,
  8979. ngNonBindable: ngNonBindableDirective,
  8980. ngPluralize: ngPluralizeDirective,
  8981. ngRepeat: ngRepeatDirective,
  8982. ngShow: ngShowDirective,
  8983. ngSubmit: ngSubmitDirective,
  8984. ngStyle: ngStyleDirective,
  8985. ngSwitch: ngSwitchDirective,
  8986. ngSwitchWhen: ngSwitchWhenDirective,
  8987. ngSwitchDefault: ngSwitchDefaultDirective,
  8988. ngOptions: ngOptionsDirective,
  8989. ngView: ngViewDirective,
  8990. ngTransclude: ngTranscludeDirective,
  8991. ngModel: ngModelDirective,
  8992. ngList: ngListDirective,
  8993. ngChange: ngChangeDirective,
  8994. required: requiredDirective,
  8995. ngRequired: requiredDirective,
  8996. ngValue: ngValueDirective
  8997. }).
  8998. directive(ngAttributeAliasDirectives).
  8999. directive(ngEventDirectives);
  9000. $provide.provider({
  9001. $anchorScroll: $AnchorScrollProvider,
  9002. $browser: $BrowserProvider,
  9003. $cacheFactory: $CacheFactoryProvider,
  9004. $controller: $ControllerProvider,
  9005. $document: $DocumentProvider,
  9006. $exceptionHandler: $ExceptionHandlerProvider,
  9007. $filter: $FilterProvider,
  9008. $interpolate: $InterpolateProvider,
  9009. $http: $HttpProvider,
  9010. $httpBackend: $HttpBackendProvider,
  9011. $location: $LocationProvider,
  9012. $log: $LogProvider,
  9013. $parse: $ParseProvider,
  9014. $route: $RouteProvider,
  9015. $routeParams: $RouteParamsProvider,
  9016. $rootScope: $RootScopeProvider,
  9017. $q: $QProvider,
  9018. $sniffer: $SnifferProvider,
  9019. $templateCache: $TemplateCacheProvider,
  9020. $timeout: $TimeoutProvider,
  9021. $window: $WindowProvider
  9022. });
  9023. }
  9024. ]);
  9025. }
  9026. //////////////////////////////////
  9027. //JQLite
  9028. //////////////////////////////////
  9029. /**
  9030. * @ngdoc function
  9031. * @name angular.element
  9032. * @function
  9033. *
  9034. * @description
  9035. * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
  9036. * `angular.element` can be either an alias for [jQuery](http://api.jquery.com/jQuery/) function, if
  9037. * jQuery is available, or a function that wraps the element or string in Angular's jQuery lite
  9038. * implementation (commonly referred to as jqLite).
  9039. *
  9040. * Real jQuery always takes precedence over jqLite, provided it was loaded before `DOMContentLoaded`
  9041. * event fired.
  9042. *
  9043. * jqLite is a tiny, API-compatible subset of jQuery that allows
  9044. * Angular to manipulate the DOM. jqLite implements only the most commonly needed functionality
  9045. * within a very small footprint, so only a subset of the jQuery API - methods, arguments and
  9046. * invocation styles - are supported.
  9047. *
  9048. * Note: All element references in Angular are always wrapped with jQuery or jqLite; they are never
  9049. * raw DOM references.
  9050. *
  9051. * ## Angular's jQuery lite provides the following methods:
  9052. *
  9053. * - [addClass()](http://api.jquery.com/addClass/)
  9054. * - [after()](http://api.jquery.com/after/)
  9055. * - [append()](http://api.jquery.com/append/)
  9056. * - [attr()](http://api.jquery.com/attr/)
  9057. * - [bind()](http://api.jquery.com/bind/)
  9058. * - [children()](http://api.jquery.com/children/)
  9059. * - [clone()](http://api.jquery.com/clone/)
  9060. * - [contents()](http://api.jquery.com/contents/)
  9061. * - [css()](http://api.jquery.com/css/)
  9062. * - [data()](http://api.jquery.com/data/)
  9063. * - [eq()](http://api.jquery.com/eq/)
  9064. * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name.
  9065. * - [hasClass()](http://api.jquery.com/hasClass/)
  9066. * - [html()](http://api.jquery.com/html/)
  9067. * - [next()](http://api.jquery.com/next/)
  9068. * - [parent()](http://api.jquery.com/parent/)
  9069. * - [prepend()](http://api.jquery.com/prepend/)
  9070. * - [prop()](http://api.jquery.com/prop/)
  9071. * - [ready()](http://api.jquery.com/ready/)
  9072. * - [remove()](http://api.jquery.com/remove/)
  9073. * - [removeAttr()](http://api.jquery.com/removeAttr/)
  9074. * - [removeClass()](http://api.jquery.com/removeClass/)
  9075. * - [removeData()](http://api.jquery.com/removeData/)
  9076. * - [replaceWith()](http://api.jquery.com/replaceWith/)
  9077. * - [text()](http://api.jquery.com/text/)
  9078. * - [toggleClass()](http://api.jquery.com/toggleClass/)
  9079. * - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers.
  9080. * - [unbind()](http://api.jquery.com/unbind/)
  9081. * - [val()](http://api.jquery.com/val/)
  9082. * - [wrap()](http://api.jquery.com/wrap/)
  9083. *
  9084. * ## In addtion to the above, Angular provides additional methods to both jQuery and jQuery lite:
  9085. *
  9086. * - `controller(name)` - retrieves the controller of the current element or its parent. By default
  9087. * retrieves controller associated with the `ngController` directive. If `name` is provided as
  9088. * camelCase directive name, then the controller for this directive will be retrieved (e.g.
  9089. * `'ngModel'`).
  9090. * - `injector()` - retrieves the injector of the current element or its parent.
  9091. * - `scope()` - retrieves the {@link api/ng.$rootScope.Scope scope} of the current
  9092. * element or its parent.
  9093. * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
  9094. * parent element is reached.
  9095. *
  9096. * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
  9097. * @returns {Object} jQuery object.
  9098. */
  9099. var jqCache = JQLite.cache = {},
  9100. jqName = JQLite.expando = 'ng-' + new Date().getTime(),
  9101. jqId = 1,
  9102. addEventListenerFn = (window.document.addEventListener
  9103. ? function(element, type, fn) {element.addEventListener(type, fn, false);}
  9104. : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
  9105. removeEventListenerFn = (window.document.removeEventListener
  9106. ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
  9107. : function(element, type, fn) {element.detachEvent('on' + type, fn); });
  9108. function jqNextId() { return ++jqId; }
  9109. var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
  9110. var MOZ_HACK_REGEXP = /^moz([A-Z])/;
  9111. /**
  9112. * Converts snake_case to camelCase.
  9113. * Also there is special case for Moz prefix starting with upper case letter.
  9114. * @param name Name to normalize
  9115. */
  9116. function camelCase(name) {
  9117. return name.
  9118. replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
  9119. return offset ? letter.toUpperCase() : letter;
  9120. }).
  9121. replace(MOZ_HACK_REGEXP, 'Moz$1');
  9122. }
  9123. /////////////////////////////////////////////
  9124. // jQuery mutation patch
  9125. //
  9126. // In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
  9127. // $destroy event on all DOM nodes being removed.
  9128. //
  9129. /////////////////////////////////////////////
  9130. function JQLitePatchJQueryRemove(name, dispatchThis) {
  9131. var originalJqFn = jQuery.fn[name];
  9132. originalJqFn = originalJqFn.$original || originalJqFn;
  9133. removePatch.$original = originalJqFn;
  9134. jQuery.fn[name] = removePatch;
  9135. function removePatch() {
  9136. var list = [this],
  9137. fireEvent = dispatchThis,
  9138. set, setIndex, setLength,
  9139. element, childIndex, childLength, children,
  9140. fns, events;
  9141. while(list.length) {
  9142. set = list.shift();
  9143. for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
  9144. element = jqLite(set[setIndex]);
  9145. if (fireEvent) {
  9146. element.triggerHandler('$destroy');
  9147. } else {
  9148. fireEvent = !fireEvent;
  9149. }
  9150. for(childIndex = 0, childLength = (children = element.children()).length;
  9151. childIndex < childLength;
  9152. childIndex++) {
  9153. list.push(jQuery(children[childIndex]));
  9154. }
  9155. }
  9156. }
  9157. return originalJqFn.apply(this, arguments);
  9158. }
  9159. }
  9160. /////////////////////////////////////////////
  9161. function JQLite(element) {
  9162. if (element instanceof JQLite) {
  9163. return element;
  9164. }
  9165. if (!(this instanceof JQLite)) {
  9166. if (isString(element) && element.charAt(0) != '<') {
  9167. throw Error('selectors not implemented');
  9168. }
  9169. return new JQLite(element);
  9170. }
  9171. if (isString(element)) {
  9172. var div = document.createElement('div');
  9173. // Read about the NoScope elements here:
  9174. // http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
  9175. div.innerHTML = '<div>&#160;</div>' + element; // IE insanity to make NoScope elements work!
  9176. div.removeChild(div.firstChild); // remove the superfluous div
  9177. JQLiteAddNodes(this, div.childNodes);
  9178. this.remove(); // detach the elements from the temporary DOM div.
  9179. } else {
  9180. JQLiteAddNodes(this, element);
  9181. }
  9182. }
  9183. function JQLiteClone(element) {
  9184. return element.cloneNode(true);
  9185. }
  9186. function JQLiteDealoc(element){
  9187. JQLiteRemoveData(element);
  9188. for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
  9189. JQLiteDealoc(children[i]);
  9190. }
  9191. }
  9192. function JQLiteUnbind(element, type, fn) {
  9193. var events = JQLiteExpandoStore(element, 'events'),
  9194. handle = JQLiteExpandoStore(element, 'handle');
  9195. if (!handle) return; //no listeners registered
  9196. if (isUndefined(type)) {
  9197. forEach(events, function(eventHandler, type) {
  9198. removeEventListenerFn(element, type, eventHandler);
  9199. delete events[type];
  9200. });
  9201. } else {
  9202. if (isUndefined(fn)) {
  9203. removeEventListenerFn(element, type, events[type]);
  9204. delete events[type];
  9205. } else {
  9206. arrayRemove(events[type], fn);
  9207. }
  9208. }
  9209. }
  9210. function JQLiteRemoveData(element) {
  9211. var expandoId = element[jqName],
  9212. expandoStore = jqCache[expandoId];
  9213. if (expandoStore) {
  9214. if (expandoStore.handle) {
  9215. expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
  9216. JQLiteUnbind(element);
  9217. }
  9218. delete jqCache[expandoId];
  9219. element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
  9220. }
  9221. }
  9222. function JQLiteExpandoStore(element, key, value) {
  9223. var expandoId = element[jqName],
  9224. expandoStore = jqCache[expandoId || -1];
  9225. if (isDefined(value)) {
  9226. if (!expandoStore) {
  9227. element[jqName] = expandoId = jqNextId();
  9228. expandoStore = jqCache[expandoId] = {};
  9229. }
  9230. expandoStore[key] = value;
  9231. } else {
  9232. return expandoStore && expandoStore[key];
  9233. }
  9234. }
  9235. function JQLiteData(element, key, value) {
  9236. var data = JQLiteExpandoStore(element, 'data'),
  9237. isSetter = isDefined(value),
  9238. keyDefined = !isSetter && isDefined(key),
  9239. isSimpleGetter = keyDefined && !isObject(key);
  9240. if (!data && !isSimpleGetter) {
  9241. JQLiteExpandoStore(element, 'data', data = {});
  9242. }
  9243. if (isSetter) {
  9244. data[key] = value;
  9245. } else {
  9246. if (keyDefined) {
  9247. if (isSimpleGetter) {
  9248. // don't create data in this case.
  9249. return data && data[key];
  9250. } else {
  9251. extend(data, key);
  9252. }
  9253. } else {
  9254. return data;
  9255. }
  9256. }
  9257. }
  9258. function JQLiteHasClass(element, selector) {
  9259. return ((" " + element.className + " ").replace(/[\n\t]/g, " ").
  9260. indexOf( " " + selector + " " ) > -1);
  9261. }
  9262. function JQLiteRemoveClass(element, cssClasses) {
  9263. if (cssClasses) {
  9264. forEach(cssClasses.split(' '), function(cssClass) {
  9265. element.className = trim(
  9266. (" " + element.className + " ")
  9267. .replace(/[\n\t]/g, " ")
  9268. .replace(" " + trim(cssClass) + " ", " ")
  9269. );
  9270. });
  9271. }
  9272. }
  9273. function JQLiteAddClass(element, cssClasses) {
  9274. if (cssClasses) {
  9275. forEach(cssClasses.split(' '), function(cssClass) {
  9276. if (!JQLiteHasClass(element, cssClass)) {
  9277. element.className = trim(element.className + ' ' + trim(cssClass));
  9278. }
  9279. });
  9280. }
  9281. }
  9282. function JQLiteAddNodes(root, elements) {
  9283. if (elements) {
  9284. elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
  9285. ? elements
  9286. : [ elements ];
  9287. for(var i=0; i < elements.length; i++) {
  9288. root.push(elements[i]);
  9289. }
  9290. }
  9291. }
  9292. function JQLiteController(element, name) {
  9293. return JQLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
  9294. }
  9295. function JQLiteInheritedData(element, name, value) {
  9296. element = jqLite(element);
  9297. // if element is the document object work with the html element instead
  9298. // this makes $(document).scope() possible
  9299. if(element[0].nodeType == 9) {
  9300. element = element.find('html');
  9301. }
  9302. while (element.length) {
  9303. if (value = element.data(name)) return value;
  9304. element = element.parent();
  9305. }
  9306. }
  9307. //////////////////////////////////////////
  9308. // Functions which are declared directly.
  9309. //////////////////////////////////////////
  9310. var JQLitePrototype = JQLite.prototype = {
  9311. ready: function(fn) {
  9312. var fired = false;
  9313. function trigger() {
  9314. if (fired) return;
  9315. fired = true;
  9316. fn();
  9317. }
  9318. this.bind('DOMContentLoaded', trigger); // works for modern browsers and IE9
  9319. // we can not use jqLite since we are not done loading and jQuery could be loaded later.
  9320. JQLite(window).bind('load', trigger); // fallback to window.onload for others
  9321. },
  9322. toString: function() {
  9323. var value = [];
  9324. forEach(this, function(e){ value.push('' + e);});
  9325. return '[' + value.join(', ') + ']';
  9326. },
  9327. eq: function(index) {
  9328. return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
  9329. },
  9330. length: 0,
  9331. push: push,
  9332. sort: [].sort,
  9333. splice: [].splice
  9334. };
  9335. //////////////////////////////////////////
  9336. // Functions iterating getter/setters.
  9337. // these functions return self on setter and
  9338. // value on get.
  9339. //////////////////////////////////////////
  9340. var BOOLEAN_ATTR = {};
  9341. forEach('multiple,selected,checked,disabled,readOnly,required'.split(','), function(value) {
  9342. BOOLEAN_ATTR[lowercase(value)] = value;
  9343. });
  9344. var BOOLEAN_ELEMENTS = {};
  9345. forEach('input,select,option,textarea,button,form'.split(','), function(value) {
  9346. BOOLEAN_ELEMENTS[uppercase(value)] = true;
  9347. });
  9348. function getBooleanAttrName(element, name) {
  9349. // check dom last since we will most likely fail on name
  9350. var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
  9351. // booleanAttr is here twice to minimize DOM access
  9352. return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
  9353. }
  9354. forEach({
  9355. data: JQLiteData,
  9356. inheritedData: JQLiteInheritedData,
  9357. scope: function(element) {
  9358. return JQLiteInheritedData(element, '$scope');
  9359. },
  9360. controller: JQLiteController ,
  9361. injector: function(element) {
  9362. return JQLiteInheritedData(element, '$injector');
  9363. },
  9364. removeAttr: function(element,name) {
  9365. element.removeAttribute(name);
  9366. },
  9367. hasClass: JQLiteHasClass,
  9368. css: function(element, name, value) {
  9369. name = camelCase(name);
  9370. if (isDefined(value)) {
  9371. element.style[name] = value;
  9372. } else {
  9373. var val;
  9374. if (msie <= 8) {
  9375. // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
  9376. val = element.currentStyle && element.currentStyle[name];
  9377. if (val === '') val = 'auto';
  9378. }
  9379. val = val || element.style[name];
  9380. if (msie <= 8) {
  9381. // jquery weirdness :-/
  9382. val = (val === '') ? undefined : val;
  9383. }
  9384. return val;
  9385. }
  9386. },
  9387. attr: function(element, name, value){
  9388. var lowercasedName = lowercase(name);
  9389. if (BOOLEAN_ATTR[lowercasedName]) {
  9390. if (isDefined(value)) {
  9391. if (!!value) {
  9392. element[name] = true;
  9393. element.setAttribute(name, lowercasedName);
  9394. } else {
  9395. element[name] = false;
  9396. element.removeAttribute(lowercasedName);
  9397. }
  9398. } else {
  9399. return (element[name] ||
  9400. (element.attributes.getNamedItem(name)|| noop).specified)
  9401. ? lowercasedName
  9402. : undefined;
  9403. }
  9404. } else if (isDefined(value)) {
  9405. element.setAttribute(name, value);
  9406. } else if (element.getAttribute) {
  9407. // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
  9408. // some elements (e.g. Document) don't have get attribute, so return undefined
  9409. var ret = element.getAttribute(name, 2);
  9410. // normalize non-existing attributes to undefined (as jQuery)
  9411. return ret === null ? undefined : ret;
  9412. }
  9413. },
  9414. prop: function(element, name, value) {
  9415. if (isDefined(value)) {
  9416. element[name] = value;
  9417. } else {
  9418. return element[name];
  9419. }
  9420. },
  9421. text: extend((msie < 9)
  9422. ? function(element, value) {
  9423. if (element.nodeType == 1 /** Element */) {
  9424. if (isUndefined(value))
  9425. return element.innerText;
  9426. element.innerText = value;
  9427. } else {
  9428. if (isUndefined(value))
  9429. return element.nodeValue;
  9430. element.nodeValue = value;
  9431. }
  9432. }
  9433. : function(element, value) {
  9434. if (isUndefined(value)) {
  9435. return element.textContent;
  9436. }
  9437. element.textContent = value;
  9438. }, {$dv:''}),
  9439. val: function(element, value) {
  9440. if (isUndefined(value)) {
  9441. return element.value;
  9442. }
  9443. element.value = value;
  9444. },
  9445. html: function(element, value) {
  9446. if (isUndefined(value)) {
  9447. return element.innerHTML;
  9448. }
  9449. for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
  9450. JQLiteDealoc(childNodes[i]);
  9451. }
  9452. element.innerHTML = value;
  9453. }
  9454. }, function(fn, name){
  9455. /**
  9456. * Properties: writes return selection, reads return first value
  9457. */
  9458. JQLite.prototype[name] = function(arg1, arg2) {
  9459. var i, key;
  9460. // JQLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
  9461. // in a way that survives minification.
  9462. if (((fn.length == 2 && (fn !== JQLiteHasClass && fn !== JQLiteController)) ? arg1 : arg2) === undefined) {
  9463. if (isObject(arg1)) {
  9464. // we are a write, but the object properties are the key/values
  9465. for(i=0; i < this.length; i++) {
  9466. if (fn === JQLiteData) {
  9467. // data() takes the whole object in jQuery
  9468. fn(this[i], arg1);
  9469. } else {
  9470. for (key in arg1) {
  9471. fn(this[i], key, arg1[key]);
  9472. }
  9473. }
  9474. }
  9475. // return self for chaining
  9476. return this;
  9477. } else {
  9478. // we are a read, so read the first child.
  9479. if (this.length)
  9480. return fn(this[0], arg1, arg2);
  9481. }
  9482. } else {
  9483. // we are a write, so apply to all children
  9484. for(i=0; i < this.length; i++) {
  9485. fn(this[i], arg1, arg2);
  9486. }
  9487. // return self for chaining
  9488. return this;
  9489. }
  9490. return fn.$dv;
  9491. };
  9492. });
  9493. function createEventHandler(element, events) {
  9494. var eventHandler = function (event, type) {
  9495. if (!event.preventDefault) {
  9496. event.preventDefault = function() {
  9497. event.returnValue = false; //ie
  9498. };
  9499. }
  9500. if (!event.stopPropagation) {
  9501. event.stopPropagation = function() {
  9502. event.cancelBubble = true; //ie
  9503. };
  9504. }
  9505. if (!event.target) {
  9506. event.target = event.srcElement || document;
  9507. }
  9508. if (isUndefined(event.defaultPrevented)) {
  9509. var prevent = event.preventDefault;
  9510. event.preventDefault = function() {
  9511. event.defaultPrevented = true;
  9512. prevent.call(event);
  9513. };
  9514. event.defaultPrevented = false;
  9515. }
  9516. event.isDefaultPrevented = function() {
  9517. return event.defaultPrevented;
  9518. };
  9519. forEach(events[type || event.type], function(fn) {
  9520. fn.call(element, event);
  9521. });
  9522. // Remove monkey-patched methods (IE),
  9523. // as they would cause memory leaks in IE8.
  9524. if (msie <= 8) {
  9525. // IE7/8 does not allow to delete property on native object
  9526. event.preventDefault = null;
  9527. event.stopPropagation = null;
  9528. event.isDefaultPrevented = null;
  9529. } else {
  9530. // It shouldn't affect normal browsers (native methods are defined on prototype).
  9531. delete event.preventDefault;
  9532. delete event.stopPropagation;
  9533. delete event.isDefaultPrevented;
  9534. }
  9535. };
  9536. eventHandler.elem = element;
  9537. return eventHandler;
  9538. }
  9539. //////////////////////////////////////////
  9540. // Functions iterating traversal.
  9541. // These functions chain results into a single
  9542. // selector.
  9543. //////////////////////////////////////////
  9544. forEach({
  9545. removeData: JQLiteRemoveData,
  9546. dealoc: JQLiteDealoc,
  9547. bind: function bindFn(element, type, fn){
  9548. var events = JQLiteExpandoStore(element, 'events'),
  9549. handle = JQLiteExpandoStore(element, 'handle');
  9550. if (!events) JQLiteExpandoStore(element, 'events', events = {});
  9551. if (!handle) JQLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
  9552. forEach(type.split(' '), function(type){
  9553. var eventFns = events[type];
  9554. if (!eventFns) {
  9555. if (type == 'mouseenter' || type == 'mouseleave') {
  9556. var counter = 0;
  9557. events.mouseenter = [];
  9558. events.mouseleave = [];
  9559. bindFn(element, 'mouseover', function(event) {
  9560. counter++;
  9561. if (counter == 1) {
  9562. handle(event, 'mouseenter');
  9563. }
  9564. });
  9565. bindFn(element, 'mouseout', function(event) {
  9566. counter --;
  9567. if (counter == 0) {
  9568. handle(event, 'mouseleave');
  9569. }
  9570. });
  9571. } else {
  9572. addEventListenerFn(element, type, handle);
  9573. events[type] = [];
  9574. }
  9575. eventFns = events[type]
  9576. }
  9577. eventFns.push(fn);
  9578. });
  9579. },
  9580. unbind: JQLiteUnbind,
  9581. replaceWith: function(element, replaceNode) {
  9582. var index, parent = element.parentNode;
  9583. JQLiteDealoc(element);
  9584. forEach(new JQLite(replaceNode), function(node){
  9585. if (index) {
  9586. parent.insertBefore(node, index.nextSibling);
  9587. } else {
  9588. parent.replaceChild(node, element);
  9589. }
  9590. index = node;
  9591. });
  9592. },
  9593. children: function(element) {
  9594. var children = [];
  9595. forEach(element.childNodes, function(element){
  9596. if (element.nodeType === 1)
  9597. children.push(element);
  9598. });
  9599. return children;
  9600. },
  9601. contents: function(element) {
  9602. return element.childNodes || [];
  9603. },
  9604. append: function(element, node) {
  9605. forEach(new JQLite(node), function(child){
  9606. if (element.nodeType === 1)
  9607. element.appendChild(child);
  9608. });
  9609. },
  9610. prepend: function(element, node) {
  9611. if (element.nodeType === 1) {
  9612. var index = element.firstChild;
  9613. forEach(new JQLite(node), function(child){
  9614. if (index) {
  9615. element.insertBefore(child, index);
  9616. } else {
  9617. element.appendChild(child);
  9618. index = child;
  9619. }
  9620. });
  9621. }
  9622. },
  9623. wrap: function(element, wrapNode) {
  9624. wrapNode = jqLite(wrapNode)[0];
  9625. var parent = element.parentNode;
  9626. if (parent) {
  9627. parent.replaceChild(wrapNode, element);
  9628. }
  9629. wrapNode.appendChild(element);
  9630. },
  9631. remove: function(element) {
  9632. JQLiteDealoc(element);
  9633. var parent = element.parentNode;
  9634. if (parent) parent.removeChild(element);
  9635. },
  9636. after: function(element, newElement) {
  9637. var index = element, parent = element.parentNode;
  9638. forEach(new JQLite(newElement), function(node){
  9639. parent.insertBefore(node, index.nextSibling);
  9640. index = node;
  9641. });
  9642. },
  9643. addClass: JQLiteAddClass,
  9644. removeClass: JQLiteRemoveClass,
  9645. toggleClass: function(element, selector, condition) {
  9646. if (isUndefined(condition)) {
  9647. condition = !JQLiteHasClass(element, selector);
  9648. }
  9649. (condition ? JQLiteAddClass : JQLiteRemoveClass)(element, selector);
  9650. },
  9651. parent: function(element) {
  9652. var parent = element.parentNode;
  9653. return parent && parent.nodeType !== 11 ? parent : null;
  9654. },
  9655. next: function(element) {
  9656. if (element.nextElementSibling) {
  9657. return element.nextElementSibling;
  9658. }
  9659. // IE8 doesn't have nextElementSibling
  9660. var elm = element.nextSibling;
  9661. while (elm != null && elm.nodeType !== 1) {
  9662. elm = elm.nextSibling;
  9663. }
  9664. return elm;
  9665. },
  9666. find: function(element, selector) {
  9667. return element.getElementsByTagName(selector);
  9668. },
  9669. clone: JQLiteClone,
  9670. triggerHandler: function(element, eventName) {
  9671. var eventFns = (JQLiteExpandoStore(element, 'events') || {})[eventName];
  9672. forEach(eventFns, function(fn) {
  9673. fn.call(element, null);
  9674. });
  9675. }
  9676. }, function(fn, name){
  9677. /**
  9678. * chaining functions
  9679. */
  9680. JQLite.prototype[name] = function(arg1, arg2) {
  9681. var value;
  9682. for(var i=0; i < this.length; i++) {
  9683. if (value == undefined) {
  9684. value = fn(this[i], arg1, arg2);
  9685. if (value !== undefined) {
  9686. // any function which returns a value needs to be wrapped
  9687. value = jqLite(value);
  9688. }
  9689. } else {
  9690. JQLiteAddNodes(value, fn(this[i], arg1, arg2));
  9691. }
  9692. }
  9693. return value == undefined ? this : value;
  9694. };
  9695. });
  9696. /**
  9697. * Computes a hash of an 'obj'.
  9698. * Hash of a:
  9699. * string is string
  9700. * number is number as string
  9701. * object is either result of calling $$hashKey function on the object or uniquely generated id,
  9702. * that is also assigned to the $$hashKey property of the object.
  9703. *
  9704. * @param obj
  9705. * @returns {string} hash string such that the same input will have the same hash string.
  9706. * The resulting string key is in 'type:hashKey' format.
  9707. */
  9708. function hashKey(obj) {
  9709. var objType = typeof obj,
  9710. key;
  9711. if (objType == 'object' && obj !== null) {
  9712. if (typeof (key = obj.$$hashKey) == 'function') {
  9713. // must invoke on object to keep the right this
  9714. key = obj.$$hashKey();
  9715. } else if (key === undefined) {
  9716. key = obj.$$hashKey = nextUid();
  9717. }
  9718. } else {
  9719. key = obj;
  9720. }
  9721. return objType + ':' + key;
  9722. }
  9723. /**
  9724. * HashMap which can use objects as keys
  9725. */
  9726. function HashMap(array){
  9727. forEach(array, this.put, this);
  9728. }
  9729. HashMap.prototype = {
  9730. /**
  9731. * Store key value pair
  9732. * @param key key to store can be any type
  9733. * @param value value to store can be any type
  9734. */
  9735. put: function(key, value) {
  9736. this[hashKey(key)] = value;
  9737. },
  9738. /**
  9739. * @param key
  9740. * @returns the value for the key
  9741. */
  9742. get: function(key) {
  9743. return this[hashKey(key)];
  9744. },
  9745. /**
  9746. * Remove the key/value pair
  9747. * @param key
  9748. */
  9749. remove: function(key) {
  9750. var value = this[key = hashKey(key)];
  9751. delete this[key];
  9752. return value;
  9753. }
  9754. };
  9755. /**
  9756. * A map where multiple values can be added to the same key such that they form a queue.
  9757. * @returns {HashQueueMap}
  9758. */
  9759. function HashQueueMap() {}
  9760. HashQueueMap.prototype = {
  9761. /**
  9762. * Same as array push, but using an array as the value for the hash
  9763. */
  9764. push: function(key, value) {
  9765. var array = this[key = hashKey(key)];
  9766. if (!array) {
  9767. this[key] = [value];
  9768. } else {
  9769. array.push(value);
  9770. }
  9771. },
  9772. /**
  9773. * Same as array shift, but using an array as the value for the hash
  9774. */
  9775. shift: function(key) {
  9776. var array = this[key = hashKey(key)];
  9777. if (array) {
  9778. if (array.length == 1) {
  9779. delete this[key];
  9780. return array[0];
  9781. } else {
  9782. return array.shift();
  9783. }
  9784. }
  9785. },
  9786. /**
  9787. * return the first item without deleting it
  9788. */
  9789. peek: function(key) {
  9790. var array = this[hashKey(key)];
  9791. if (array) {
  9792. return array[0];
  9793. }
  9794. }
  9795. };
  9796. /**
  9797. * @ngdoc function
  9798. * @name angular.injector
  9799. * @function
  9800. *
  9801. * @description
  9802. * Creates an injector function that can be used for retrieving services as well as for
  9803. * dependency injection (see {@link guide/di dependency injection}).
  9804. *
  9805. * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
  9806. * {@link angular.module}. The `ng` module must be explicitly added.
  9807. * @returns {function()} Injector function. See {@link AUTO.$injector $injector}.
  9808. *
  9809. * @example
  9810. * Typical usage
  9811. * <pre>
  9812. * // create an injector
  9813. * var $injector = angular.injector(['ng']);
  9814. *
  9815. * // use the injector to kick off your application
  9816. * // use the type inference to auto inject arguments, or use implicit injection
  9817. * $injector.invoke(function($rootScope, $compile, $document){
  9818. * $compile($document)($rootScope);
  9819. * $rootScope.$digest();
  9820. * });
  9821. * </pre>
  9822. */
  9823. /**
  9824. * @ngdoc overview
  9825. * @name AUTO
  9826. * @description
  9827. *
  9828. * Implicit module which gets automatically added to each {@link AUTO.$injector $injector}.
  9829. */
  9830. var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
  9831. var FN_ARG_SPLIT = /,/;
  9832. var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
  9833. var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
  9834. function annotate(fn) {
  9835. var $inject,
  9836. fnText,
  9837. argDecl,
  9838. last;
  9839. if (typeof fn == 'function') {
  9840. if (!($inject = fn.$inject)) {
  9841. $inject = [];
  9842. fnText = fn.toString().replace(STRIP_COMMENTS, '');
  9843. argDecl = fnText.match(FN_ARGS);
  9844. forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
  9845. arg.replace(FN_ARG, function(all, underscore, name){
  9846. $inject.push(name);
  9847. });
  9848. });
  9849. fn.$inject = $inject;
  9850. }
  9851. } else if (isArray(fn)) {
  9852. last = fn.length - 1;
  9853. assertArgFn(fn[last], 'fn')
  9854. $inject = fn.slice(0, last);
  9855. } else {
  9856. assertArgFn(fn, 'fn', true);
  9857. }
  9858. return $inject;
  9859. }
  9860. ///////////////////////////////////////
  9861. /**
  9862. * @ngdoc object
  9863. * @name AUTO.$injector
  9864. * @function
  9865. *
  9866. * @description
  9867. *
  9868. * `$injector` is used to retrieve object instances as defined by
  9869. * {@link AUTO.$provide provider}, instantiate types, invoke methods,
  9870. * and load modules.
  9871. *
  9872. * The following always holds true:
  9873. *
  9874. * <pre>
  9875. * var $injector = angular.injector();
  9876. * expect($injector.get('$injector')).toBe($injector);
  9877. * expect($injector.invoke(function($injector){
  9878. * return $injector;
  9879. * }).toBe($injector);
  9880. * </pre>
  9881. *
  9882. * # Injection Function Annotation
  9883. *
  9884. * JavaScript does not have annotations, and annotations are needed for dependency injection. The
  9885. * following ways are all valid way of annotating function with injection arguments and are equivalent.
  9886. *
  9887. * <pre>
  9888. * // inferred (only works if code not minified/obfuscated)
  9889. * $injector.invoke(function(serviceA){});
  9890. *
  9891. * // annotated
  9892. * function explicit(serviceA) {};
  9893. * explicit.$inject = ['serviceA'];
  9894. * $injector.invoke(explicit);
  9895. *
  9896. * // inline
  9897. * $injector.invoke(['serviceA', function(serviceA){}]);
  9898. * </pre>
  9899. *
  9900. * ## Inference
  9901. *
  9902. * In JavaScript calling `toString()` on a function returns the function definition. The definition can then be
  9903. * parsed and the function arguments can be extracted. *NOTE:* This does not work with minification, and obfuscation
  9904. * tools since these tools change the argument names.
  9905. *
  9906. * ## `$inject` Annotation
  9907. * By adding a `$inject` property onto a function the injection parameters can be specified.
  9908. *
  9909. * ## Inline
  9910. * As an array of injection names, where the last item in the array is the function to call.
  9911. */
  9912. /**
  9913. * @ngdoc method
  9914. * @name AUTO.$injector#get
  9915. * @methodOf AUTO.$injector
  9916. *
  9917. * @description
  9918. * Return an instance of the service.
  9919. *
  9920. * @param {string} name The name of the instance to retrieve.
  9921. * @return {*} The instance.
  9922. */
  9923. /**
  9924. * @ngdoc method
  9925. * @name AUTO.$injector#invoke
  9926. * @methodOf AUTO.$injector
  9927. *
  9928. * @description
  9929. * Invoke the method and supply the method arguments from the `$injector`.
  9930. *
  9931. * @param {!function} fn The function to invoke. The function arguments come form the function annotation.
  9932. * @param {Object=} self The `this` for the invoked method.
  9933. * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
  9934. * the `$injector` is consulted.
  9935. * @returns {*} the value returned by the invoked `fn` function.
  9936. */
  9937. /**
  9938. * @ngdoc method
  9939. * @name AUTO.$injector#instantiate
  9940. * @methodOf AUTO.$injector
  9941. * @description
  9942. * Create a new instance of JS type. The method takes a constructor function invokes the new operator and supplies
  9943. * all of the arguments to the constructor function as specified by the constructor annotation.
  9944. *
  9945. * @param {function} Type Annotated constructor function.
  9946. * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
  9947. * the `$injector` is consulted.
  9948. * @returns {Object} new instance of `Type`.
  9949. */
  9950. /**
  9951. * @ngdoc method
  9952. * @name AUTO.$injector#annotate
  9953. * @methodOf AUTO.$injector
  9954. *
  9955. * @description
  9956. * Returns an array of service names which the function is requesting for injection. This API is used by the injector
  9957. * to determine which services need to be injected into the function when the function is invoked. There are three
  9958. * ways in which the function can be annotated with the needed dependencies.
  9959. *
  9960. * # Argument names
  9961. *
  9962. * The simplest form is to extract the dependencies from the arguments of the function. This is done by converting
  9963. * the function into a string using `toString()` method and extracting the argument names.
  9964. * <pre>
  9965. * // Given
  9966. * function MyController($scope, $route) {
  9967. * // ...
  9968. * }
  9969. *
  9970. * // Then
  9971. * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
  9972. * </pre>
  9973. *
  9974. * This method does not work with code minfication / obfuscation. For this reason the following annotation strategies
  9975. * are supported.
  9976. *
  9977. * # The `$inject` property
  9978. *
  9979. * If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
  9980. * services to be injected into the function.
  9981. * <pre>
  9982. * // Given
  9983. * var MyController = function(obfuscatedScope, obfuscatedRoute) {
  9984. * // ...
  9985. * }
  9986. * // Define function dependencies
  9987. * MyController.$inject = ['$scope', '$route'];
  9988. *
  9989. * // Then
  9990. * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
  9991. * </pre>
  9992. *
  9993. * # The array notation
  9994. *
  9995. * It is often desirable to inline Injected functions and that's when setting the `$inject` property is very
  9996. * inconvenient. In these situations using the array notation to specify the dependencies in a way that survives
  9997. * minification is a better choice:
  9998. *
  9999. * <pre>
  10000. * // We wish to write this (not minification / obfuscation safe)
  10001. * injector.invoke(function($compile, $rootScope) {
  10002. * // ...
  10003. * });
  10004. *
  10005. * // We are forced to write break inlining
  10006. * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
  10007. * // ...
  10008. * };
  10009. * tmpFn.$inject = ['$compile', '$rootScope'];
  10010. * injector.invoke(tempFn);
  10011. *
  10012. * // To better support inline function the inline annotation is supported
  10013. * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
  10014. * // ...
  10015. * }]);
  10016. *
  10017. * // Therefore
  10018. * expect(injector.annotate(
  10019. * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
  10020. * ).toEqual(['$compile', '$rootScope']);
  10021. * </pre>
  10022. *
  10023. * @param {function|Array.<string|Function>} fn Function for which dependent service names need to be retrieved as described
  10024. * above.
  10025. *
  10026. * @returns {Array.<string>} The names of the services which the function requires.
  10027. */
  10028. /**
  10029. * @ngdoc object
  10030. * @name AUTO.$provide
  10031. *
  10032. * @description
  10033. *
  10034. * Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance.
  10035. * The providers share the same name as the instance they create with `Provider` suffixed to them.
  10036. *
  10037. * A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of
  10038. * a service. The Provider can have additional methods which would allow for configuration of the provider.
  10039. *
  10040. * <pre>
  10041. * function GreetProvider() {
  10042. * var salutation = 'Hello';
  10043. *
  10044. * this.salutation = function(text) {
  10045. * salutation = text;
  10046. * };
  10047. *
  10048. * this.$get = function() {
  10049. * return function (name) {
  10050. * return salutation + ' ' + name + '!';
  10051. * };
  10052. * };
  10053. * }
  10054. *
  10055. * describe('Greeter', function(){
  10056. *
  10057. * beforeEach(module(function($provide) {
  10058. * $provide.provider('greet', GreetProvider);
  10059. * });
  10060. *
  10061. * it('should greet', inject(function(greet) {
  10062. * expect(greet('angular')).toEqual('Hello angular!');
  10063. * }));
  10064. *
  10065. * it('should allow configuration of salutation', function() {
  10066. * module(function(greetProvider) {
  10067. * greetProvider.salutation('Ahoj');
  10068. * });
  10069. * inject(function(greet) {
  10070. * expect(greet('angular')).toEqual('Ahoj angular!');
  10071. * });
  10072. * )};
  10073. *
  10074. * });
  10075. * </pre>
  10076. */
  10077. /**
  10078. * @ngdoc method
  10079. * @name AUTO.$provide#provider
  10080. * @methodOf AUTO.$provide
  10081. * @description
  10082. *
  10083. * Register a provider for a service. The providers can be retrieved and can have additional configuration methods.
  10084. *
  10085. * @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provider'` key.
  10086. * @param {(Object|function())} provider If the provider is:
  10087. *
  10088. * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
  10089. * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
  10090. * - `Constructor`: a new instance of the provider will be created using
  10091. * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
  10092. *
  10093. * @returns {Object} registered provider instance
  10094. */
  10095. /**
  10096. * @ngdoc method
  10097. * @name AUTO.$provide#factory
  10098. * @methodOf AUTO.$provide
  10099. * @description
  10100. *
  10101. * A short hand for configuring services if only `$get` method is required.
  10102. *
  10103. * @param {string} name The name of the instance.
  10104. * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand for
  10105. * `$provide.provider(name, {$get: $getFn})`.
  10106. * @returns {Object} registered provider instance
  10107. */
  10108. /**
  10109. * @ngdoc method
  10110. * @name AUTO.$provide#service
  10111. * @methodOf AUTO.$provide
  10112. * @description
  10113. *
  10114. * A short hand for registering service of given class.
  10115. *
  10116. * @param {string} name The name of the instance.
  10117. * @param {Function} constructor A class (constructor function) that will be instantiated.
  10118. * @returns {Object} registered provider instance
  10119. */
  10120. /**
  10121. * @ngdoc method
  10122. * @name AUTO.$provide#value
  10123. * @methodOf AUTO.$provide
  10124. * @description
  10125. *
  10126. * A short hand for configuring services if the `$get` method is a constant.
  10127. *
  10128. * @param {string} name The name of the instance.
  10129. * @param {*} value The value.
  10130. * @returns {Object} registered provider instance
  10131. */
  10132. /**
  10133. * @ngdoc method
  10134. * @name AUTO.$provide#constant
  10135. * @methodOf AUTO.$provide
  10136. * @description
  10137. *
  10138. * A constant value, but unlike {@link AUTO.$provide#value value} it can be injected
  10139. * into configuration function (other modules) and it is not interceptable by
  10140. * {@link AUTO.$provide#decorator decorator}.
  10141. *
  10142. * @param {string} name The name of the constant.
  10143. * @param {*} value The constant value.
  10144. * @returns {Object} registered instance
  10145. */
  10146. /**
  10147. * @ngdoc method
  10148. * @name AUTO.$provide#decorator
  10149. * @methodOf AUTO.$provide
  10150. * @description
  10151. *
  10152. * Decoration of service, allows the decorator to intercept the service instance creation. The
  10153. * returned instance may be the original instance, or a new instance which delegates to the
  10154. * original instance.
  10155. *
  10156. * @param {string} name The name of the service to decorate.
  10157. * @param {function()} decorator This function will be invoked when the service needs to be
  10158. * instanciated. The function is called using the {@link AUTO.$injector#invoke
  10159. * injector.invoke} method and is therefore fully injectable. Local injection arguments:
  10160. *
  10161. * * `$delegate` - The original service instance, which can be monkey patched, configured,
  10162. * decorated or delegated to.
  10163. */
  10164. function createInjector(modulesToLoad) {
  10165. var INSTANTIATING = {},
  10166. providerSuffix = 'Provider',
  10167. path = [],
  10168. loadedModules = new HashMap(),
  10169. providerCache = {
  10170. $provide: {
  10171. provider: supportObject(provider),
  10172. factory: supportObject(factory),
  10173. service: supportObject(service),
  10174. value: supportObject(value),
  10175. constant: supportObject(constant),
  10176. decorator: decorator
  10177. }
  10178. },
  10179. providerInjector = createInternalInjector(providerCache, function() {
  10180. throw Error("Unknown provider: " + path.join(' <- '));
  10181. }),
  10182. instanceCache = {},
  10183. instanceInjector = (instanceCache.$injector =
  10184. createInternalInjector(instanceCache, function(servicename) {
  10185. var provider = providerInjector.get(servicename + providerSuffix);
  10186. return instanceInjector.invoke(provider.$get, provider);
  10187. }));
  10188. forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
  10189. return instanceInjector;
  10190. ////////////////////////////////////
  10191. // $provider
  10192. ////////////////////////////////////
  10193. function supportObject(delegate) {
  10194. return function(key, value) {
  10195. if (isObject(key)) {
  10196. forEach(key, reverseParams(delegate));
  10197. } else {
  10198. return delegate(key, value);
  10199. }
  10200. }
  10201. }
  10202. function provider(name, provider_) {
  10203. if (isFunction(provider_) || isArray(provider_)) {
  10204. provider_ = providerInjector.instantiate(provider_);
  10205. }
  10206. if (!provider_.$get) {
  10207. throw Error('Provider ' + name + ' must define $get factory method.');
  10208. }
  10209. return providerCache[name + providerSuffix] = provider_;
  10210. }
  10211. function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
  10212. function service(name, constructor) {
  10213. return factory(name, ['$injector', function($injector) {
  10214. return $injector.instantiate(constructor);
  10215. }]);
  10216. }
  10217. function value(name, value) { return factory(name, valueFn(value)); }
  10218. function constant(name, value) {
  10219. providerCache[name] = value;
  10220. instanceCache[name] = value;
  10221. }
  10222. function decorator(serviceName, decorFn) {
  10223. var origProvider = providerInjector.get(serviceName + providerSuffix),
  10224. orig$get = origProvider.$get;
  10225. origProvider.$get = function() {
  10226. var origInstance = instanceInjector.invoke(orig$get, origProvider);
  10227. return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
  10228. };
  10229. }
  10230. ////////////////////////////////////
  10231. // Module Loading
  10232. ////////////////////////////////////
  10233. function loadModules(modulesToLoad){
  10234. var runBlocks = [];
  10235. forEach(modulesToLoad, function(module) {
  10236. if (loadedModules.get(module)) return;
  10237. loadedModules.put(module, true);
  10238. if (isString(module)) {
  10239. var moduleFn = angularModule(module);
  10240. runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
  10241. try {
  10242. for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
  10243. var invokeArgs = invokeQueue[i],
  10244. provider = invokeArgs[0] == '$injector'
  10245. ? providerInjector
  10246. : providerInjector.get(invokeArgs[0]);
  10247. provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
  10248. }
  10249. } catch (e) {
  10250. if (e.message) e.message += ' from ' + module;
  10251. throw e;
  10252. }
  10253. } else if (isFunction(module)) {
  10254. try {
  10255. runBlocks.push(providerInjector.invoke(module));
  10256. } catch (e) {
  10257. if (e.message) e.message += ' from ' + module;
  10258. throw e;
  10259. }
  10260. } else if (isArray(module)) {
  10261. try {
  10262. runBlocks.push(providerInjector.invoke(module));
  10263. } catch (e) {
  10264. if (e.message) e.message += ' from ' + String(module[module.length - 1]);
  10265. throw e;
  10266. }
  10267. } else {
  10268. assertArgFn(module, 'module');
  10269. }
  10270. });
  10271. return runBlocks;
  10272. }
  10273. ////////////////////////////////////
  10274. // internal Injector
  10275. ////////////////////////////////////
  10276. function createInternalInjector(cache, factory) {
  10277. function getService(serviceName) {
  10278. if (typeof serviceName !== 'string') {
  10279. throw Error('Service name expected');
  10280. }
  10281. if (cache.hasOwnProperty(serviceName)) {
  10282. if (cache[serviceName] === INSTANTIATING) {
  10283. throw Error('Circular dependency: ' + path.join(' <- '));
  10284. }
  10285. return cache[serviceName];
  10286. } else {
  10287. try {
  10288. path.unshift(serviceName);
  10289. cache[serviceName] = INSTANTIATING;
  10290. return cache[serviceName] = factory(serviceName);
  10291. } finally {
  10292. path.shift();
  10293. }
  10294. }
  10295. }
  10296. function invoke(fn, self, locals){
  10297. var args = [],
  10298. $inject = annotate(fn),
  10299. length, i,
  10300. key;
  10301. for(i = 0, length = $inject.length; i < length; i++) {
  10302. key = $inject[i];
  10303. args.push(
  10304. locals && locals.hasOwnProperty(key)
  10305. ? locals[key]
  10306. : getService(key)
  10307. );
  10308. }
  10309. if (!fn.$inject) {
  10310. // this means that we must be an array.
  10311. fn = fn[length];
  10312. }
  10313. // Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke
  10314. switch (self ? -1 : args.length) {
  10315. case 0: return fn();
  10316. case 1: return fn(args[0]);
  10317. case 2: return fn(args[0], args[1]);
  10318. case 3: return fn(args[0], args[1], args[2]);
  10319. case 4: return fn(args[0], args[1], args[2], args[3]);
  10320. case 5: return fn(args[0], args[1], args[2], args[3], args[4]);
  10321. case 6: return fn(args[0], args[1], args[2], args[3], args[4], args[5]);
  10322. case 7: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
  10323. case 8: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
  10324. case 9: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
  10325. case 10: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
  10326. default: return fn.apply(self, args);
  10327. }
  10328. }
  10329. function instantiate(Type, locals) {
  10330. var Constructor = function() {},
  10331. instance, returnedValue;
  10332. Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
  10333. instance = new Constructor();
  10334. returnedValue = invoke(Type, instance, locals);
  10335. return isObject(returnedValue) ? returnedValue : instance;
  10336. }
  10337. return {
  10338. invoke: invoke,
  10339. instantiate: instantiate,
  10340. get: getService,
  10341. annotate: annotate
  10342. };
  10343. }
  10344. }
  10345. /**
  10346. * @ngdoc function
  10347. * @name ng.$anchorScroll
  10348. * @requires $window
  10349. * @requires $location
  10350. * @requires $rootScope
  10351. *
  10352. * @description
  10353. * When called, it checks current value of `$location.hash()` and scroll to related element,
  10354. * according to rules specified in
  10355. * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}.
  10356. *
  10357. * It also watches the `$location.hash()` and scroll whenever it changes to match any anchor.
  10358. * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
  10359. */
  10360. function $AnchorScrollProvider() {
  10361. var autoScrollingEnabled = true;
  10362. this.disableAutoScrolling = function() {
  10363. autoScrollingEnabled = false;
  10364. };
  10365. this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
  10366. var document = $window.document;
  10367. // helper function to get first anchor from a NodeList
  10368. // can't use filter.filter, as it accepts only instances of Array
  10369. // and IE can't convert NodeList to an array using [].slice
  10370. // TODO(vojta): use filter if we change it to accept lists as well
  10371. function getFirstAnchor(list) {
  10372. var result = null;
  10373. forEach(list, function(element) {
  10374. if (!result && lowercase(element.nodeName) === 'a') result = element;
  10375. });
  10376. return result;
  10377. }
  10378. function scroll() {
  10379. var hash = $location.hash(), elm;
  10380. // empty hash, scroll to the top of the page
  10381. if (!hash) $window.scrollTo(0, 0);
  10382. // element with given id
  10383. else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
  10384. // first anchor with given name :-D
  10385. else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
  10386. // no element and hash == 'top', scroll to the top of the page
  10387. else if (hash === 'top') $window.scrollTo(0, 0);
  10388. }
  10389. // does not scroll when user clicks on anchor link that is currently on
  10390. // (no url change, no $location.hash() change), browser native does scroll
  10391. if (autoScrollingEnabled) {
  10392. $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
  10393. function autoScrollWatchAction() {
  10394. $rootScope.$evalAsync(scroll);
  10395. });
  10396. }
  10397. return scroll;
  10398. }];
  10399. }
  10400. /**
  10401. * ! This is a private undocumented service !
  10402. *
  10403. * @name ng.$browser
  10404. * @requires $log
  10405. * @description
  10406. * This object has two goals:
  10407. *
  10408. * - hide all the global state in the browser caused by the window object
  10409. * - abstract away all the browser specific features and inconsistencies
  10410. *
  10411. * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
  10412. * service, which can be used for convenient testing of the application without the interaction with
  10413. * the real browser apis.
  10414. */
  10415. /**
  10416. * @param {object} window The global window object.
  10417. * @param {object} document jQuery wrapped document.
  10418. * @param {function()} XHR XMLHttpRequest constructor.
  10419. * @param {object} $log console.log or an object with the same interface.
  10420. * @param {object} $sniffer $sniffer service
  10421. */
  10422. function Browser(window, document, $log, $sniffer) {
  10423. var self = this,
  10424. rawDocument = document[0],
  10425. location = window.location,
  10426. history = window.history,
  10427. setTimeout = window.setTimeout,
  10428. clearTimeout = window.clearTimeout,
  10429. pendingDeferIds = {};
  10430. self.isMock = false;
  10431. var outstandingRequestCount = 0;
  10432. var outstandingRequestCallbacks = [];
  10433. // TODO(vojta): remove this temporary api
  10434. self.$$completeOutstandingRequest = completeOutstandingRequest;
  10435. self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
  10436. /**
  10437. * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
  10438. * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
  10439. */
  10440. function completeOutstandingRequest(fn) {
  10441. try {
  10442. fn.apply(null, sliceArgs(arguments, 1));
  10443. } finally {
  10444. outstandingRequestCount--;
  10445. if (outstandingRequestCount === 0) {
  10446. while(outstandingRequestCallbacks.length) {
  10447. try {
  10448. outstandingRequestCallbacks.pop()();
  10449. } catch (e) {
  10450. $log.error(e);
  10451. }
  10452. }
  10453. }
  10454. }
  10455. }
  10456. /**
  10457. * @private
  10458. * Note: this method is used only by scenario runner
  10459. * TODO(vojta): prefix this method with $$ ?
  10460. * @param {function()} callback Function that will be called when no outstanding request
  10461. */
  10462. self.notifyWhenNoOutstandingRequests = function(callback) {
  10463. // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
  10464. // at some deterministic time in respect to the test runner's actions. Leaving things up to the
  10465. // regular poller would result in flaky tests.
  10466. forEach(pollFns, function(pollFn){ pollFn(); });
  10467. if (outstandingRequestCount === 0) {
  10468. callback();
  10469. } else {
  10470. outstandingRequestCallbacks.push(callback);
  10471. }
  10472. };
  10473. //////////////////////////////////////////////////////////////
  10474. // Poll Watcher API
  10475. //////////////////////////////////////////////////////////////
  10476. var pollFns = [],
  10477. pollTimeout;
  10478. /**
  10479. * @name ng.$browser#addPollFn
  10480. * @methodOf ng.$browser
  10481. *
  10482. * @param {function()} fn Poll function to add
  10483. *
  10484. * @description
  10485. * Adds a function to the list of functions that poller periodically executes,
  10486. * and starts polling if not started yet.
  10487. *
  10488. * @returns {function()} the added function
  10489. */
  10490. self.addPollFn = function(fn) {
  10491. if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
  10492. pollFns.push(fn);
  10493. return fn;
  10494. };
  10495. /**
  10496. * @param {number} interval How often should browser call poll functions (ms)
  10497. * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
  10498. *
  10499. * @description
  10500. * Configures the poller to run in the specified intervals, using the specified
  10501. * setTimeout fn and kicks it off.
  10502. */
  10503. function startPoller(interval, setTimeout) {
  10504. (function check() {
  10505. forEach(pollFns, function(pollFn){ pollFn(); });
  10506. pollTimeout = setTimeout(check, interval);
  10507. })();
  10508. }
  10509. //////////////////////////////////////////////////////////////
  10510. // URL API
  10511. //////////////////////////////////////////////////////////////
  10512. var lastBrowserUrl = location.href,
  10513. baseElement = document.find('base');
  10514. /**
  10515. * @name ng.$browser#url
  10516. * @methodOf ng.$browser
  10517. *
  10518. * @description
  10519. * GETTER:
  10520. * Without any argument, this method just returns current value of location.href.
  10521. *
  10522. * SETTER:
  10523. * With at least one argument, this method sets url to new value.
  10524. * If html5 history api supported, pushState/replaceState is used, otherwise
  10525. * location.href/location.replace is used.
  10526. * Returns its own instance to allow chaining
  10527. *
  10528. * NOTE: this api is intended for use only by the $location service. Please use the
  10529. * {@link ng.$location $location service} to change url.
  10530. *
  10531. * @param {string} url New url (when used as setter)
  10532. * @param {boolean=} replace Should new url replace current history record ?
  10533. */
  10534. self.url = function(url, replace) {
  10535. // setter
  10536. if (url) {
  10537. if (lastBrowserUrl == url) return;
  10538. lastBrowserUrl = url;
  10539. if ($sniffer.history) {
  10540. if (replace) history.replaceState(null, '', url);
  10541. else {
  10542. history.pushState(null, '', url);
  10543. // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
  10544. baseElement.attr('href', baseElement.attr('href'));
  10545. }
  10546. } else {
  10547. if (replace) location.replace(url);
  10548. else location.href = url;
  10549. }
  10550. return self;
  10551. // getter
  10552. } else {
  10553. // the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
  10554. return location.href.replace(/%27/g,"'");
  10555. }
  10556. };
  10557. var urlChangeListeners = [],
  10558. urlChangeInit = false;
  10559. function fireUrlChange() {
  10560. if (lastBrowserUrl == self.url()) return;
  10561. lastBrowserUrl = self.url();
  10562. forEach(urlChangeListeners, function(listener) {
  10563. listener(self.url());
  10564. });
  10565. }
  10566. /**
  10567. * @name ng.$browser#onUrlChange
  10568. * @methodOf ng.$browser
  10569. * @TODO(vojta): refactor to use node's syntax for events
  10570. *
  10571. * @description
  10572. * Register callback function that will be called, when url changes.
  10573. *
  10574. * It's only called when the url is changed by outside of angular:
  10575. * - user types different url into address bar
  10576. * - user clicks on history (forward/back) button
  10577. * - user clicks on a link
  10578. *
  10579. * It's not called when url is changed by $browser.url() method
  10580. *
  10581. * The listener gets called with new url as parameter.
  10582. *
  10583. * NOTE: this api is intended for use only by the $location service. Please use the
  10584. * {@link ng.$location $location service} to monitor url changes in angular apps.
  10585. *
  10586. * @param {function(string)} listener Listener function to be called when url changes.
  10587. * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
  10588. */
  10589. self.onUrlChange = function(callback) {
  10590. if (!urlChangeInit) {
  10591. // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
  10592. // don't fire popstate when user change the address bar and don't fire hashchange when url
  10593. // changed by push/replaceState
  10594. // html5 history api - popstate event
  10595. if ($sniffer.history) jqLite(window).bind('popstate', fireUrlChange);
  10596. // hashchange event
  10597. if ($sniffer.hashchange) jqLite(window).bind('hashchange', fireUrlChange);
  10598. // polling
  10599. else self.addPollFn(fireUrlChange);
  10600. urlChangeInit = true;
  10601. }
  10602. urlChangeListeners.push(callback);
  10603. return callback;
  10604. };
  10605. //////////////////////////////////////////////////////////////
  10606. // Misc API
  10607. //////////////////////////////////////////////////////////////
  10608. /**
  10609. * Returns current <base href>
  10610. * (always relative - without domain)
  10611. *
  10612. * @returns {string=}
  10613. */
  10614. self.baseHref = function() {
  10615. var href = baseElement.attr('href');
  10616. return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
  10617. };
  10618. //////////////////////////////////////////////////////////////
  10619. // Cookies API
  10620. //////////////////////////////////////////////////////////////
  10621. var lastCookies = {};
  10622. var lastCookieString = '';
  10623. var cookiePath = self.baseHref();
  10624. /**
  10625. * @name ng.$browser#cookies
  10626. * @methodOf ng.$browser
  10627. *
  10628. * @param {string=} name Cookie name
  10629. * @param {string=} value Cokkie value
  10630. *
  10631. * @description
  10632. * The cookies method provides a 'private' low level access to browser cookies.
  10633. * It is not meant to be used directly, use the $cookie service instead.
  10634. *
  10635. * The return values vary depending on the arguments that the method was called with as follows:
  10636. * <ul>
  10637. * <li>cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify it</li>
  10638. * <li>cookies(name, value) -> set name to value, if value is undefined delete the cookie</li>
  10639. * <li>cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that way)</li>
  10640. * </ul>
  10641. *
  10642. * @returns {Object} Hash of all cookies (if called without any parameter)
  10643. */
  10644. self.cookies = function(name, value) {
  10645. var cookieLength, cookieArray, cookie, i, index;
  10646. if (name) {
  10647. if (value === undefined) {
  10648. rawDocument.cookie = escape(name) + "=;path=" + cookiePath + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
  10649. } else {
  10650. if (isString(value)) {
  10651. cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + ';path=' + cookiePath).length + 1;
  10652. // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
  10653. // - 300 cookies
  10654. // - 20 cookies per unique domain
  10655. // - 4096 bytes per cookie
  10656. if (cookieLength > 4096) {
  10657. $log.warn("Cookie '"+ name +"' possibly not set or overflowed because it was too large ("+
  10658. cookieLength + " > 4096 bytes)!");
  10659. }
  10660. }
  10661. }
  10662. } else {
  10663. if (rawDocument.cookie !== lastCookieString) {
  10664. lastCookieString = rawDocument.cookie;
  10665. cookieArray = lastCookieString.split("; ");
  10666. lastCookies = {};
  10667. for (i = 0; i < cookieArray.length; i++) {
  10668. cookie = cookieArray[i];
  10669. index = cookie.indexOf('=');
  10670. if (index > 0) { //ignore nameless cookies
  10671. lastCookies[unescape(cookie.substring(0, index))] = unescape(cookie.substring(index + 1));
  10672. }
  10673. }
  10674. }
  10675. return lastCookies;
  10676. }
  10677. };
  10678. /**
  10679. * @name ng.$browser#defer
  10680. * @methodOf ng.$browser
  10681. * @param {function()} fn A function, who's execution should be defered.
  10682. * @param {number=} [delay=0] of milliseconds to defer the function execution.
  10683. * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
  10684. *
  10685. * @description
  10686. * Executes a fn asynchroniously via `setTimeout(fn, delay)`.
  10687. *
  10688. * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
  10689. * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
  10690. * via `$browser.defer.flush()`.
  10691. *
  10692. */
  10693. self.defer = function(fn, delay) {
  10694. var timeoutId;
  10695. outstandingRequestCount++;
  10696. timeoutId = setTimeout(function() {
  10697. delete pendingDeferIds[timeoutId];
  10698. completeOutstandingRequest(fn);
  10699. }, delay || 0);
  10700. pendingDeferIds[timeoutId] = true;
  10701. return timeoutId;
  10702. };
  10703. /**
  10704. * @name ng.$browser#defer.cancel
  10705. * @methodOf ng.$browser.defer
  10706. *
  10707. * @description
  10708. * Cancels a defered task identified with `deferId`.
  10709. *
  10710. * @param {*} deferId Token returned by the `$browser.defer` function.
  10711. * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfuly canceled.
  10712. */
  10713. self.defer.cancel = function(deferId) {
  10714. if (pendingDeferIds[deferId]) {
  10715. delete pendingDeferIds[deferId];
  10716. clearTimeout(deferId);
  10717. completeOutstandingRequest(noop);
  10718. return true;
  10719. }
  10720. return false;
  10721. };
  10722. }
  10723. function $BrowserProvider(){
  10724. this.$get = ['$window', '$log', '$sniffer', '$document',
  10725. function( $window, $log, $sniffer, $document){
  10726. return new Browser($window, $document, $log, $sniffer);
  10727. }];
  10728. }
  10729. /**
  10730. * @ngdoc object
  10731. * @name ng.$cacheFactory
  10732. *
  10733. * @description
  10734. * Factory that constructs cache objects.
  10735. *
  10736. *
  10737. * @param {string} cacheId Name or id of the newly created cache.
  10738. * @param {object=} options Options object that specifies the cache behavior. Properties:
  10739. *
  10740. * - `{number=}` `capacity` — turns the cache into LRU cache.
  10741. *
  10742. * @returns {object} Newly created cache object with the following set of methods:
  10743. *
  10744. * - `{object}` `info()` — Returns id, size, and options of cache.
  10745. * - `{void}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache.
  10746. * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
  10747. * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
  10748. * - `{void}` `removeAll()` — Removes all cached values.
  10749. * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
  10750. *
  10751. */
  10752. function $CacheFactoryProvider() {
  10753. this.$get = function() {
  10754. var caches = {};
  10755. function cacheFactory(cacheId, options) {
  10756. if (cacheId in caches) {
  10757. throw Error('cacheId ' + cacheId + ' taken');
  10758. }
  10759. var size = 0,
  10760. stats = extend({}, options, {id: cacheId}),
  10761. data = {},
  10762. capacity = (options && options.capacity) || Number.MAX_VALUE,
  10763. lruHash = {},
  10764. freshEnd = null,
  10765. staleEnd = null;
  10766. return caches[cacheId] = {
  10767. put: function(key, value) {
  10768. var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
  10769. refresh(lruEntry);
  10770. if (isUndefined(value)) return;
  10771. if (!(key in data)) size++;
  10772. data[key] = value;
  10773. if (size > capacity) {
  10774. this.remove(staleEnd.key);
  10775. }
  10776. },
  10777. get: function(key) {
  10778. var lruEntry = lruHash[key];
  10779. if (!lruEntry) return;
  10780. refresh(lruEntry);
  10781. return data[key];
  10782. },
  10783. remove: function(key) {
  10784. var lruEntry = lruHash[key];
  10785. if (!lruEntry) return;
  10786. if (lruEntry == freshEnd) freshEnd = lruEntry.p;
  10787. if (lruEntry == staleEnd) staleEnd = lruEntry.n;
  10788. link(lruEntry.n,lruEntry.p);
  10789. delete lruHash[key];
  10790. delete data[key];
  10791. size--;
  10792. },
  10793. removeAll: function() {
  10794. data = {};
  10795. size = 0;
  10796. lruHash = {};
  10797. freshEnd = staleEnd = null;
  10798. },
  10799. destroy: function() {
  10800. data = null;
  10801. stats = null;
  10802. lruHash = null;
  10803. delete caches[cacheId];
  10804. },
  10805. info: function() {
  10806. return extend({}, stats, {size: size});
  10807. }
  10808. };
  10809. /**
  10810. * makes the `entry` the freshEnd of the LRU linked list
  10811. */
  10812. function refresh(entry) {
  10813. if (entry != freshEnd) {
  10814. if (!staleEnd) {
  10815. staleEnd = entry;
  10816. } else if (staleEnd == entry) {
  10817. staleEnd = entry.n;
  10818. }
  10819. link(entry.n, entry.p);
  10820. link(entry, freshEnd);
  10821. freshEnd = entry;
  10822. freshEnd.n = null;
  10823. }
  10824. }
  10825. /**
  10826. * bidirectionally links two entries of the LRU linked list
  10827. */
  10828. function link(nextEntry, prevEntry) {
  10829. if (nextEntry != prevEntry) {
  10830. if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
  10831. if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
  10832. }
  10833. }
  10834. }
  10835. cacheFactory.info = function() {
  10836. var info = {};
  10837. forEach(caches, function(cache, cacheId) {
  10838. info[cacheId] = cache.info();
  10839. });
  10840. return info;
  10841. };
  10842. cacheFactory.get = function(cacheId) {
  10843. return caches[cacheId];
  10844. };
  10845. return cacheFactory;
  10846. };
  10847. }
  10848. /**
  10849. * @ngdoc object
  10850. * @name ng.$templateCache
  10851. *
  10852. * @description
  10853. * Cache used for storing html templates.
  10854. *
  10855. * See {@link ng.$cacheFactory $cacheFactory}.
  10856. *
  10857. */
  10858. function $TemplateCacheProvider() {
  10859. this.$get = ['$cacheFactory', function($cacheFactory) {
  10860. return $cacheFactory('templates');
  10861. }];
  10862. }
  10863. /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
  10864. *
  10865. * DOM-related variables:
  10866. *
  10867. * - "node" - DOM Node
  10868. * - "element" - DOM Element or Node
  10869. * - "$node" or "$element" - jqLite-wrapped node or element
  10870. *
  10871. *
  10872. * Compiler related stuff:
  10873. *
  10874. * - "linkFn" - linking fn of a single directive
  10875. * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
  10876. * - "childLinkFn" - function that aggregates all linking fns for child nodes of a particular node
  10877. * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
  10878. */
  10879. var NON_ASSIGNABLE_MODEL_EXPRESSION = 'Non-assignable model expression: ';
  10880. /**
  10881. * @ngdoc function
  10882. * @name ng.$compile
  10883. * @function
  10884. *
  10885. * @description
  10886. * Compiles a piece of HTML string or DOM into a template and produces a template function, which
  10887. * can then be used to link {@link ng.$rootScope.Scope scope} and the template together.
  10888. *
  10889. * The compilation is a process of walking the DOM tree and trying to match DOM elements to
  10890. * {@link ng.$compileProvider#directive directives}. For each match it
  10891. * executes corresponding template function and collects the
  10892. * instance functions into a single template function which is then returned.
  10893. *
  10894. * The template function can then be used once to produce the view or as it is the case with
  10895. * {@link ng.directive:ngRepeat repeater} many-times, in which
  10896. * case each call results in a view that is a DOM clone of the original template.
  10897. *
  10898. <doc:example module="compile">
  10899. <doc:source>
  10900. <script>
  10901. // declare a new module, and inject the $compileProvider
  10902. angular.module('compile', [], function($compileProvider) {
  10903. // configure new 'compile' directive by passing a directive
  10904. // factory function. The factory function injects the '$compile'
  10905. $compileProvider.directive('compile', function($compile) {
  10906. // directive factory creates a link function
  10907. return function(scope, element, attrs) {
  10908. scope.$watch(
  10909. function(scope) {
  10910. // watch the 'compile' expression for changes
  10911. return scope.$eval(attrs.compile);
  10912. },
  10913. function(value) {
  10914. // when the 'compile' expression changes
  10915. // assign it into the current DOM
  10916. element.html(value);
  10917. // compile the new DOM and link it to the current
  10918. // scope.
  10919. // NOTE: we only compile .childNodes so that
  10920. // we don't get into infinite loop compiling ourselves
  10921. $compile(element.contents())(scope);
  10922. }
  10923. );
  10924. };
  10925. })
  10926. });
  10927. function Ctrl($scope) {
  10928. $scope.name = 'Angular';
  10929. $scope.html = 'Hello {{name}}';
  10930. }
  10931. </script>
  10932. <div ng-controller="Ctrl">
  10933. <input ng-model="name"> <br>
  10934. <textarea ng-model="html"></textarea> <br>
  10935. <div compile="html"></div>
  10936. </div>
  10937. </doc:source>
  10938. <doc:scenario>
  10939. it('should auto compile', function() {
  10940. expect(element('div[compile]').text()).toBe('Hello Angular');
  10941. input('html').enter('{{name}}!');
  10942. expect(element('div[compile]').text()).toBe('Angular!');
  10943. });
  10944. </doc:scenario>
  10945. </doc:example>
  10946. *
  10947. *
  10948. * @param {string|DOMElement} element Element or HTML string to compile into a template function.
  10949. * @param {function(angular.Scope[, cloneAttachFn]} transclude function available to directives.
  10950. * @param {number} maxPriority only apply directives lower then given priority (Only effects the
  10951. * root element(s), not their children)
  10952. * @returns {function(scope[, cloneAttachFn])} a link function which is used to bind template
  10953. * (a DOM element/tree) to a scope. Where:
  10954. *
  10955. * * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
  10956. * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
  10957. * `template` and call the `cloneAttachFn` function allowing the caller to attach the
  10958. * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
  10959. * called as: <br> `cloneAttachFn(clonedElement, scope)` where:
  10960. *
  10961. * * `clonedElement` - is a clone of the original `element` passed into the compiler.
  10962. * * `scope` - is the current scope with which the linking function is working with.
  10963. *
  10964. * Calling the linking function returns the element of the template. It is either the original element
  10965. * passed in, or the clone of the element if the `cloneAttachFn` is provided.
  10966. *
  10967. * After linking the view is not updated until after a call to $digest which typically is done by
  10968. * Angular automatically.
  10969. *
  10970. * If you need access to the bound view, there are two ways to do it:
  10971. *
  10972. * - If you are not asking the linking function to clone the template, create the DOM element(s)
  10973. * before you send them to the compiler and keep this reference around.
  10974. * <pre>
  10975. * var element = $compile('<p>{{total}}</p>')(scope);
  10976. * </pre>
  10977. *
  10978. * - if on the other hand, you need the element to be cloned, the view reference from the original
  10979. * example would not point to the clone, but rather to the original template that was cloned. In
  10980. * this case, you can access the clone via the cloneAttachFn:
  10981. * <pre>
  10982. * var templateHTML = angular.element('<p>{{total}}</p>'),
  10983. * scope = ....;
  10984. *
  10985. * var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) {
  10986. * //attach the clone to DOM document at the right place
  10987. * });
  10988. *
  10989. * //now we have reference to the cloned DOM via `clone`
  10990. * </pre>
  10991. *
  10992. *
  10993. * For information on how the compiler works, see the
  10994. * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
  10995. */
  10996. /**
  10997. * @ngdoc service
  10998. * @name ng.$compileProvider
  10999. * @function
  11000. *
  11001. * @description
  11002. */
  11003. $CompileProvider.$inject = ['$provide'];
  11004. function $CompileProvider($provide) {
  11005. var hasDirectives = {},
  11006. Suffix = 'Directive',
  11007. COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
  11008. CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
  11009. MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',
  11010. urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/;
  11011. /**
  11012. * @ngdoc function
  11013. * @name ng.$compileProvider#directive
  11014. * @methodOf ng.$compileProvider
  11015. * @function
  11016. *
  11017. * @description
  11018. * Register a new directives with the compiler.
  11019. *
  11020. * @param {string} name Name of the directive in camel-case. (ie <code>ngBind</code> which will match as
  11021. * <code>ng-bind</code>).
  11022. * @param {function} directiveFactory An injectable directive factroy function. See {@link guide/directive} for more
  11023. * info.
  11024. * @returns {ng.$compileProvider} Self for chaining.
  11025. */
  11026. this.directive = function registerDirective(name, directiveFactory) {
  11027. if (isString(name)) {
  11028. assertArg(directiveFactory, 'directive');
  11029. if (!hasDirectives.hasOwnProperty(name)) {
  11030. hasDirectives[name] = [];
  11031. $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
  11032. function($injector, $exceptionHandler) {
  11033. var directives = [];
  11034. forEach(hasDirectives[name], function(directiveFactory) {
  11035. try {
  11036. var directive = $injector.invoke(directiveFactory);
  11037. if (isFunction(directive)) {
  11038. directive = { compile: valueFn(directive) };
  11039. } else if (!directive.compile && directive.link) {
  11040. directive.compile = valueFn(directive.link);
  11041. }
  11042. directive.priority = directive.priority || 0;
  11043. directive.name = directive.name || name;
  11044. directive.require = directive.require || (directive.controller && directive.name);
  11045. directive.restrict = directive.restrict || 'A';
  11046. directives.push(directive);
  11047. } catch (e) {
  11048. $exceptionHandler(e);
  11049. }
  11050. });
  11051. return directives;
  11052. }]);
  11053. }
  11054. hasDirectives[name].push(directiveFactory);
  11055. } else {
  11056. forEach(name, reverseParams(registerDirective));
  11057. }
  11058. return this;
  11059. };
  11060. /**
  11061. * @ngdoc function
  11062. * @name ng.$compileProvider#urlSanitizationWhitelist
  11063. * @methodOf ng.$compileProvider
  11064. * @function
  11065. *
  11066. * @description
  11067. * Retrieves or overrides the default regular expression that is used for whitelisting of safe
  11068. * urls during a[href] sanitization.
  11069. *
  11070. * The sanitization is a security measure aimed at prevent XSS attacks via html links.
  11071. *
  11072. * Any url about to be assigned to a[href] via data-binding is first normalized and turned into an
  11073. * absolute url. Afterwards the url is matched against the `urlSanitizationWhitelist` regular
  11074. * expression. If a match is found the original url is written into the dom. Otherwise the
  11075. * absolute url is prefixed with `'unsafe:'` string and only then it is written into the DOM.
  11076. *
  11077. * @param {RegExp=} regexp New regexp to whitelist urls with.
  11078. * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
  11079. * chaining otherwise.
  11080. */
  11081. this.urlSanitizationWhitelist = function(regexp) {
  11082. if (isDefined(regexp)) {
  11083. urlSanitizationWhitelist = regexp;
  11084. return this;
  11085. }
  11086. return urlSanitizationWhitelist;
  11087. };
  11088. this.$get = [
  11089. '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
  11090. '$controller', '$rootScope', '$document',
  11091. function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
  11092. $controller, $rootScope, $document) {
  11093. var Attributes = function(element, attr) {
  11094. this.$$element = element;
  11095. this.$attr = attr || {};
  11096. };
  11097. Attributes.prototype = {
  11098. $normalize: directiveNormalize,
  11099. /**
  11100. * Set a normalized attribute on the element in a way such that all directives
  11101. * can share the attribute. This function properly handles boolean attributes.
  11102. * @param {string} key Normalized key. (ie ngAttribute)
  11103. * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
  11104. * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
  11105. * Defaults to true.
  11106. * @param {string=} attrName Optional none normalized name. Defaults to key.
  11107. */
  11108. $set: function(key, value, writeAttr, attrName) {
  11109. var booleanKey = getBooleanAttrName(this.$$element[0], key),
  11110. $$observers = this.$$observers,
  11111. normalizedVal;
  11112. if (booleanKey) {
  11113. this.$$element.prop(key, value);
  11114. attrName = booleanKey;
  11115. }
  11116. this[key] = value;
  11117. // translate normalized key to actual key
  11118. if (attrName) {
  11119. this.$attr[key] = attrName;
  11120. } else {
  11121. attrName = this.$attr[key];
  11122. if (!attrName) {
  11123. this.$attr[key] = attrName = snake_case(key, '-');
  11124. }
  11125. }
  11126. // sanitize a[href] values
  11127. if (nodeName_(this.$$element[0]) === 'A' && key === 'href') {
  11128. urlSanitizationNode.setAttribute('href', value);
  11129. // href property always returns normalized absolute url, so we can match against that
  11130. normalizedVal = urlSanitizationNode.href;
  11131. if (!normalizedVal.match(urlSanitizationWhitelist)) {
  11132. this[key] = value = 'unsafe:' + normalizedVal;
  11133. }
  11134. }
  11135. if (writeAttr !== false) {
  11136. if (value === null || value === undefined) {
  11137. this.$$element.removeAttr(attrName);
  11138. } else {
  11139. this.$$element.attr(attrName, value);
  11140. }
  11141. }
  11142. // fire observers
  11143. $$observers && forEach($$observers[key], function(fn) {
  11144. try {
  11145. fn(value);
  11146. } catch (e) {
  11147. $exceptionHandler(e);
  11148. }
  11149. });
  11150. },
  11151. /**
  11152. * Observe an interpolated attribute.
  11153. * The observer will never be called, if given attribute is not interpolated.
  11154. *
  11155. * @param {string} key Normalized key. (ie ngAttribute) .
  11156. * @param {function(*)} fn Function that will be called whenever the attribute value changes.
  11157. * @returns {function(*)} the `fn` Function passed in.
  11158. */
  11159. $observe: function(key, fn) {
  11160. var attrs = this,
  11161. $$observers = (attrs.$$observers || (attrs.$$observers = {})),
  11162. listeners = ($$observers[key] || ($$observers[key] = []));
  11163. listeners.push(fn);
  11164. $rootScope.$evalAsync(function() {
  11165. if (!listeners.$$inter) {
  11166. // no one registered attribute interpolation function, so lets call it manually
  11167. fn(attrs[key]);
  11168. }
  11169. });
  11170. return fn;
  11171. }
  11172. };
  11173. var urlSanitizationNode = $document[0].createElement('a'),
  11174. startSymbol = $interpolate.startSymbol(),
  11175. endSymbol = $interpolate.endSymbol(),
  11176. denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
  11177. ? identity
  11178. : function denormalizeTemplate(template) {
  11179. return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
  11180. };
  11181. return compile;
  11182. //================================
  11183. function compile($compileNodes, transcludeFn, maxPriority) {
  11184. if (!($compileNodes instanceof jqLite)) {
  11185. // jquery always rewraps, whereas we need to preserve the original selector so that we can modify it.
  11186. $compileNodes = jqLite($compileNodes);
  11187. }
  11188. // We can not compile top level text elements since text nodes can be merged and we will
  11189. // not be able to attach scope data to them, so we will wrap them in <span>
  11190. forEach($compileNodes, function(node, index){
  11191. if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
  11192. $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
  11193. }
  11194. });
  11195. var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority);
  11196. return function publicLinkFn(scope, cloneConnectFn){
  11197. assertArg(scope, 'scope');
  11198. // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
  11199. // and sometimes changes the structure of the DOM.
  11200. var $linkNode = cloneConnectFn
  11201. ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
  11202. : $compileNodes;
  11203. // Attach scope only to non-text nodes.
  11204. for(var i = 0, ii = $linkNode.length; i<ii; i++) {
  11205. var node = $linkNode[i];
  11206. if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
  11207. $linkNode.eq(i).data('$scope', scope);
  11208. }
  11209. }
  11210. safeAddClass($linkNode, 'ng-scope');
  11211. if (cloneConnectFn) cloneConnectFn($linkNode, scope);
  11212. if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
  11213. return $linkNode;
  11214. };
  11215. }
  11216. function wrongMode(localName, mode) {
  11217. throw Error("Unsupported '" + mode + "' for '" + localName + "'.");
  11218. }
  11219. function safeAddClass($element, className) {
  11220. try {
  11221. $element.addClass(className);
  11222. } catch(e) {
  11223. // ignore, since it means that we are trying to set class on
  11224. // SVG element, where class name is read-only.
  11225. }
  11226. }
  11227. /**
  11228. * Compile function matches each node in nodeList against the directives. Once all directives
  11229. * for a particular node are collected their compile functions are executed. The compile
  11230. * functions return values - the linking functions - are combined into a composite linking
  11231. * function, which is the a linking function for the node.
  11232. *
  11233. * @param {NodeList} nodeList an array of nodes or NodeList to compile
  11234. * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
  11235. * scope argument is auto-generated to the new child of the transcluded parent scope.
  11236. * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the
  11237. * rootElement must be set the jqLite collection of the compile root. This is
  11238. * needed so that the jqLite collection items can be replaced with widgets.
  11239. * @param {number=} max directive priority
  11240. * @returns {?function} A composite linking function of all of the matched directives or null.
  11241. */
  11242. function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority) {
  11243. var linkFns = [],
  11244. nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
  11245. for(var i = 0; i < nodeList.length; i++) {
  11246. attrs = new Attributes();
  11247. // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
  11248. directives = collectDirectives(nodeList[i], [], attrs, maxPriority);
  11249. nodeLinkFn = (directives.length)
  11250. ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
  11251. : null;
  11252. childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length)
  11253. ? null
  11254. : compileNodes(nodeList[i].childNodes,
  11255. nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
  11256. linkFns.push(nodeLinkFn);
  11257. linkFns.push(childLinkFn);
  11258. linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
  11259. }
  11260. // return a linking function if we have found anything, null otherwise
  11261. return linkFnFound ? compositeLinkFn : null;
  11262. function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
  11263. var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn, i, ii, n;
  11264. // copy nodeList so that linking doesn't break due to live list updates.
  11265. var stableNodeList = [];
  11266. for (i = 0, ii = nodeList.length; i < ii; i++) {
  11267. stableNodeList.push(nodeList[i]);
  11268. }
  11269. for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
  11270. node = stableNodeList[n];
  11271. nodeLinkFn = linkFns[i++];
  11272. childLinkFn = linkFns[i++];
  11273. if (nodeLinkFn) {
  11274. if (nodeLinkFn.scope) {
  11275. childScope = scope.$new(isObject(nodeLinkFn.scope));
  11276. jqLite(node).data('$scope', childScope);
  11277. } else {
  11278. childScope = scope;
  11279. }
  11280. childTranscludeFn = nodeLinkFn.transclude;
  11281. if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
  11282. nodeLinkFn(childLinkFn, childScope, node, $rootElement,
  11283. (function(transcludeFn) {
  11284. return function(cloneFn) {
  11285. var transcludeScope = scope.$new();
  11286. transcludeScope.$$transcluded = true;
  11287. return transcludeFn(transcludeScope, cloneFn).
  11288. bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
  11289. };
  11290. })(childTranscludeFn || transcludeFn)
  11291. );
  11292. } else {
  11293. nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
  11294. }
  11295. } else if (childLinkFn) {
  11296. childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
  11297. }
  11298. }
  11299. }
  11300. }
  11301. /**
  11302. * Looks for directives on the given node and adds them to the directive collection which is
  11303. * sorted.
  11304. *
  11305. * @param node Node to search.
  11306. * @param directives An array to which the directives are added to. This array is sorted before
  11307. * the function returns.
  11308. * @param attrs The shared attrs object which is used to populate the normalized attributes.
  11309. * @param {number=} maxPriority Max directive priority.
  11310. */
  11311. function collectDirectives(node, directives, attrs, maxPriority) {
  11312. var nodeType = node.nodeType,
  11313. attrsMap = attrs.$attr,
  11314. match,
  11315. className;
  11316. switch(nodeType) {
  11317. case 1: /* Element */
  11318. // use the node name: <directive>
  11319. addDirective(directives,
  11320. directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority);
  11321. // iterate over the attributes
  11322. for (var attr, name, nName, value, nAttrs = node.attributes,
  11323. j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
  11324. attr = nAttrs[j];
  11325. if (attr.specified) {
  11326. name = attr.name;
  11327. nName = directiveNormalize(name.toLowerCase());
  11328. attrsMap[nName] = name;
  11329. attrs[nName] = value = trim((msie && name == 'href')
  11330. ? decodeURIComponent(node.getAttribute(name, 2))
  11331. : attr.value);
  11332. if (getBooleanAttrName(node, nName)) {
  11333. attrs[nName] = true; // presence means true
  11334. }
  11335. addAttrInterpolateDirective(node, directives, value, nName);
  11336. addDirective(directives, nName, 'A', maxPriority);
  11337. }
  11338. }
  11339. // use class as directive
  11340. className = node.className;
  11341. if (isString(className) && className !== '') {
  11342. while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
  11343. nName = directiveNormalize(match[2]);
  11344. if (addDirective(directives, nName, 'C', maxPriority)) {
  11345. attrs[nName] = trim(match[3]);
  11346. }
  11347. className = className.substr(match.index + match[0].length);
  11348. }
  11349. }
  11350. break;
  11351. case 3: /* Text Node */
  11352. addTextInterpolateDirective(directives, node.nodeValue);
  11353. break;
  11354. case 8: /* Comment */
  11355. try {
  11356. match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
  11357. if (match) {
  11358. nName = directiveNormalize(match[1]);
  11359. if (addDirective(directives, nName, 'M', maxPriority)) {
  11360. attrs[nName] = trim(match[2]);
  11361. }
  11362. }
  11363. } catch (e) {
  11364. // turns out that under some circumstances IE9 throws errors when one attempts to read comment's node value.
  11365. // Just ignore it and continue. (Can't seem to reproduce in test case.)
  11366. }
  11367. break;
  11368. }
  11369. directives.sort(byPriority);
  11370. return directives;
  11371. }
  11372. /**
  11373. * Once the directives have been collected their compile functions is executed. This method
  11374. * is responsible for inlining directive templates as well as terminating the application
  11375. * of the directives if the terminal directive has been reached..
  11376. *
  11377. * @param {Array} directives Array of collected directives to execute their compile function.
  11378. * this needs to be pre-sorted by priority order.
  11379. * @param {Node} compileNode The raw DOM node to apply the compile functions to
  11380. * @param {Object} templateAttrs The shared attribute function
  11381. * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
  11382. * scope argument is auto-generated to the new child of the transcluded parent scope.
  11383. * @param {DOMElement} $rootElement If we are working on the root of the compile tree then this
  11384. * argument has the root jqLite array so that we can replace widgets on it.
  11385. * @returns linkFn
  11386. */
  11387. function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, $rootElement) {
  11388. var terminalPriority = -Number.MAX_VALUE,
  11389. preLinkFns = [],
  11390. postLinkFns = [],
  11391. newScopeDirective = null,
  11392. newIsolateScopeDirective = null,
  11393. templateDirective = null,
  11394. $compileNode = templateAttrs.$$element = jqLite(compileNode),
  11395. directive,
  11396. directiveName,
  11397. $template,
  11398. transcludeDirective,
  11399. childTranscludeFn = transcludeFn,
  11400. controllerDirectives,
  11401. linkFn,
  11402. directiveValue;
  11403. // executes all directives on the current element
  11404. for(var i = 0, ii = directives.length; i < ii; i++) {
  11405. directive = directives[i];
  11406. $template = undefined;
  11407. if (terminalPriority > directive.priority) {
  11408. break; // prevent further processing of directives
  11409. }
  11410. if (directiveValue = directive.scope) {
  11411. assertNoDuplicate('isolated scope', newIsolateScopeDirective, directive, $compileNode);
  11412. if (isObject(directiveValue)) {
  11413. safeAddClass($compileNode, 'ng-isolate-scope');
  11414. newIsolateScopeDirective = directive;
  11415. }
  11416. safeAddClass($compileNode, 'ng-scope');
  11417. newScopeDirective = newScopeDirective || directive;
  11418. }
  11419. directiveName = directive.name;
  11420. if (directiveValue = directive.controller) {
  11421. controllerDirectives = controllerDirectives || {};
  11422. assertNoDuplicate("'" + directiveName + "' controller",
  11423. controllerDirectives[directiveName], directive, $compileNode);
  11424. controllerDirectives[directiveName] = directive;
  11425. }
  11426. if (directiveValue = directive.transclude) {
  11427. assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode);
  11428. transcludeDirective = directive;
  11429. terminalPriority = directive.priority;
  11430. if (directiveValue == 'element') {
  11431. $template = jqLite(compileNode);
  11432. $compileNode = templateAttrs.$$element =
  11433. jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
  11434. compileNode = $compileNode[0];
  11435. replaceWith($rootElement, jqLite($template[0]), compileNode);
  11436. childTranscludeFn = compile($template, transcludeFn, terminalPriority);
  11437. } else {
  11438. $template = jqLite(JQLiteClone(compileNode)).contents();
  11439. $compileNode.html(''); // clear contents
  11440. childTranscludeFn = compile($template, transcludeFn);
  11441. }
  11442. }
  11443. if ((directiveValue = directive.template)) {
  11444. assertNoDuplicate('template', templateDirective, directive, $compileNode);
  11445. templateDirective = directive;
  11446. directiveValue = denormalizeTemplate(directiveValue);
  11447. if (directive.replace) {
  11448. $template = jqLite('<div>' +
  11449. trim(directiveValue) +
  11450. '</div>').contents();
  11451. compileNode = $template[0];
  11452. if ($template.length != 1 || compileNode.nodeType !== 1) {
  11453. throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue);
  11454. }
  11455. replaceWith($rootElement, $compileNode, compileNode);
  11456. var newTemplateAttrs = {$attr: {}};
  11457. // combine directives from the original node and from the template:
  11458. // - take the array of directives for this element
  11459. // - split it into two parts, those that were already applied and those that weren't
  11460. // - collect directives from the template, add them to the second group and sort them
  11461. // - append the second group with new directives to the first group
  11462. directives = directives.concat(
  11463. collectDirectives(
  11464. compileNode,
  11465. directives.splice(i + 1, directives.length - (i + 1)),
  11466. newTemplateAttrs
  11467. )
  11468. );
  11469. mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
  11470. ii = directives.length;
  11471. } else {
  11472. $compileNode.html(directiveValue);
  11473. }
  11474. }
  11475. if (directive.templateUrl) {
  11476. assertNoDuplicate('template', templateDirective, directive, $compileNode);
  11477. templateDirective = directive;
  11478. nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i),
  11479. nodeLinkFn, $compileNode, templateAttrs, $rootElement, directive.replace,
  11480. childTranscludeFn);
  11481. ii = directives.length;
  11482. } else if (directive.compile) {
  11483. try {
  11484. linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
  11485. if (isFunction(linkFn)) {
  11486. addLinkFns(null, linkFn);
  11487. } else if (linkFn) {
  11488. addLinkFns(linkFn.pre, linkFn.post);
  11489. }
  11490. } catch (e) {
  11491. $exceptionHandler(e, startingTag($compileNode));
  11492. }
  11493. }
  11494. if (directive.terminal) {
  11495. nodeLinkFn.terminal = true;
  11496. terminalPriority = Math.max(terminalPriority, directive.priority);
  11497. }
  11498. }
  11499. nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope;
  11500. nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;
  11501. // might be normal or delayed nodeLinkFn depending on if templateUrl is present
  11502. return nodeLinkFn;
  11503. ////////////////////
  11504. function addLinkFns(pre, post) {
  11505. if (pre) {
  11506. pre.require = directive.require;
  11507. preLinkFns.push(pre);
  11508. }
  11509. if (post) {
  11510. post.require = directive.require;
  11511. postLinkFns.push(post);
  11512. }
  11513. }
  11514. function getControllers(require, $element) {
  11515. var value, retrievalMethod = 'data', optional = false;
  11516. if (isString(require)) {
  11517. while((value = require.charAt(0)) == '^' || value == '?') {
  11518. require = require.substr(1);
  11519. if (value == '^') {
  11520. retrievalMethod = 'inheritedData';
  11521. }
  11522. optional = optional || value == '?';
  11523. }
  11524. value = $element[retrievalMethod]('$' + require + 'Controller');
  11525. if (!value && !optional) {
  11526. throw Error("No controller: " + require);
  11527. }
  11528. return value;
  11529. } else if (isArray(require)) {
  11530. value = [];
  11531. forEach(require, function(require) {
  11532. value.push(getControllers(require, $element));
  11533. });
  11534. }
  11535. return value;
  11536. }
  11537. function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
  11538. var attrs, $element, i, ii, linkFn, controller;
  11539. if (compileNode === linkNode) {
  11540. attrs = templateAttrs;
  11541. } else {
  11542. attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
  11543. }
  11544. $element = attrs.$$element;
  11545. if (newIsolateScopeDirective) {
  11546. var LOCAL_REGEXP = /^\s*([@=&])\s*(\w*)\s*$/;
  11547. var parentScope = scope.$parent || scope;
  11548. forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) {
  11549. var match = definiton.match(LOCAL_REGEXP) || [],
  11550. attrName = match[2]|| scopeName,
  11551. mode = match[1], // @, =, or &
  11552. lastValue,
  11553. parentGet, parentSet;
  11554. scope.$$isolateBindings[scopeName] = mode + attrName;
  11555. switch (mode) {
  11556. case '@': {
  11557. attrs.$observe(attrName, function(value) {
  11558. scope[scopeName] = value;
  11559. });
  11560. attrs.$$observers[attrName].$$scope = parentScope;
  11561. break;
  11562. }
  11563. case '=': {
  11564. parentGet = $parse(attrs[attrName]);
  11565. parentSet = parentGet.assign || function() {
  11566. // reset the change, or we will throw this exception on every $digest
  11567. lastValue = scope[scopeName] = parentGet(parentScope);
  11568. throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + attrs[attrName] +
  11569. ' (directive: ' + newIsolateScopeDirective.name + ')');
  11570. };
  11571. lastValue = scope[scopeName] = parentGet(parentScope);
  11572. scope.$watch(function parentValueWatch() {
  11573. var parentValue = parentGet(parentScope);
  11574. if (parentValue !== scope[scopeName]) {
  11575. // we are out of sync and need to copy
  11576. if (parentValue !== lastValue) {
  11577. // parent changed and it has precedence
  11578. lastValue = scope[scopeName] = parentValue;
  11579. } else {
  11580. // if the parent can be assigned then do so
  11581. parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
  11582. }
  11583. }
  11584. return parentValue;
  11585. });
  11586. break;
  11587. }
  11588. case '&': {
  11589. parentGet = $parse(attrs[attrName]);
  11590. scope[scopeName] = function(locals) {
  11591. return parentGet(parentScope, locals);
  11592. }
  11593. break;
  11594. }
  11595. default: {
  11596. throw Error('Invalid isolate scope definition for directive ' +
  11597. newIsolateScopeDirective.name + ': ' + definiton);
  11598. }
  11599. }
  11600. });
  11601. }
  11602. if (controllerDirectives) {
  11603. forEach(controllerDirectives, function(directive) {
  11604. var locals = {
  11605. $scope: scope,
  11606. $element: $element,
  11607. $attrs: attrs,
  11608. $transclude: boundTranscludeFn
  11609. };
  11610. controller = directive.controller;
  11611. if (controller == '@') {
  11612. controller = attrs[directive.name];
  11613. }
  11614. $element.data(
  11615. '$' + directive.name + 'Controller',
  11616. $controller(controller, locals));
  11617. });
  11618. }
  11619. // PRELINKING
  11620. for(i = 0, ii = preLinkFns.length; i < ii; i++) {
  11621. try {
  11622. linkFn = preLinkFns[i];
  11623. linkFn(scope, $element, attrs,
  11624. linkFn.require && getControllers(linkFn.require, $element));
  11625. } catch (e) {
  11626. $exceptionHandler(e, startingTag($element));
  11627. }
  11628. }
  11629. // RECURSION
  11630. childLinkFn && childLinkFn(scope, linkNode.childNodes, undefined, boundTranscludeFn);
  11631. // POSTLINKING
  11632. for(i = 0, ii = postLinkFns.length; i < ii; i++) {
  11633. try {
  11634. linkFn = postLinkFns[i];
  11635. linkFn(scope, $element, attrs,
  11636. linkFn.require && getControllers(linkFn.require, $element));
  11637. } catch (e) {
  11638. $exceptionHandler(e, startingTag($element));
  11639. }
  11640. }
  11641. }
  11642. }
  11643. /**
  11644. * looks up the directive and decorates it with exception handling and proper parameters. We
  11645. * call this the boundDirective.
  11646. *
  11647. * @param {string} name name of the directive to look up.
  11648. * @param {string} location The directive must be found in specific format.
  11649. * String containing any of theses characters:
  11650. *
  11651. * * `E`: element name
  11652. * * `A': attribute
  11653. * * `C`: class
  11654. * * `M`: comment
  11655. * @returns true if directive was added.
  11656. */
  11657. function addDirective(tDirectives, name, location, maxPriority) {
  11658. var match = false;
  11659. if (hasDirectives.hasOwnProperty(name)) {
  11660. for(var directive, directives = $injector.get(name + Suffix),
  11661. i = 0, ii = directives.length; i<ii; i++) {
  11662. try {
  11663. directive = directives[i];
  11664. if ( (maxPriority === undefined || maxPriority > directive.priority) &&
  11665. directive.restrict.indexOf(location) != -1) {
  11666. tDirectives.push(directive);
  11667. match = true;
  11668. }
  11669. } catch(e) { $exceptionHandler(e); }
  11670. }
  11671. }
  11672. return match;
  11673. }
  11674. /**
  11675. * When the element is replaced with HTML template then the new attributes
  11676. * on the template need to be merged with the existing attributes in the DOM.
  11677. * The desired effect is to have both of the attributes present.
  11678. *
  11679. * @param {object} dst destination attributes (original DOM)
  11680. * @param {object} src source attributes (from the directive template)
  11681. */
  11682. function mergeTemplateAttributes(dst, src) {
  11683. var srcAttr = src.$attr,
  11684. dstAttr = dst.$attr,
  11685. $element = dst.$$element;
  11686. // reapply the old attributes to the new element
  11687. forEach(dst, function(value, key) {
  11688. if (key.charAt(0) != '$') {
  11689. if (src[key]) {
  11690. value += (key === 'style' ? ';' : ' ') + src[key];
  11691. }
  11692. dst.$set(key, value, true, srcAttr[key]);
  11693. }
  11694. });
  11695. // copy the new attributes on the old attrs object
  11696. forEach(src, function(value, key) {
  11697. if (key == 'class') {
  11698. safeAddClass($element, value);
  11699. dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
  11700. } else if (key == 'style') {
  11701. $element.attr('style', $element.attr('style') + ';' + value);
  11702. } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
  11703. dst[key] = value;
  11704. dstAttr[key] = srcAttr[key];
  11705. }
  11706. });
  11707. }
  11708. function compileTemplateUrl(directives, beforeTemplateNodeLinkFn, $compileNode, tAttrs,
  11709. $rootElement, replace, childTranscludeFn) {
  11710. var linkQueue = [],
  11711. afterTemplateNodeLinkFn,
  11712. afterTemplateChildLinkFn,
  11713. beforeTemplateCompileNode = $compileNode[0],
  11714. origAsyncDirective = directives.shift(),
  11715. // The fact that we have to copy and patch the directive seems wrong!
  11716. derivedSyncDirective = extend({}, origAsyncDirective, {
  11717. controller: null, templateUrl: null, transclude: null, scope: null
  11718. });
  11719. $compileNode.html('');
  11720. $http.get(origAsyncDirective.templateUrl, {cache: $templateCache}).
  11721. success(function(content) {
  11722. var compileNode, tempTemplateAttrs, $template;
  11723. content = denormalizeTemplate(content);
  11724. if (replace) {
  11725. $template = jqLite('<div>' + trim(content) + '</div>').contents();
  11726. compileNode = $template[0];
  11727. if ($template.length != 1 || compileNode.nodeType !== 1) {
  11728. throw new Error(MULTI_ROOT_TEMPLATE_ERROR + content);
  11729. }
  11730. tempTemplateAttrs = {$attr: {}};
  11731. replaceWith($rootElement, $compileNode, compileNode);
  11732. collectDirectives(compileNode, directives, tempTemplateAttrs);
  11733. mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
  11734. } else {
  11735. compileNode = beforeTemplateCompileNode;
  11736. $compileNode.html(content);
  11737. }
  11738. directives.unshift(derivedSyncDirective);
  11739. afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn);
  11740. afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
  11741. while(linkQueue.length) {
  11742. var controller = linkQueue.pop(),
  11743. linkRootElement = linkQueue.pop(),
  11744. beforeTemplateLinkNode = linkQueue.pop(),
  11745. scope = linkQueue.pop(),
  11746. linkNode = compileNode;
  11747. if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
  11748. // it was cloned therefore we have to clone as well.
  11749. linkNode = JQLiteClone(compileNode);
  11750. replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
  11751. }
  11752. afterTemplateNodeLinkFn(function() {
  11753. beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, controller);
  11754. }, scope, linkNode, $rootElement, controller);
  11755. }
  11756. linkQueue = null;
  11757. }).
  11758. error(function(response, code, headers, config) {
  11759. throw Error('Failed to load template: ' + config.url);
  11760. });
  11761. return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
  11762. if (linkQueue) {
  11763. linkQueue.push(scope);
  11764. linkQueue.push(node);
  11765. linkQueue.push(rootElement);
  11766. linkQueue.push(controller);
  11767. } else {
  11768. afterTemplateNodeLinkFn(function() {
  11769. beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, controller);
  11770. }, scope, node, rootElement, controller);
  11771. }
  11772. };
  11773. }
  11774. /**
  11775. * Sorting function for bound directives.
  11776. */
  11777. function byPriority(a, b) {
  11778. return b.priority - a.priority;
  11779. }
  11780. function assertNoDuplicate(what, previousDirective, directive, element) {
  11781. if (previousDirective) {
  11782. throw Error('Multiple directives [' + previousDirective.name + ', ' +
  11783. directive.name + '] asking for ' + what + ' on: ' + startingTag(element));
  11784. }
  11785. }
  11786. function addTextInterpolateDirective(directives, text) {
  11787. var interpolateFn = $interpolate(text, true);
  11788. if (interpolateFn) {
  11789. directives.push({
  11790. priority: 0,
  11791. compile: valueFn(function textInterpolateLinkFn(scope, node) {
  11792. var parent = node.parent(),
  11793. bindings = parent.data('$binding') || [];
  11794. bindings.push(interpolateFn);
  11795. safeAddClass(parent.data('$binding', bindings), 'ng-binding');
  11796. scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
  11797. node[0].nodeValue = value;
  11798. });
  11799. })
  11800. });
  11801. }
  11802. }
  11803. function addAttrInterpolateDirective(node, directives, value, name) {
  11804. var interpolateFn = $interpolate(value, true);
  11805. // no interpolation found -> ignore
  11806. if (!interpolateFn) return;
  11807. directives.push({
  11808. priority: 100,
  11809. compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
  11810. var $$observers = (attr.$$observers || (attr.$$observers = {}));
  11811. if (name === 'class') {
  11812. // we need to interpolate classes again, in the case the element was replaced
  11813. // and therefore the two class attrs got merged - we want to interpolate the result
  11814. interpolateFn = $interpolate(attr[name], true);
  11815. }
  11816. attr[name] = undefined;
  11817. ($$observers[name] || ($$observers[name] = [])).$$inter = true;
  11818. (attr.$$observers && attr.$$observers[name].$$scope || scope).
  11819. $watch(interpolateFn, function interpolateFnWatchAction(value) {
  11820. attr.$set(name, value);
  11821. });
  11822. })
  11823. });
  11824. }
  11825. /**
  11826. * This is a special jqLite.replaceWith, which can replace items which
  11827. * have no parents, provided that the containing jqLite collection is provided.
  11828. *
  11829. * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
  11830. * in the root of the tree.
  11831. * @param {JqLite} $element The jqLite element which we are going to replace. We keep the shell,
  11832. * but replace its DOM node reference.
  11833. * @param {Node} newNode The new DOM node.
  11834. */
  11835. function replaceWith($rootElement, $element, newNode) {
  11836. var oldNode = $element[0],
  11837. parent = oldNode.parentNode,
  11838. i, ii;
  11839. if ($rootElement) {
  11840. for(i = 0, ii = $rootElement.length; i < ii; i++) {
  11841. if ($rootElement[i] == oldNode) {
  11842. $rootElement[i] = newNode;
  11843. break;
  11844. }
  11845. }
  11846. }
  11847. if (parent) {
  11848. parent.replaceChild(newNode, oldNode);
  11849. }
  11850. newNode[jqLite.expando] = oldNode[jqLite.expando];
  11851. $element[0] = newNode;
  11852. }
  11853. }];
  11854. }
  11855. var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
  11856. /**
  11857. * Converts all accepted directives format into proper directive name.
  11858. * All of these will become 'myDirective':
  11859. * my:DiRective
  11860. * my-directive
  11861. * x-my-directive
  11862. * data-my:directive
  11863. *
  11864. * Also there is special case for Moz prefix starting with upper case letter.
  11865. * @param name Name to normalize
  11866. */
  11867. function directiveNormalize(name) {
  11868. return camelCase(name.replace(PREFIX_REGEXP, ''));
  11869. }
  11870. /**
  11871. * @ngdoc object
  11872. * @name ng.$compile.directive.Attributes
  11873. * @description
  11874. *
  11875. * A shared object between directive compile / linking functions which contains normalized DOM element
  11876. * attributes. The the values reflect current binding state `{{ }}`. The normalization is needed
  11877. * since all of these are treated as equivalent in Angular:
  11878. *
  11879. * <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
  11880. */
  11881. /**
  11882. * @ngdoc property
  11883. * @name ng.$compile.directive.Attributes#$attr
  11884. * @propertyOf ng.$compile.directive.Attributes
  11885. * @returns {object} A map of DOM element attribute names to the normalized name. This is
  11886. * needed to do reverse lookup from normalized name back to actual name.
  11887. */
  11888. /**
  11889. * @ngdoc function
  11890. * @name ng.$compile.directive.Attributes#$set
  11891. * @methodOf ng.$compile.directive.Attributes
  11892. * @function
  11893. *
  11894. * @description
  11895. * Set DOM element attribute value.
  11896. *
  11897. *
  11898. * @param {string} name Normalized element attribute name of the property to modify. The name is
  11899. * revers translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
  11900. * property to the original name.
  11901. * @param {string} value Value to set the attribute to.
  11902. */
  11903. /**
  11904. * Closure compiler type information
  11905. */
  11906. function nodesetLinkingFn(
  11907. /* angular.Scope */ scope,
  11908. /* NodeList */ nodeList,
  11909. /* Element */ rootElement,
  11910. /* function(Function) */ boundTranscludeFn
  11911. ){}
  11912. function directiveLinkingFn(
  11913. /* nodesetLinkingFn */ nodesetLinkingFn,
  11914. /* angular.Scope */ scope,
  11915. /* Node */ node,
  11916. /* Element */ rootElement,
  11917. /* function(Function) */ boundTranscludeFn
  11918. ){}
  11919. /**
  11920. * @ngdoc object
  11921. * @name ng.$controllerProvider
  11922. * @description
  11923. * The {@link ng.$controller $controller service} is used by Angular to create new
  11924. * controllers.
  11925. *
  11926. * This provider allows controller registration via the
  11927. * {@link ng.$controllerProvider#register register} method.
  11928. */
  11929. function $ControllerProvider() {
  11930. var controllers = {};
  11931. /**
  11932. * @ngdoc function
  11933. * @name ng.$controllerProvider#register
  11934. * @methodOf ng.$controllerProvider
  11935. * @param {string} name Controller name
  11936. * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
  11937. * annotations in the array notation).
  11938. */
  11939. this.register = function(name, constructor) {
  11940. if (isObject(name)) {
  11941. extend(controllers, name)
  11942. } else {
  11943. controllers[name] = constructor;
  11944. }
  11945. };
  11946. this.$get = ['$injector', '$window', function($injector, $window) {
  11947. /**
  11948. * @ngdoc function
  11949. * @name ng.$controller
  11950. * @requires $injector
  11951. *
  11952. * @param {Function|string} constructor If called with a function then it's considered to be the
  11953. * controller constructor function. Otherwise it's considered to be a string which is used
  11954. * to retrieve the controller constructor using the following steps:
  11955. *
  11956. * * check if a controller with given name is registered via `$controllerProvider`
  11957. * * check if evaluating the string on the current scope returns a constructor
  11958. * * check `window[constructor]` on the global `window` object
  11959. *
  11960. * @param {Object} locals Injection locals for Controller.
  11961. * @return {Object} Instance of given controller.
  11962. *
  11963. * @description
  11964. * `$controller` service is responsible for instantiating controllers.
  11965. *
  11966. * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into
  11967. * a service, so that one can override this service with {@link https://gist.github.com/1649788
  11968. * BC version}.
  11969. */
  11970. return function(constructor, locals) {
  11971. if(isString(constructor)) {
  11972. var name = constructor;
  11973. constructor = controllers.hasOwnProperty(name)
  11974. ? controllers[name]
  11975. : getter(locals.$scope, name, true) || getter($window, name, true);
  11976. assertArgFn(constructor, name, true);
  11977. }
  11978. return $injector.instantiate(constructor, locals);
  11979. };
  11980. }];
  11981. }
  11982. /**
  11983. * @ngdoc object
  11984. * @name ng.$document
  11985. * @requires $window
  11986. *
  11987. * @description
  11988. * A {@link angular.element jQuery (lite)}-wrapped reference to the browser's `window.document`
  11989. * element.
  11990. */
  11991. function $DocumentProvider(){
  11992. this.$get = ['$window', function(window){
  11993. return jqLite(window.document);
  11994. }];
  11995. }
  11996. /**
  11997. * @ngdoc function
  11998. * @name ng.$exceptionHandler
  11999. * @requires $log
  12000. *
  12001. * @description
  12002. * Any uncaught exception in angular expressions is delegated to this service.
  12003. * The default implementation simply delegates to `$log.error` which logs it into
  12004. * the browser console.
  12005. *
  12006. * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
  12007. * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
  12008. *
  12009. * @param {Error} exception Exception associated with the error.
  12010. * @param {string=} cause optional information about the context in which
  12011. * the error was thrown.
  12012. *
  12013. */
  12014. function $ExceptionHandlerProvider() {
  12015. this.$get = ['$log', function($log){
  12016. return function(exception, cause) {
  12017. $log.error.apply($log, arguments);
  12018. };
  12019. }];
  12020. }
  12021. /**
  12022. * @ngdoc object
  12023. * @name ng.$interpolateProvider
  12024. * @function
  12025. *
  12026. * @description
  12027. *
  12028. * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
  12029. */
  12030. function $InterpolateProvider() {
  12031. var startSymbol = '{{';
  12032. var endSymbol = '}}';
  12033. /**
  12034. * @ngdoc method
  12035. * @name ng.$interpolateProvider#startSymbol
  12036. * @methodOf ng.$interpolateProvider
  12037. * @description
  12038. * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
  12039. *
  12040. * @param {string=} value new value to set the starting symbol to.
  12041. * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
  12042. */
  12043. this.startSymbol = function(value){
  12044. if (value) {
  12045. startSymbol = value;
  12046. return this;
  12047. } else {
  12048. return startSymbol;
  12049. }
  12050. };
  12051. /**
  12052. * @ngdoc method
  12053. * @name ng.$interpolateProvider#endSymbol
  12054. * @methodOf ng.$interpolateProvider
  12055. * @description
  12056. * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
  12057. *
  12058. * @param {string=} value new value to set the ending symbol to.
  12059. * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
  12060. */
  12061. this.endSymbol = function(value){
  12062. if (value) {
  12063. endSymbol = value;
  12064. return this;
  12065. } else {
  12066. return endSymbol;
  12067. }
  12068. };
  12069. this.$get = ['$parse', function($parse) {
  12070. var startSymbolLength = startSymbol.length,
  12071. endSymbolLength = endSymbol.length;
  12072. /**
  12073. * @ngdoc function
  12074. * @name ng.$interpolate
  12075. * @function
  12076. *
  12077. * @requires $parse
  12078. *
  12079. * @description
  12080. *
  12081. * Compiles a string with markup into an interpolation function. This service is used by the
  12082. * HTML {@link ng.$compile $compile} service for data binding. See
  12083. * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
  12084. * interpolation markup.
  12085. *
  12086. *
  12087. <pre>
  12088. var $interpolate = ...; // injected
  12089. var exp = $interpolate('Hello {{name}}!');
  12090. expect(exp({name:'Angular'}).toEqual('Hello Angular!');
  12091. </pre>
  12092. *
  12093. *
  12094. * @param {string} text The text with markup to interpolate.
  12095. * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
  12096. * embedded expression in order to return an interpolation function. Strings with no
  12097. * embedded expression will return null for the interpolation function.
  12098. * @returns {function(context)} an interpolation function which is used to compute the interpolated
  12099. * string. The function has these parameters:
  12100. *
  12101. * * `context`: an object against which any expressions embedded in the strings are evaluated
  12102. * against.
  12103. *
  12104. */
  12105. function $interpolate(text, mustHaveExpression) {
  12106. var startIndex,
  12107. endIndex,
  12108. index = 0,
  12109. parts = [],
  12110. length = text.length,
  12111. hasInterpolation = false,
  12112. fn,
  12113. exp,
  12114. concat = [];
  12115. while(index < length) {
  12116. if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
  12117. ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
  12118. (index != startIndex) && parts.push(text.substring(index, startIndex));
  12119. parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
  12120. fn.exp = exp;
  12121. index = endIndex + endSymbolLength;
  12122. hasInterpolation = true;
  12123. } else {
  12124. // we did not find anything, so we have to add the remainder to the parts array
  12125. (index != length) && parts.push(text.substring(index));
  12126. index = length;
  12127. }
  12128. }
  12129. if (!(length = parts.length)) {
  12130. // we added, nothing, must have been an empty string.
  12131. parts.push('');
  12132. length = 1;
  12133. }
  12134. if (!mustHaveExpression || hasInterpolation) {
  12135. concat.length = length;
  12136. fn = function(context) {
  12137. for(var i = 0, ii = length, part; i<ii; i++) {
  12138. if (typeof (part = parts[i]) == 'function') {
  12139. part = part(context);
  12140. if (part == null || part == undefined) {
  12141. part = '';
  12142. } else if (typeof part != 'string') {
  12143. part = toJson(part);
  12144. }
  12145. }
  12146. concat[i] = part;
  12147. }
  12148. return concat.join('');
  12149. };
  12150. fn.exp = text;
  12151. fn.parts = parts;
  12152. return fn;
  12153. }
  12154. }
  12155. /**
  12156. * @ngdoc method
  12157. * @name ng.$interpolate#startSymbol
  12158. * @methodOf ng.$interpolate
  12159. * @description
  12160. * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
  12161. *
  12162. * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
  12163. * the symbol.
  12164. *
  12165. * @returns {string} start symbol.
  12166. */
  12167. $interpolate.startSymbol = function() {
  12168. return startSymbol;
  12169. }
  12170. /**
  12171. * @ngdoc method
  12172. * @name ng.$interpolate#endSymbol
  12173. * @methodOf ng.$interpolate
  12174. * @description
  12175. * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
  12176. *
  12177. * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
  12178. * the symbol.
  12179. *
  12180. * @returns {string} start symbol.
  12181. */
  12182. $interpolate.endSymbol = function() {
  12183. return endSymbol;
  12184. }
  12185. return $interpolate;
  12186. }];
  12187. }
  12188. var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
  12189. PATH_MATCH = /^([^\?#]*)?(\?([^#]*))?(#(.*))?$/,
  12190. HASH_MATCH = PATH_MATCH,
  12191. DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
  12192. /**
  12193. * Encode path using encodeUriSegment, ignoring forward slashes
  12194. *
  12195. * @param {string} path Path to encode
  12196. * @returns {string}
  12197. */
  12198. function encodePath(path) {
  12199. var segments = path.split('/'),
  12200. i = segments.length;
  12201. while (i--) {
  12202. segments[i] = encodeUriSegment(segments[i]);
  12203. }
  12204. return segments.join('/');
  12205. }
  12206. function stripHash(url) {
  12207. return url.split('#')[0];
  12208. }
  12209. function matchUrl(url, obj) {
  12210. var match = URL_MATCH.exec(url);
  12211. match = {
  12212. protocol: match[1],
  12213. host: match[3],
  12214. port: int(match[5]) || DEFAULT_PORTS[match[1]] || null,
  12215. path: match[6] || '/',
  12216. search: match[8],
  12217. hash: match[10]
  12218. };
  12219. if (obj) {
  12220. obj.$$protocol = match.protocol;
  12221. obj.$$host = match.host;
  12222. obj.$$port = match.port;
  12223. }
  12224. return match;
  12225. }
  12226. function composeProtocolHostPort(protocol, host, port) {
  12227. return protocol + '://' + host + (port == DEFAULT_PORTS[protocol] ? '' : ':' + port);
  12228. }
  12229. function pathPrefixFromBase(basePath) {
  12230. return basePath.substr(0, basePath.lastIndexOf('/'));
  12231. }
  12232. function convertToHtml5Url(url, basePath, hashPrefix) {
  12233. var match = matchUrl(url);
  12234. // already html5 url
  12235. if (decodeURIComponent(match.path) != basePath || isUndefined(match.hash) ||
  12236. match.hash.indexOf(hashPrefix) !== 0) {
  12237. return url;
  12238. // convert hashbang url -> html5 url
  12239. } else {
  12240. return composeProtocolHostPort(match.protocol, match.host, match.port) +
  12241. pathPrefixFromBase(basePath) + match.hash.substr(hashPrefix.length);
  12242. }
  12243. }
  12244. function convertToHashbangUrl(url, basePath, hashPrefix) {
  12245. var match = matchUrl(url);
  12246. // already hashbang url
  12247. if (decodeURIComponent(match.path) == basePath && !isUndefined(match.hash) &&
  12248. match.hash.indexOf(hashPrefix) === 0) {
  12249. return url;
  12250. // convert html5 url -> hashbang url
  12251. } else {
  12252. var search = match.search && '?' + match.search || '',
  12253. hash = match.hash && '#' + match.hash || '',
  12254. pathPrefix = pathPrefixFromBase(basePath),
  12255. path = match.path.substr(pathPrefix.length);
  12256. if (match.path.indexOf(pathPrefix) !== 0) {
  12257. throw Error('Invalid url "' + url + '", missing path prefix "' + pathPrefix + '" !');
  12258. }
  12259. return composeProtocolHostPort(match.protocol, match.host, match.port) + basePath +
  12260. '#' + hashPrefix + path + search + hash;
  12261. }
  12262. }
  12263. /**
  12264. * LocationUrl represents an url
  12265. * This object is exposed as $location service when HTML5 mode is enabled and supported
  12266. *
  12267. * @constructor
  12268. * @param {string} url HTML5 url
  12269. * @param {string} pathPrefix
  12270. */
  12271. function LocationUrl(url, pathPrefix, appBaseUrl) {
  12272. pathPrefix = pathPrefix || '';
  12273. /**
  12274. * Parse given html5 (regular) url string into properties
  12275. * @param {string} newAbsoluteUrl HTML5 url
  12276. * @private
  12277. */
  12278. this.$$parse = function(newAbsoluteUrl) {
  12279. var match = matchUrl(newAbsoluteUrl, this);
  12280. if (match.path.indexOf(pathPrefix) !== 0) {
  12281. throw Error('Invalid url "' + newAbsoluteUrl + '", missing path prefix "' + pathPrefix + '" !');
  12282. }
  12283. this.$$path = decodeURIComponent(match.path.substr(pathPrefix.length));
  12284. this.$$search = parseKeyValue(match.search);
  12285. this.$$hash = match.hash && decodeURIComponent(match.hash) || '';
  12286. this.$$compose();
  12287. };
  12288. /**
  12289. * Compose url and update `absUrl` property
  12290. * @private
  12291. */
  12292. this.$$compose = function() {
  12293. var search = toKeyValue(this.$$search),
  12294. hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
  12295. this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
  12296. this.$$absUrl = composeProtocolHostPort(this.$$protocol, this.$$host, this.$$port) +
  12297. pathPrefix + this.$$url;
  12298. };
  12299. this.$$rewriteAppUrl = function(absoluteLinkUrl) {
  12300. if(absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
  12301. return absoluteLinkUrl;
  12302. }
  12303. }
  12304. this.$$parse(url);
  12305. }
  12306. /**
  12307. * LocationHashbangUrl represents url
  12308. * This object is exposed as $location service when html5 history api is disabled or not supported
  12309. *
  12310. * @constructor
  12311. * @param {string} url Legacy url
  12312. * @param {string} hashPrefix Prefix for hash part (containing path and search)
  12313. */
  12314. function LocationHashbangUrl(url, hashPrefix, appBaseUrl) {
  12315. var basePath;
  12316. /**
  12317. * Parse given hashbang url into properties
  12318. * @param {string} url Hashbang url
  12319. * @private
  12320. */
  12321. this.$$parse = function(url) {
  12322. var match = matchUrl(url, this);
  12323. if (match.hash && match.hash.indexOf(hashPrefix) !== 0) {
  12324. throw Error('Invalid url "' + url + '", missing hash prefix "' + hashPrefix + '" !');
  12325. }
  12326. basePath = match.path + (match.search ? '?' + match.search : '');
  12327. match = HASH_MATCH.exec((match.hash || '').substr(hashPrefix.length));
  12328. if (match[1]) {
  12329. this.$$path = (match[1].charAt(0) == '/' ? '' : '/') + decodeURIComponent(match[1]);
  12330. } else {
  12331. this.$$path = '';
  12332. }
  12333. this.$$search = parseKeyValue(match[3]);
  12334. this.$$hash = match[5] && decodeURIComponent(match[5]) || '';
  12335. this.$$compose();
  12336. };
  12337. /**
  12338. * Compose hashbang url and update `absUrl` property
  12339. * @private
  12340. */
  12341. this.$$compose = function() {
  12342. var search = toKeyValue(this.$$search),
  12343. hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
  12344. this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
  12345. this.$$absUrl = composeProtocolHostPort(this.$$protocol, this.$$host, this.$$port) +
  12346. basePath + (this.$$url ? '#' + hashPrefix + this.$$url : '');
  12347. };
  12348. this.$$rewriteAppUrl = function(absoluteLinkUrl) {
  12349. if(absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
  12350. return absoluteLinkUrl;
  12351. }
  12352. }
  12353. this.$$parse(url);
  12354. }
  12355. LocationUrl.prototype = {
  12356. /**
  12357. * Has any change been replacing ?
  12358. * @private
  12359. */
  12360. $$replace: false,
  12361. /**
  12362. * @ngdoc method
  12363. * @name ng.$location#absUrl
  12364. * @methodOf ng.$location
  12365. *
  12366. * @description
  12367. * This method is getter only.
  12368. *
  12369. * Return full url representation with all segments encoded according to rules specified in
  12370. * {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}.
  12371. *
  12372. * @return {string} full url
  12373. */
  12374. absUrl: locationGetter('$$absUrl'),
  12375. /**
  12376. * @ngdoc method
  12377. * @name ng.$location#url
  12378. * @methodOf ng.$location
  12379. *
  12380. * @description
  12381. * This method is getter / setter.
  12382. *
  12383. * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
  12384. *
  12385. * Change path, search and hash, when called with parameter and return `$location`.
  12386. *
  12387. * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
  12388. * @return {string} url
  12389. */
  12390. url: function(url, replace) {
  12391. if (isUndefined(url))
  12392. return this.$$url;
  12393. var match = PATH_MATCH.exec(url);
  12394. if (match[1]) this.path(decodeURIComponent(match[1]));
  12395. if (match[2] || match[1]) this.search(match[3] || '');
  12396. this.hash(match[5] || '', replace);
  12397. return this;
  12398. },
  12399. /**
  12400. * @ngdoc method
  12401. * @name ng.$location#protocol
  12402. * @methodOf ng.$location
  12403. *
  12404. * @description
  12405. * This method is getter only.
  12406. *
  12407. * Return protocol of current url.
  12408. *
  12409. * @return {string} protocol of current url
  12410. */
  12411. protocol: locationGetter('$$protocol'),
  12412. /**
  12413. * @ngdoc method
  12414. * @name ng.$location#host
  12415. * @methodOf ng.$location
  12416. *
  12417. * @description
  12418. * This method is getter only.
  12419. *
  12420. * Return host of current url.
  12421. *
  12422. * @return {string} host of current url.
  12423. */
  12424. host: locationGetter('$$host'),
  12425. /**
  12426. * @ngdoc method
  12427. * @name ng.$location#port
  12428. * @methodOf ng.$location
  12429. *
  12430. * @description
  12431. * This method is getter only.
  12432. *
  12433. * Return port of current url.
  12434. *
  12435. * @return {Number} port
  12436. */
  12437. port: locationGetter('$$port'),
  12438. /**
  12439. * @ngdoc method
  12440. * @name ng.$location#path
  12441. * @methodOf ng.$location
  12442. *
  12443. * @description
  12444. * This method is getter / setter.
  12445. *
  12446. * Return path of current url when called without any parameter.
  12447. *
  12448. * Change path when called with parameter and return `$location`.
  12449. *
  12450. * Note: Path should always begin with forward slash (/), this method will add the forward slash
  12451. * if it is missing.
  12452. *
  12453. * @param {string=} path New path
  12454. * @return {string} path
  12455. */
  12456. path: locationGetterSetter('$$path', function(path) {
  12457. return path.charAt(0) == '/' ? path : '/' + path;
  12458. }),
  12459. /**
  12460. * @ngdoc method
  12461. * @name ng.$location#search
  12462. * @methodOf ng.$location
  12463. *
  12464. * @description
  12465. * This method is getter / setter.
  12466. *
  12467. * Return search part (as object) of current url when called without any parameter.
  12468. *
  12469. * Change search part when called with parameter and return `$location`.
  12470. *
  12471. * @param {string|object<string,string>=} search New search params - string or hash object
  12472. * @param {string=} paramValue If `search` is a string, then `paramValue` will override only a
  12473. * single search parameter. If the value is `null`, the parameter will be deleted.
  12474. *
  12475. * @return {string} search
  12476. */
  12477. search: function(search, paramValue) {
  12478. if (isUndefined(search))
  12479. return this.$$search;
  12480. if (isDefined(paramValue)) {
  12481. if (paramValue === null) {
  12482. delete this.$$search[search];
  12483. } else {
  12484. this.$$search[search] = paramValue;
  12485. }
  12486. } else {
  12487. this.$$search = isString(search) ? parseKeyValue(search) : search;
  12488. }
  12489. this.$$compose();
  12490. return this;
  12491. },
  12492. /**
  12493. * @ngdoc method
  12494. * @name ng.$location#hash
  12495. * @methodOf ng.$location
  12496. *
  12497. * @description
  12498. * This method is getter / setter.
  12499. *
  12500. * Return hash fragment when called without any parameter.
  12501. *
  12502. * Change hash fragment when called with parameter and return `$location`.
  12503. *
  12504. * @param {string=} hash New hash fragment
  12505. * @return {string} hash
  12506. */
  12507. hash: locationGetterSetter('$$hash', identity),
  12508. /**
  12509. * @ngdoc method
  12510. * @name ng.$location#replace
  12511. * @methodOf ng.$location
  12512. *
  12513. * @description
  12514. * If called, all changes to $location during current `$digest` will be replacing current history
  12515. * record, instead of adding new one.
  12516. */
  12517. replace: function() {
  12518. this.$$replace = true;
  12519. return this;
  12520. }
  12521. };
  12522. LocationHashbangUrl.prototype = inherit(LocationUrl.prototype);
  12523. function LocationHashbangInHtml5Url(url, hashPrefix, appBaseUrl, baseExtra) {
  12524. LocationHashbangUrl.apply(this, arguments);
  12525. this.$$rewriteAppUrl = function(absoluteLinkUrl) {
  12526. if (absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
  12527. return appBaseUrl + baseExtra + '#' + hashPrefix + absoluteLinkUrl.substr(appBaseUrl.length);
  12528. }
  12529. }
  12530. }
  12531. LocationHashbangInHtml5Url.prototype = inherit(LocationHashbangUrl.prototype);
  12532. function locationGetter(property) {
  12533. return function() {
  12534. return this[property];
  12535. };
  12536. }
  12537. function locationGetterSetter(property, preprocess) {
  12538. return function(value) {
  12539. if (isUndefined(value))
  12540. return this[property];
  12541. this[property] = preprocess(value);
  12542. this.$$compose();
  12543. return this;
  12544. };
  12545. }
  12546. /**
  12547. * @ngdoc object
  12548. * @name ng.$location
  12549. *
  12550. * @requires $browser
  12551. * @requires $sniffer
  12552. * @requires $rootElement
  12553. *
  12554. * @description
  12555. * The $location service parses the URL in the browser address bar (based on the
  12556. * {@link https://developer.mozilla.org/en/window.location window.location}) and makes the URL
  12557. * available to your application. Changes to the URL in the address bar are reflected into
  12558. * $location service and changes to $location are reflected into the browser address bar.
  12559. *
  12560. * **The $location service:**
  12561. *
  12562. * - Exposes the current URL in the browser address bar, so you can
  12563. * - Watch and observe the URL.
  12564. * - Change the URL.
  12565. * - Synchronizes the URL with the browser when the user
  12566. * - Changes the address bar.
  12567. * - Clicks the back or forward button (or clicks a History link).
  12568. * - Clicks on a link.
  12569. * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
  12570. *
  12571. * For more information see {@link guide/dev_guide.services.$location Developer Guide: Angular
  12572. * Services: Using $location}
  12573. */
  12574. /**
  12575. * @ngdoc object
  12576. * @name ng.$locationProvider
  12577. * @description
  12578. * Use the `$locationProvider` to configure how the application deep linking paths are stored.
  12579. */
  12580. function $LocationProvider(){
  12581. var hashPrefix = '',
  12582. html5Mode = false;
  12583. /**
  12584. * @ngdoc property
  12585. * @name ng.$locationProvider#hashPrefix
  12586. * @methodOf ng.$locationProvider
  12587. * @description
  12588. * @param {string=} prefix Prefix for hash part (containing path and search)
  12589. * @returns {*} current value if used as getter or itself (chaining) if used as setter
  12590. */
  12591. this.hashPrefix = function(prefix) {
  12592. if (isDefined(prefix)) {
  12593. hashPrefix = prefix;
  12594. return this;
  12595. } else {
  12596. return hashPrefix;
  12597. }
  12598. };
  12599. /**
  12600. * @ngdoc property
  12601. * @name ng.$locationProvider#html5Mode
  12602. * @methodOf ng.$locationProvider
  12603. * @description
  12604. * @param {string=} mode Use HTML5 strategy if available.
  12605. * @returns {*} current value if used as getter or itself (chaining) if used as setter
  12606. */
  12607. this.html5Mode = function(mode) {
  12608. if (isDefined(mode)) {
  12609. html5Mode = mode;
  12610. return this;
  12611. } else {
  12612. return html5Mode;
  12613. }
  12614. };
  12615. this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
  12616. function( $rootScope, $browser, $sniffer, $rootElement) {
  12617. var $location,
  12618. basePath,
  12619. pathPrefix,
  12620. initUrl = $browser.url(),
  12621. initUrlParts = matchUrl(initUrl),
  12622. appBaseUrl;
  12623. if (html5Mode) {
  12624. basePath = $browser.baseHref() || '/';
  12625. pathPrefix = pathPrefixFromBase(basePath);
  12626. appBaseUrl =
  12627. composeProtocolHostPort(initUrlParts.protocol, initUrlParts.host, initUrlParts.port) +
  12628. pathPrefix + '/';
  12629. if ($sniffer.history) {
  12630. $location = new LocationUrl(
  12631. convertToHtml5Url(initUrl, basePath, hashPrefix),
  12632. pathPrefix, appBaseUrl);
  12633. } else {
  12634. $location = new LocationHashbangInHtml5Url(
  12635. convertToHashbangUrl(initUrl, basePath, hashPrefix),
  12636. hashPrefix, appBaseUrl, basePath.substr(pathPrefix.length + 1));
  12637. }
  12638. } else {
  12639. appBaseUrl =
  12640. composeProtocolHostPort(initUrlParts.protocol, initUrlParts.host, initUrlParts.port) +
  12641. (initUrlParts.path || '') +
  12642. (initUrlParts.search ? ('?' + initUrlParts.search) : '') +
  12643. '#' + hashPrefix + '/';
  12644. $location = new LocationHashbangUrl(initUrl, hashPrefix, appBaseUrl);
  12645. }
  12646. $rootElement.bind('click', function(event) {
  12647. // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
  12648. // currently we open nice url link and redirect then
  12649. if (event.ctrlKey || event.metaKey || event.which == 2) return;
  12650. var elm = jqLite(event.target);
  12651. // traverse the DOM up to find first A tag
  12652. while (lowercase(elm[0].nodeName) !== 'a') {
  12653. // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
  12654. if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
  12655. }
  12656. var absHref = elm.prop('href'),
  12657. rewrittenUrl = $location.$$rewriteAppUrl(absHref);
  12658. if (absHref && !elm.attr('target') && rewrittenUrl) {
  12659. // update location manually
  12660. $location.$$parse(rewrittenUrl);
  12661. $rootScope.$apply();
  12662. event.preventDefault();
  12663. // hack to work around FF6 bug 684208 when scenario runner clicks on links
  12664. window.angular['ff-684208-preventDefault'] = true;
  12665. }
  12666. });
  12667. // rewrite hashbang url <> html5 url
  12668. if ($location.absUrl() != initUrl) {
  12669. $browser.url($location.absUrl(), true);
  12670. }
  12671. // update $location when $browser url changes
  12672. $browser.onUrlChange(function(newUrl) {
  12673. if ($location.absUrl() != newUrl) {
  12674. $rootScope.$evalAsync(function() {
  12675. var oldUrl = $location.absUrl();
  12676. $location.$$parse(newUrl);
  12677. afterLocationChange(oldUrl);
  12678. });
  12679. if (!$rootScope.$$phase) $rootScope.$digest();
  12680. }
  12681. });
  12682. // update browser
  12683. var changeCounter = 0;
  12684. $rootScope.$watch(function $locationWatch() {
  12685. var oldUrl = $browser.url();
  12686. var currentReplace = $location.$$replace;
  12687. if (!changeCounter || oldUrl != $location.absUrl()) {
  12688. changeCounter++;
  12689. $rootScope.$evalAsync(function() {
  12690. if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
  12691. defaultPrevented) {
  12692. $location.$$parse(oldUrl);
  12693. } else {
  12694. $browser.url($location.absUrl(), currentReplace);
  12695. afterLocationChange(oldUrl);
  12696. }
  12697. });
  12698. }
  12699. $location.$$replace = false;
  12700. return changeCounter;
  12701. });
  12702. return $location;
  12703. function afterLocationChange(oldUrl) {
  12704. $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
  12705. }
  12706. }];
  12707. }
  12708. /**
  12709. * @ngdoc object
  12710. * @name ng.$log
  12711. * @requires $window
  12712. *
  12713. * @description
  12714. * Simple service for logging. Default implementation writes the message
  12715. * into the browser's console (if present).
  12716. *
  12717. * The main purpose of this service is to simplify debugging and troubleshooting.
  12718. *
  12719. * @example
  12720. <example>
  12721. <file name="script.js">
  12722. function LogCtrl($scope, $log) {
  12723. $scope.$log = $log;
  12724. $scope.message = 'Hello World!';
  12725. }
  12726. </file>
  12727. <file name="index.html">
  12728. <div ng-controller="LogCtrl">
  12729. <p>Reload this page with open console, enter text and hit the log button...</p>
  12730. Message:
  12731. <input type="text" ng-model="message"/>
  12732. <button ng-click="$log.log(message)">log</button>
  12733. <button ng-click="$log.warn(message)">warn</button>
  12734. <button ng-click="$log.info(message)">info</button>
  12735. <button ng-click="$log.error(message)">error</button>
  12736. </div>
  12737. </file>
  12738. </example>
  12739. */
  12740. function $LogProvider(){
  12741. this.$get = ['$window', function($window){
  12742. return {
  12743. /**
  12744. * @ngdoc method
  12745. * @name ng.$log#log
  12746. * @methodOf ng.$log
  12747. *
  12748. * @description
  12749. * Write a log message
  12750. */
  12751. log: consoleLog('log'),
  12752. /**
  12753. * @ngdoc method
  12754. * @name ng.$log#warn
  12755. * @methodOf ng.$log
  12756. *
  12757. * @description
  12758. * Write a warning message
  12759. */
  12760. warn: consoleLog('warn'),
  12761. /**
  12762. * @ngdoc method
  12763. * @name ng.$log#info
  12764. * @methodOf ng.$log
  12765. *
  12766. * @description
  12767. * Write an information message
  12768. */
  12769. info: consoleLog('info'),
  12770. /**
  12771. * @ngdoc method
  12772. * @name ng.$log#error
  12773. * @methodOf ng.$log
  12774. *
  12775. * @description
  12776. * Write an error message
  12777. */
  12778. error: consoleLog('error')
  12779. };
  12780. function formatError(arg) {
  12781. if (arg instanceof Error) {
  12782. if (arg.stack) {
  12783. arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
  12784. ? 'Error: ' + arg.message + '\n' + arg.stack
  12785. : arg.stack;
  12786. } else if (arg.sourceURL) {
  12787. arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
  12788. }
  12789. }
  12790. return arg;
  12791. }
  12792. function consoleLog(type) {
  12793. var console = $window.console || {},
  12794. logFn = console[type] || console.log || noop;
  12795. if (logFn.apply) {
  12796. return function() {
  12797. var args = [];
  12798. forEach(arguments, function(arg) {
  12799. args.push(formatError(arg));
  12800. });
  12801. return logFn.apply(console, args);
  12802. };
  12803. }
  12804. // we are IE which either doesn't have window.console => this is noop and we do nothing,
  12805. // or we are IE where console.log doesn't have apply so we log at least first 2 args
  12806. return function(arg1, arg2) {
  12807. logFn(arg1, arg2);
  12808. }
  12809. }
  12810. }];
  12811. }
  12812. var OPERATORS = {
  12813. 'null':function(){return null;},
  12814. 'true':function(){return true;},
  12815. 'false':function(){return false;},
  12816. undefined:noop,
  12817. '+':function(self, locals, a,b){
  12818. a=a(self, locals); b=b(self, locals);
  12819. if (isDefined(a)) {
  12820. if (isDefined(b)) {
  12821. return a + b;
  12822. }
  12823. return a;
  12824. }
  12825. return isDefined(b)?b:undefined;},
  12826. '-':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
  12827. '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
  12828. '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
  12829. '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
  12830. '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
  12831. '=':noop,
  12832. '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
  12833. '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
  12834. '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
  12835. '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
  12836. '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
  12837. '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
  12838. '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
  12839. '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
  12840. '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
  12841. // '|':function(self, locals, a,b){return a|b;},
  12842. '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
  12843. '!':function(self, locals, a){return !a(self, locals);}
  12844. };
  12845. var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
  12846. function lex(text, csp){
  12847. var tokens = [],
  12848. token,
  12849. index = 0,
  12850. json = [],
  12851. ch,
  12852. lastCh = ':'; // can start regexp
  12853. while (index < text.length) {
  12854. ch = text.charAt(index);
  12855. if (is('"\'')) {
  12856. readString(ch);
  12857. } else if (isNumber(ch) || is('.') && isNumber(peek())) {
  12858. readNumber();
  12859. } else if (isIdent(ch)) {
  12860. readIdent();
  12861. // identifiers can only be if the preceding char was a { or ,
  12862. if (was('{,') && json[0]=='{' &&
  12863. (token=tokens[tokens.length-1])) {
  12864. token.json = token.text.indexOf('.') == -1;
  12865. }
  12866. } else if (is('(){}[].,;:')) {
  12867. tokens.push({
  12868. index:index,
  12869. text:ch,
  12870. json:(was(':[,') && is('{[')) || is('}]:,')
  12871. });
  12872. if (is('{[')) json.unshift(ch);
  12873. if (is('}]')) json.shift();
  12874. index++;
  12875. } else if (isWhitespace(ch)) {
  12876. index++;
  12877. continue;
  12878. } else {
  12879. var ch2 = ch + peek(),
  12880. fn = OPERATORS[ch],
  12881. fn2 = OPERATORS[ch2];
  12882. if (fn2) {
  12883. tokens.push({index:index, text:ch2, fn:fn2});
  12884. index += 2;
  12885. } else if (fn) {
  12886. tokens.push({index:index, text:ch, fn:fn, json: was('[,:') && is('+-')});
  12887. index += 1;
  12888. } else {
  12889. throwError("Unexpected next character ", index, index+1);
  12890. }
  12891. }
  12892. lastCh = ch;
  12893. }
  12894. return tokens;
  12895. function is(chars) {
  12896. return chars.indexOf(ch) != -1;
  12897. }
  12898. function was(chars) {
  12899. return chars.indexOf(lastCh) != -1;
  12900. }
  12901. function peek() {
  12902. return index + 1 < text.length ? text.charAt(index + 1) : false;
  12903. }
  12904. function isNumber(ch) {
  12905. return '0' <= ch && ch <= '9';
  12906. }
  12907. function isWhitespace(ch) {
  12908. return ch == ' ' || ch == '\r' || ch == '\t' ||
  12909. ch == '\n' || ch == '\v' || ch == '\u00A0'; // IE treats non-breaking space as \u00A0
  12910. }
  12911. function isIdent(ch) {
  12912. return 'a' <= ch && ch <= 'z' ||
  12913. 'A' <= ch && ch <= 'Z' ||
  12914. '_' == ch || ch == '$';
  12915. }
  12916. function isExpOperator(ch) {
  12917. return ch == '-' || ch == '+' || isNumber(ch);
  12918. }
  12919. function throwError(error, start, end) {
  12920. end = end || index;
  12921. throw Error("Lexer Error: " + error + " at column" +
  12922. (isDefined(start)
  12923. ? "s " + start + "-" + index + " [" + text.substring(start, end) + "]"
  12924. : " " + end) +
  12925. " in expression [" + text + "].");
  12926. }
  12927. function readNumber() {
  12928. var number = "";
  12929. var start = index;
  12930. while (index < text.length) {
  12931. var ch = lowercase(text.charAt(index));
  12932. if (ch == '.' || isNumber(ch)) {
  12933. number += ch;
  12934. } else {
  12935. var peekCh = peek();
  12936. if (ch == 'e' && isExpOperator(peekCh)) {
  12937. number += ch;
  12938. } else if (isExpOperator(ch) &&
  12939. peekCh && isNumber(peekCh) &&
  12940. number.charAt(number.length - 1) == 'e') {
  12941. number += ch;
  12942. } else if (isExpOperator(ch) &&
  12943. (!peekCh || !isNumber(peekCh)) &&
  12944. number.charAt(number.length - 1) == 'e') {
  12945. throwError('Invalid exponent');
  12946. } else {
  12947. break;
  12948. }
  12949. }
  12950. index++;
  12951. }
  12952. number = 1 * number;
  12953. tokens.push({index:start, text:number, json:true,
  12954. fn:function() {return number;}});
  12955. }
  12956. function readIdent() {
  12957. var ident = "",
  12958. start = index,
  12959. lastDot, peekIndex, methodName;
  12960. while (index < text.length) {
  12961. var ch = text.charAt(index);
  12962. if (ch == '.' || isIdent(ch) || isNumber(ch)) {
  12963. if (ch == '.') lastDot = index;
  12964. ident += ch;
  12965. } else {
  12966. break;
  12967. }
  12968. index++;
  12969. }
  12970. //check if this is not a method invocation and if it is back out to last dot
  12971. if (lastDot) {
  12972. peekIndex = index;
  12973. while(peekIndex < text.length) {
  12974. var ch = text.charAt(peekIndex);
  12975. if (ch == '(') {
  12976. methodName = ident.substr(lastDot - start + 1);
  12977. ident = ident.substr(0, lastDot - start);
  12978. index = peekIndex;
  12979. break;
  12980. }
  12981. if(isWhitespace(ch)) {
  12982. peekIndex++;
  12983. } else {
  12984. break;
  12985. }
  12986. }
  12987. }
  12988. var token = {
  12989. index:start,
  12990. text:ident
  12991. };
  12992. if (OPERATORS.hasOwnProperty(ident)) {
  12993. token.fn = token.json = OPERATORS[ident];
  12994. } else {
  12995. var getter = getterFn(ident, csp);
  12996. token.fn = extend(function(self, locals) {
  12997. return (getter(self, locals));
  12998. }, {
  12999. assign: function(self, value) {
  13000. return setter(self, ident, value);
  13001. }
  13002. });
  13003. }
  13004. tokens.push(token);
  13005. if (methodName) {
  13006. tokens.push({
  13007. index:lastDot,
  13008. text: '.',
  13009. json: false
  13010. });
  13011. tokens.push({
  13012. index: lastDot + 1,
  13013. text: methodName,
  13014. json: false
  13015. });
  13016. }
  13017. }
  13018. function readString(quote) {
  13019. var start = index;
  13020. index++;
  13021. var string = "";
  13022. var rawString = quote;
  13023. var escape = false;
  13024. while (index < text.length) {
  13025. var ch = text.charAt(index);
  13026. rawString += ch;
  13027. if (escape) {
  13028. if (ch == 'u') {
  13029. var hex = text.substring(index + 1, index + 5);
  13030. if (!hex.match(/[\da-f]{4}/i))
  13031. throwError( "Invalid unicode escape [\\u" + hex + "]");
  13032. index += 4;
  13033. string += String.fromCharCode(parseInt(hex, 16));
  13034. } else {
  13035. var rep = ESCAPE[ch];
  13036. if (rep) {
  13037. string += rep;
  13038. } else {
  13039. string += ch;
  13040. }
  13041. }
  13042. escape = false;
  13043. } else if (ch == '\\') {
  13044. escape = true;
  13045. } else if (ch == quote) {
  13046. index++;
  13047. tokens.push({
  13048. index:start,
  13049. text:rawString,
  13050. string:string,
  13051. json:true,
  13052. fn:function() { return string; }
  13053. });
  13054. return;
  13055. } else {
  13056. string += ch;
  13057. }
  13058. index++;
  13059. }
  13060. throwError("Unterminated quote", start);
  13061. }
  13062. }
  13063. /////////////////////////////////////////
  13064. function parser(text, json, $filter, csp){
  13065. var ZERO = valueFn(0),
  13066. value,
  13067. tokens = lex(text, csp),
  13068. assignment = _assignment,
  13069. functionCall = _functionCall,
  13070. fieldAccess = _fieldAccess,
  13071. objectIndex = _objectIndex,
  13072. filterChain = _filterChain;
  13073. if(json){
  13074. // The extra level of aliasing is here, just in case the lexer misses something, so that
  13075. // we prevent any accidental execution in JSON.
  13076. assignment = logicalOR;
  13077. functionCall =
  13078. fieldAccess =
  13079. objectIndex =
  13080. filterChain =
  13081. function() { throwError("is not valid json", {text:text, index:0}); };
  13082. value = primary();
  13083. } else {
  13084. value = statements();
  13085. }
  13086. if (tokens.length !== 0) {
  13087. throwError("is an unexpected token", tokens[0]);
  13088. }
  13089. return value;
  13090. ///////////////////////////////////
  13091. function throwError(msg, token) {
  13092. throw Error("Syntax Error: Token '" + token.text +
  13093. "' " + msg + " at column " +
  13094. (token.index + 1) + " of the expression [" +
  13095. text + "] starting at [" + text.substring(token.index) + "].");
  13096. }
  13097. function peekToken() {
  13098. if (tokens.length === 0)
  13099. throw Error("Unexpected end of expression: " + text);
  13100. return tokens[0];
  13101. }
  13102. function peek(e1, e2, e3, e4) {
  13103. if (tokens.length > 0) {
  13104. var token = tokens[0];
  13105. var t = token.text;
  13106. if (t==e1 || t==e2 || t==e3 || t==e4 ||
  13107. (!e1 && !e2 && !e3 && !e4)) {
  13108. return token;
  13109. }
  13110. }
  13111. return false;
  13112. }
  13113. function expect(e1, e2, e3, e4){
  13114. var token = peek(e1, e2, e3, e4);
  13115. if (token) {
  13116. if (json && !token.json) {
  13117. throwError("is not valid json", token);
  13118. }
  13119. tokens.shift();
  13120. return token;
  13121. }
  13122. return false;
  13123. }
  13124. function consume(e1){
  13125. if (!expect(e1)) {
  13126. throwError("is unexpected, expecting [" + e1 + "]", peek());
  13127. }
  13128. }
  13129. function unaryFn(fn, right) {
  13130. return function(self, locals) {
  13131. return fn(self, locals, right);
  13132. };
  13133. }
  13134. function binaryFn(left, fn, right) {
  13135. return function(self, locals) {
  13136. return fn(self, locals, left, right);
  13137. };
  13138. }
  13139. function statements() {
  13140. var statements = [];
  13141. while(true) {
  13142. if (tokens.length > 0 && !peek('}', ')', ';', ']'))
  13143. statements.push(filterChain());
  13144. if (!expect(';')) {
  13145. // optimize for the common case where there is only one statement.
  13146. // TODO(size): maybe we should not support multiple statements?
  13147. return statements.length == 1
  13148. ? statements[0]
  13149. : function(self, locals){
  13150. var value;
  13151. for ( var i = 0; i < statements.length; i++) {
  13152. var statement = statements[i];
  13153. if (statement)
  13154. value = statement(self, locals);
  13155. }
  13156. return value;
  13157. };
  13158. }
  13159. }
  13160. }
  13161. function _filterChain() {
  13162. var left = expression();
  13163. var token;
  13164. while(true) {
  13165. if ((token = expect('|'))) {
  13166. left = binaryFn(left, token.fn, filter());
  13167. } else {
  13168. return left;
  13169. }
  13170. }
  13171. }
  13172. function filter() {
  13173. var token = expect();
  13174. var fn = $filter(token.text);
  13175. var argsFn = [];
  13176. while(true) {
  13177. if ((token = expect(':'))) {
  13178. argsFn.push(expression());
  13179. } else {
  13180. var fnInvoke = function(self, locals, input){
  13181. var args = [input];
  13182. for ( var i = 0; i < argsFn.length; i++) {
  13183. args.push(argsFn[i](self, locals));
  13184. }
  13185. return fn.apply(self, args);
  13186. };
  13187. return function() {
  13188. return fnInvoke;
  13189. };
  13190. }
  13191. }
  13192. }
  13193. function expression() {
  13194. return assignment();
  13195. }
  13196. function _assignment() {
  13197. var left = logicalOR();
  13198. var right;
  13199. var token;
  13200. if ((token = expect('='))) {
  13201. if (!left.assign) {
  13202. throwError("implies assignment but [" +
  13203. text.substring(0, token.index) + "] can not be assigned to", token);
  13204. }
  13205. right = logicalOR();
  13206. return function(self, locals){
  13207. return left.assign(self, right(self, locals), locals);
  13208. };
  13209. } else {
  13210. return left;
  13211. }
  13212. }
  13213. function logicalOR() {
  13214. var left = logicalAND();
  13215. var token;
  13216. while(true) {
  13217. if ((token = expect('||'))) {
  13218. left = binaryFn(left, token.fn, logicalAND());
  13219. } else {
  13220. return left;
  13221. }
  13222. }
  13223. }
  13224. function logicalAND() {
  13225. var left = equality();
  13226. var token;
  13227. if ((token = expect('&&'))) {
  13228. left = binaryFn(left, token.fn, logicalAND());
  13229. }
  13230. return left;
  13231. }
  13232. function equality() {
  13233. var left = relational();
  13234. var token;
  13235. if ((token = expect('==','!='))) {
  13236. left = binaryFn(left, token.fn, equality());
  13237. }
  13238. return left;
  13239. }
  13240. function relational() {
  13241. var left = additive();
  13242. var token;
  13243. if ((token = expect('<', '>', '<=', '>='))) {
  13244. left = binaryFn(left, token.fn, relational());
  13245. }
  13246. return left;
  13247. }
  13248. function additive() {
  13249. var left = multiplicative();
  13250. var token;
  13251. while ((token = expect('+','-'))) {
  13252. left = binaryFn(left, token.fn, multiplicative());
  13253. }
  13254. return left;
  13255. }
  13256. function multiplicative() {
  13257. var left = unary();
  13258. var token;
  13259. while ((token = expect('*','/','%'))) {
  13260. left = binaryFn(left, token.fn, unary());
  13261. }
  13262. return left;
  13263. }
  13264. function unary() {
  13265. var token;
  13266. if (expect('+')) {
  13267. return primary();
  13268. } else if ((token = expect('-'))) {
  13269. return binaryFn(ZERO, token.fn, unary());
  13270. } else if ((token = expect('!'))) {
  13271. return unaryFn(token.fn, unary());
  13272. } else {
  13273. return primary();
  13274. }
  13275. }
  13276. function primary() {
  13277. var primary;
  13278. if (expect('(')) {
  13279. primary = filterChain();
  13280. consume(')');
  13281. } else if (expect('[')) {
  13282. primary = arrayDeclaration();
  13283. } else if (expect('{')) {
  13284. primary = object();
  13285. } else {
  13286. var token = expect();
  13287. primary = token.fn;
  13288. if (!primary) {
  13289. throwError("not a primary expression", token);
  13290. }
  13291. }
  13292. var next, context;
  13293. while ((next = expect('(', '[', '.'))) {
  13294. if (next.text === '(') {
  13295. primary = functionCall(primary, context);
  13296. context = null;
  13297. } else if (next.text === '[') {
  13298. context = primary;
  13299. primary = objectIndex(primary);
  13300. } else if (next.text === '.') {
  13301. context = primary;
  13302. primary = fieldAccess(primary);
  13303. } else {
  13304. throwError("IMPOSSIBLE");
  13305. }
  13306. }
  13307. return primary;
  13308. }
  13309. function _fieldAccess(object) {
  13310. var field = expect().text;
  13311. var getter = getterFn(field, csp);
  13312. return extend(
  13313. function(self, locals) {
  13314. return getter(object(self, locals), locals);
  13315. },
  13316. {
  13317. assign:function(self, value, locals) {
  13318. return setter(object(self, locals), field, value);
  13319. }
  13320. }
  13321. );
  13322. }
  13323. function _objectIndex(obj) {
  13324. var indexFn = expression();
  13325. consume(']');
  13326. return extend(
  13327. function(self, locals){
  13328. var o = obj(self, locals),
  13329. i = indexFn(self, locals),
  13330. v, p;
  13331. if (!o) return undefined;
  13332. v = o[i];
  13333. if (v && v.then) {
  13334. p = v;
  13335. if (!('$$v' in v)) {
  13336. p.$$v = undefined;
  13337. p.then(function(val) { p.$$v = val; });
  13338. }
  13339. v = v.$$v;
  13340. }
  13341. return v;
  13342. }, {
  13343. assign:function(self, value, locals){
  13344. return obj(self, locals)[indexFn(self, locals)] = value;
  13345. }
  13346. });
  13347. }
  13348. function _functionCall(fn, contextGetter) {
  13349. var argsFn = [];
  13350. if (peekToken().text != ')') {
  13351. do {
  13352. argsFn.push(expression());
  13353. } while (expect(','));
  13354. }
  13355. consume(')');
  13356. return function(self, locals){
  13357. var args = [],
  13358. context = contextGetter ? contextGetter(self, locals) : self;
  13359. for ( var i = 0; i < argsFn.length; i++) {
  13360. args.push(argsFn[i](self, locals));
  13361. }
  13362. var fnPtr = fn(self, locals) || noop;
  13363. // IE stupidity!
  13364. return fnPtr.apply
  13365. ? fnPtr.apply(context, args)
  13366. : fnPtr(args[0], args[1], args[2], args[3], args[4]);
  13367. };
  13368. }
  13369. // This is used with json array declaration
  13370. function arrayDeclaration () {
  13371. var elementFns = [];
  13372. if (peekToken().text != ']') {
  13373. do {
  13374. elementFns.push(expression());
  13375. } while (expect(','));
  13376. }
  13377. consume(']');
  13378. return function(self, locals){
  13379. var array = [];
  13380. for ( var i = 0; i < elementFns.length; i++) {
  13381. array.push(elementFns[i](self, locals));
  13382. }
  13383. return array;
  13384. };
  13385. }
  13386. function object () {
  13387. var keyValues = [];
  13388. if (peekToken().text != '}') {
  13389. do {
  13390. var token = expect(),
  13391. key = token.string || token.text;
  13392. consume(":");
  13393. var value = expression();
  13394. keyValues.push({key:key, value:value});
  13395. } while (expect(','));
  13396. }
  13397. consume('}');
  13398. return function(self, locals){
  13399. var object = {};
  13400. for ( var i = 0; i < keyValues.length; i++) {
  13401. var keyValue = keyValues[i];
  13402. var value = keyValue.value(self, locals);
  13403. object[keyValue.key] = value;
  13404. }
  13405. return object;
  13406. };
  13407. }
  13408. }
  13409. //////////////////////////////////////////////////
  13410. // Parser helper functions
  13411. //////////////////////////////////////////////////
  13412. function setter(obj, path, setValue) {
  13413. var element = path.split('.');
  13414. for (var i = 0; element.length > 1; i++) {
  13415. var key = element.shift();
  13416. var propertyObj = obj[key];
  13417. if (!propertyObj) {
  13418. propertyObj = {};
  13419. obj[key] = propertyObj;
  13420. }
  13421. obj = propertyObj;
  13422. }
  13423. obj[element.shift()] = setValue;
  13424. return setValue;
  13425. }
  13426. /**
  13427. * Return the value accesible from the object by path. Any undefined traversals are ignored
  13428. * @param {Object} obj starting object
  13429. * @param {string} path path to traverse
  13430. * @param {boolean=true} bindFnToScope
  13431. * @returns value as accesbile by path
  13432. */
  13433. //TODO(misko): this function needs to be removed
  13434. function getter(obj, path, bindFnToScope) {
  13435. if (!path) return obj;
  13436. var keys = path.split('.');
  13437. var key;
  13438. var lastInstance = obj;
  13439. var len = keys.length;
  13440. for (var i = 0; i < len; i++) {
  13441. key = keys[i];
  13442. if (obj) {
  13443. obj = (lastInstance = obj)[key];
  13444. }
  13445. }
  13446. if (!bindFnToScope && isFunction(obj)) {
  13447. return bind(lastInstance, obj);
  13448. }
  13449. return obj;
  13450. }
  13451. var getterFnCache = {};
  13452. /**
  13453. * Implementation of the "Black Hole" variant from:
  13454. * - http://jsperf.com/angularjs-parse-getter/4
  13455. * - http://jsperf.com/path-evaluation-simplified/7
  13456. */
  13457. function cspSafeGetterFn(key0, key1, key2, key3, key4) {
  13458. return function(scope, locals) {
  13459. var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
  13460. promise;
  13461. if (pathVal === null || pathVal === undefined) return pathVal;
  13462. pathVal = pathVal[key0];
  13463. if (pathVal && pathVal.then) {
  13464. if (!("$$v" in pathVal)) {
  13465. promise = pathVal;
  13466. promise.$$v = undefined;
  13467. promise.then(function(val) { promise.$$v = val; });
  13468. }
  13469. pathVal = pathVal.$$v;
  13470. }
  13471. if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
  13472. pathVal = pathVal[key1];
  13473. if (pathVal && pathVal.then) {
  13474. if (!("$$v" in pathVal)) {
  13475. promise = pathVal;
  13476. promise.$$v = undefined;
  13477. promise.then(function(val) { promise.$$v = val; });
  13478. }
  13479. pathVal = pathVal.$$v;
  13480. }
  13481. if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
  13482. pathVal = pathVal[key2];
  13483. if (pathVal && pathVal.then) {
  13484. if (!("$$v" in pathVal)) {
  13485. promise = pathVal;
  13486. promise.$$v = undefined;
  13487. promise.then(function(val) { promise.$$v = val; });
  13488. }
  13489. pathVal = pathVal.$$v;
  13490. }
  13491. if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
  13492. pathVal = pathVal[key3];
  13493. if (pathVal && pathVal.then) {
  13494. if (!("$$v" in pathVal)) {
  13495. promise = pathVal;
  13496. promise.$$v = undefined;
  13497. promise.then(function(val) { promise.$$v = val; });
  13498. }
  13499. pathVal = pathVal.$$v;
  13500. }
  13501. if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
  13502. pathVal = pathVal[key4];
  13503. if (pathVal && pathVal.then) {
  13504. if (!("$$v" in pathVal)) {
  13505. promise = pathVal;
  13506. promise.$$v = undefined;
  13507. promise.then(function(val) { promise.$$v = val; });
  13508. }
  13509. pathVal = pathVal.$$v;
  13510. }
  13511. return pathVal;
  13512. };
  13513. };
  13514. function getterFn(path, csp) {
  13515. if (getterFnCache.hasOwnProperty(path)) {
  13516. return getterFnCache[path];
  13517. }
  13518. var pathKeys = path.split('.'),
  13519. pathKeysLength = pathKeys.length,
  13520. fn;
  13521. if (csp) {
  13522. fn = (pathKeysLength < 6)
  13523. ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4])
  13524. : function(scope, locals) {
  13525. var i = 0, val
  13526. do {
  13527. val = cspSafeGetterFn(
  13528. pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++]
  13529. )(scope, locals);
  13530. locals = undefined; // clear after first iteration
  13531. scope = val;
  13532. } while (i < pathKeysLength);
  13533. return val;
  13534. }
  13535. } else {
  13536. var code = 'var l, fn, p;\n';
  13537. forEach(pathKeys, function(key, index) {
  13538. code += 'if(s === null || s === undefined) return s;\n' +
  13539. 'l=s;\n' +
  13540. 's='+ (index
  13541. // we simply dereference 's' on any .dot notation
  13542. ? 's'
  13543. // but if we are first then we check locals first, and if so read it first
  13544. : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
  13545. 'if (s && s.then) {\n' +
  13546. ' if (!("$$v" in s)) {\n' +
  13547. ' p=s;\n' +
  13548. ' p.$$v = undefined;\n' +
  13549. ' p.then(function(v) {p.$$v=v;});\n' +
  13550. '}\n' +
  13551. ' s=s.$$v\n' +
  13552. '}\n';
  13553. });
  13554. code += 'return s;';
  13555. fn = Function('s', 'k', code); // s=scope, k=locals
  13556. fn.toString = function() { return code; };
  13557. }
  13558. return getterFnCache[path] = fn;
  13559. }
  13560. ///////////////////////////////////
  13561. /**
  13562. * @ngdoc function
  13563. * @name ng.$parse
  13564. * @function
  13565. *
  13566. * @description
  13567. *
  13568. * Converts Angular {@link guide/expression expression} into a function.
  13569. *
  13570. * <pre>
  13571. * var getter = $parse('user.name');
  13572. * var setter = getter.assign;
  13573. * var context = {user:{name:'angular'}};
  13574. * var locals = {user:{name:'local'}};
  13575. *
  13576. * expect(getter(context)).toEqual('angular');
  13577. * setter(context, 'newValue');
  13578. * expect(context.user.name).toEqual('newValue');
  13579. * expect(getter(context, locals)).toEqual('local');
  13580. * </pre>
  13581. *
  13582. *
  13583. * @param {string} expression String expression to compile.
  13584. * @returns {function(context, locals)} a function which represents the compiled expression:
  13585. *
  13586. * * `context` – `{object}` – an object against which any expressions embedded in the strings
  13587. * are evaluated against (tipically a scope object).
  13588. * * `locals` – `{object=}` – local variables context object, useful for overriding values in
  13589. * `context`.
  13590. *
  13591. * The return function also has an `assign` property, if the expression is assignable, which
  13592. * allows one to set values to expressions.
  13593. *
  13594. */
  13595. function $ParseProvider() {
  13596. var cache = {};
  13597. this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
  13598. return function(exp) {
  13599. switch(typeof exp) {
  13600. case 'string':
  13601. return cache.hasOwnProperty(exp)
  13602. ? cache[exp]
  13603. : cache[exp] = parser(exp, false, $filter, $sniffer.csp);
  13604. case 'function':
  13605. return exp;
  13606. default:
  13607. return noop;
  13608. }
  13609. };
  13610. }];
  13611. }
  13612. /**
  13613. * @ngdoc service
  13614. * @name ng.$q
  13615. * @requires $rootScope
  13616. *
  13617. * @description
  13618. * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
  13619. *
  13620. * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
  13621. * interface for interacting with an object that represents the result of an action that is
  13622. * performed asynchronously, and may or may not be finished at any given point in time.
  13623. *
  13624. * From the perspective of dealing with error handling, deferred and promise APIs are to
  13625. * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
  13626. *
  13627. * <pre>
  13628. * // for the purpose of this example let's assume that variables `$q` and `scope` are
  13629. * // available in the current lexical scope (they could have been injected or passed in).
  13630. *
  13631. * function asyncGreet(name) {
  13632. * var deferred = $q.defer();
  13633. *
  13634. * setTimeout(function() {
  13635. * // since this fn executes async in a future turn of the event loop, we need to wrap
  13636. * // our code into an $apply call so that the model changes are properly observed.
  13637. * scope.$apply(function() {
  13638. * if (okToGreet(name)) {
  13639. * deferred.resolve('Hello, ' + name + '!');
  13640. * } else {
  13641. * deferred.reject('Greeting ' + name + ' is not allowed.');
  13642. * }
  13643. * });
  13644. * }, 1000);
  13645. *
  13646. * return deferred.promise;
  13647. * }
  13648. *
  13649. * var promise = asyncGreet('Robin Hood');
  13650. * promise.then(function(greeting) {
  13651. * alert('Success: ' + greeting);
  13652. * }, function(reason) {
  13653. * alert('Failed: ' + reason);
  13654. * });
  13655. * </pre>
  13656. *
  13657. * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
  13658. * comes in the way of
  13659. * [guarantees that promise and deferred APIs make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
  13660. *
  13661. * Additionally the promise api allows for composition that is very hard to do with the
  13662. * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
  13663. * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
  13664. * section on serial or parallel joining of promises.
  13665. *
  13666. *
  13667. * # The Deferred API
  13668. *
  13669. * A new instance of deferred is constructed by calling `$q.defer()`.
  13670. *
  13671. * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
  13672. * that can be used for signaling the successful or unsuccessful completion of the task.
  13673. *
  13674. * **Methods**
  13675. *
  13676. * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
  13677. * constructed via `$q.reject`, the promise will be rejected instead.
  13678. * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
  13679. * resolving it with a rejection constructed via `$q.reject`.
  13680. *
  13681. * **Properties**
  13682. *
  13683. * - promise – `{Promise}` – promise object associated with this deferred.
  13684. *
  13685. *
  13686. * # The Promise API
  13687. *
  13688. * A new promise instance is created when a deferred instance is created and can be retrieved by
  13689. * calling `deferred.promise`.
  13690. *
  13691. * The purpose of the promise object is to allow for interested parties to get access to the result
  13692. * of the deferred task when it completes.
  13693. *
  13694. * **Methods**
  13695. *
  13696. * - `then(successCallback, errorCallback)` – regardless of when the promise was or will be resolved
  13697. * or rejected calls one of the success or error callbacks asynchronously as soon as the result
  13698. * is available. The callbacks are called with a single argument the result or rejection reason.
  13699. *
  13700. * This method *returns a new promise* which is resolved or rejected via the return value of the
  13701. * `successCallback` or `errorCallback`.
  13702. *
  13703. *
  13704. * # Chaining promises
  13705. *
  13706. * Because calling `then` api of a promise returns a new derived promise, it is easily possible
  13707. * to create a chain of promises:
  13708. *
  13709. * <pre>
  13710. * promiseB = promiseA.then(function(result) {
  13711. * return result + 1;
  13712. * });
  13713. *
  13714. * // promiseB will be resolved immediately after promiseA is resolved and its value will be
  13715. * // the result of promiseA incremented by 1
  13716. * </pre>
  13717. *
  13718. * It is possible to create chains of any length and since a promise can be resolved with another
  13719. * promise (which will defer its resolution further), it is possible to pause/defer resolution of
  13720. * the promises at any point in the chain. This makes it possible to implement powerful apis like
  13721. * $http's response interceptors.
  13722. *
  13723. *
  13724. * # Differences between Kris Kowal's Q and $q
  13725. *
  13726. * There are three main differences:
  13727. *
  13728. * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
  13729. * mechanism in angular, which means faster propagation of resolution or rejection into your
  13730. * models and avoiding unnecessary browser repaints, which would result in flickering UI.
  13731. * - $q promises are recognized by the templating engine in angular, which means that in templates
  13732. * you can treat promises attached to a scope as if they were the resulting values.
  13733. * - Q has many more features that $q, but that comes at a cost of bytes. $q is tiny, but contains
  13734. * all the important functionality needed for common async tasks.
  13735. *
  13736. * # Testing
  13737. *
  13738. * <pre>
  13739. * it('should simulate promise', inject(function($q, $rootScope) {
  13740. * var deferred = $q.defer();
  13741. * var promise = deferred.promise;
  13742. * var resolvedValue;
  13743. *
  13744. * promise.then(function(value) { resolvedValue = value; });
  13745. * expect(resolvedValue).toBeUndefined();
  13746. *
  13747. * // Simulate resolving of promise
  13748. * deferred.resolve(123);
  13749. * // Note that the 'then' function does not get called synchronously.
  13750. * // This is because we want the promise API to always be async, whether or not
  13751. * // it got called synchronously or asynchronously.
  13752. * expect(resolvedValue).toBeUndefined();
  13753. *
  13754. * // Propagate promise resolution to 'then' functions using $apply().
  13755. * $rootScope.$apply();
  13756. * expect(resolvedValue).toEqual(123);
  13757. * });
  13758. * </pre>
  13759. */
  13760. function $QProvider() {
  13761. this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
  13762. return qFactory(function(callback) {
  13763. $rootScope.$evalAsync(callback);
  13764. }, $exceptionHandler);
  13765. }];
  13766. }
  13767. /**
  13768. * Constructs a promise manager.
  13769. *
  13770. * @param {function(function)} nextTick Function for executing functions in the next turn.
  13771. * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
  13772. * debugging purposes.
  13773. * @returns {object} Promise manager.
  13774. */
  13775. function qFactory(nextTick, exceptionHandler) {
  13776. /**
  13777. * @ngdoc
  13778. * @name ng.$q#defer
  13779. * @methodOf ng.$q
  13780. * @description
  13781. * Creates a `Deferred` object which represents a task which will finish in the future.
  13782. *
  13783. * @returns {Deferred} Returns a new instance of deferred.
  13784. */
  13785. var defer = function() {
  13786. var pending = [],
  13787. value, deferred;
  13788. deferred = {
  13789. resolve: function(val) {
  13790. if (pending) {
  13791. var callbacks = pending;
  13792. pending = undefined;
  13793. value = ref(val);
  13794. if (callbacks.length) {
  13795. nextTick(function() {
  13796. var callback;
  13797. for (var i = 0, ii = callbacks.length; i < ii; i++) {
  13798. callback = callbacks[i];
  13799. value.then(callback[0], callback[1]);
  13800. }
  13801. });
  13802. }
  13803. }
  13804. },
  13805. reject: function(reason) {
  13806. deferred.resolve(reject(reason));
  13807. },
  13808. promise: {
  13809. then: function(callback, errback) {
  13810. var result = defer();
  13811. var wrappedCallback = function(value) {
  13812. try {
  13813. result.resolve((callback || defaultCallback)(value));
  13814. } catch(e) {
  13815. exceptionHandler(e);
  13816. result.reject(e);
  13817. }
  13818. };
  13819. var wrappedErrback = function(reason) {
  13820. try {
  13821. result.resolve((errback || defaultErrback)(reason));
  13822. } catch(e) {
  13823. exceptionHandler(e);
  13824. result.reject(e);
  13825. }
  13826. };
  13827. if (pending) {
  13828. pending.push([wrappedCallback, wrappedErrback]);
  13829. } else {
  13830. value.then(wrappedCallback, wrappedErrback);
  13831. }
  13832. return result.promise;
  13833. }
  13834. }
  13835. };
  13836. return deferred;
  13837. };
  13838. var ref = function(value) {
  13839. if (value && value.then) return value;
  13840. return {
  13841. then: function(callback) {
  13842. var result = defer();
  13843. nextTick(function() {
  13844. result.resolve(callback(value));
  13845. });
  13846. return result.promise;
  13847. }
  13848. };
  13849. };
  13850. /**
  13851. * @ngdoc
  13852. * @name ng.$q#reject
  13853. * @methodOf ng.$q
  13854. * @description
  13855. * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
  13856. * used to forward rejection in a chain of promises. If you are dealing with the last promise in
  13857. * a promise chain, you don't need to worry about it.
  13858. *
  13859. * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
  13860. * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
  13861. * a promise error callback and you want to forward the error to the promise derived from the
  13862. * current promise, you have to "rethrow" the error by returning a rejection constructed via
  13863. * `reject`.
  13864. *
  13865. * <pre>
  13866. * promiseB = promiseA.then(function(result) {
  13867. * // success: do something and resolve promiseB
  13868. * // with the old or a new result
  13869. * return result;
  13870. * }, function(reason) {
  13871. * // error: handle the error if possible and
  13872. * // resolve promiseB with newPromiseOrValue,
  13873. * // otherwise forward the rejection to promiseB
  13874. * if (canHandle(reason)) {
  13875. * // handle the error and recover
  13876. * return newPromiseOrValue;
  13877. * }
  13878. * return $q.reject(reason);
  13879. * });
  13880. * </pre>
  13881. *
  13882. * @param {*} reason Constant, message, exception or an object representing the rejection reason.
  13883. * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
  13884. */
  13885. var reject = function(reason) {
  13886. return {
  13887. then: function(callback, errback) {
  13888. var result = defer();
  13889. nextTick(function() {
  13890. result.resolve((errback || defaultErrback)(reason));
  13891. });
  13892. return result.promise;
  13893. }
  13894. };
  13895. };
  13896. /**
  13897. * @ngdoc
  13898. * @name ng.$q#when
  13899. * @methodOf ng.$q
  13900. * @description
  13901. * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
  13902. * This is useful when you are dealing with an object that might or might not be a promise, or if
  13903. * the promise comes from a source that can't be trusted.
  13904. *
  13905. * @param {*} value Value or a promise
  13906. * @returns {Promise} Returns a single promise that will be resolved with an array of values,
  13907. * each value corresponding to the promise at the same index in the `promises` array. If any of
  13908. * the promises is resolved with a rejection, this resulting promise will be resolved with the
  13909. * same rejection.
  13910. */
  13911. var when = function(value, callback, errback) {
  13912. var result = defer(),
  13913. done;
  13914. var wrappedCallback = function(value) {
  13915. try {
  13916. return (callback || defaultCallback)(value);
  13917. } catch (e) {
  13918. exceptionHandler(e);
  13919. return reject(e);
  13920. }
  13921. };
  13922. var wrappedErrback = function(reason) {
  13923. try {
  13924. return (errback || defaultErrback)(reason);
  13925. } catch (e) {
  13926. exceptionHandler(e);
  13927. return reject(e);
  13928. }
  13929. };
  13930. nextTick(function() {
  13931. ref(value).then(function(value) {
  13932. if (done) return;
  13933. done = true;
  13934. result.resolve(ref(value).then(wrappedCallback, wrappedErrback));
  13935. }, function(reason) {
  13936. if (done) return;
  13937. done = true;
  13938. result.resolve(wrappedErrback(reason));
  13939. });
  13940. });
  13941. return result.promise;
  13942. };
  13943. function defaultCallback(value) {
  13944. return value;
  13945. }
  13946. function defaultErrback(reason) {
  13947. return reject(reason);
  13948. }
  13949. /**
  13950. * @ngdoc
  13951. * @name ng.$q#all
  13952. * @methodOf ng.$q
  13953. * @description
  13954. * Combines multiple promises into a single promise that is resolved when all of the input
  13955. * promises are resolved.
  13956. *
  13957. * @param {Array.<Promise>} promises An array of promises.
  13958. * @returns {Promise} Returns a single promise that will be resolved with an array of values,
  13959. * each value corresponding to the promise at the same index in the `promises` array. If any of
  13960. * the promises is resolved with a rejection, this resulting promise will be resolved with the
  13961. * same rejection.
  13962. */
  13963. function all(promises) {
  13964. var deferred = defer(),
  13965. counter = promises.length,
  13966. results = [];
  13967. if (counter) {
  13968. forEach(promises, function(promise, index) {
  13969. ref(promise).then(function(value) {
  13970. if (index in results) return;
  13971. results[index] = value;
  13972. if (!(--counter)) deferred.resolve(results);
  13973. }, function(reason) {
  13974. if (index in results) return;
  13975. deferred.reject(reason);
  13976. });
  13977. });
  13978. } else {
  13979. deferred.resolve(results);
  13980. }
  13981. return deferred.promise;
  13982. }
  13983. return {
  13984. defer: defer,
  13985. reject: reject,
  13986. when: when,
  13987. all: all
  13988. };
  13989. }
  13990. /**
  13991. * @ngdoc object
  13992. * @name ng.$routeProvider
  13993. * @function
  13994. *
  13995. * @description
  13996. *
  13997. * Used for configuring routes. See {@link ng.$route $route} for an example.
  13998. */
  13999. function $RouteProvider(){
  14000. var routes = {};
  14001. /**
  14002. * @ngdoc method
  14003. * @name ng.$routeProvider#when
  14004. * @methodOf ng.$routeProvider
  14005. *
  14006. * @param {string} path Route path (matched against `$location.path`). If `$location.path`
  14007. * contains redundant trailing slash or is missing one, the route will still match and the
  14008. * `$location.path` will be updated to add or drop the trailing slash to exactly match the
  14009. * route definition.
  14010. *
  14011. * `path` can contain named groups starting with a colon (`:name`). All characters up to the
  14012. * next slash are matched and stored in `$routeParams` under the given `name` when the route
  14013. * matches.
  14014. *
  14015. * @param {Object} route Mapping information to be assigned to `$route.current` on route
  14016. * match.
  14017. *
  14018. * Object properties:
  14019. *
  14020. * - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
  14021. * created scope or the name of a {@link angular.Module#controller registered controller}
  14022. * if passed as a string.
  14023. * - `template` – `{string=}` – html template as a string that should be used by
  14024. * {@link ng.directive:ngView ngView} or
  14025. * {@link ng.directive:ngInclude ngInclude} directives.
  14026. * this property takes precedence over `templateUrl`.
  14027. * - `templateUrl` – `{string=}` – path to an html template that should be used by
  14028. * {@link ng.directive:ngView ngView}.
  14029. * - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
  14030. * be injected into the controller. If any of these dependencies are promises, they will be
  14031. * resolved and converted to a value before the controller is instantiated and the
  14032. * `$routeChangeSuccess` event is fired. The map object is:
  14033. *
  14034. * - `key` – `{string}`: a name of a dependency to be injected into the controller.
  14035. * - `factory` - `{string|function}`: If `string` then it is an alias for a service.
  14036. * Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
  14037. * and the return value is treated as the dependency. If the result is a promise, it is resolved
  14038. * before its value is injected into the controller.
  14039. *
  14040. * - `redirectTo` – {(string|function())=} – value to update
  14041. * {@link ng.$location $location} path with and trigger route redirection.
  14042. *
  14043. * If `redirectTo` is a function, it will be called with the following parameters:
  14044. *
  14045. * - `{Object.<string>}` - route parameters extracted from the current
  14046. * `$location.path()` by applying the current route templateUrl.
  14047. * - `{string}` - current `$location.path()`
  14048. * - `{Object}` - current `$location.search()`
  14049. *
  14050. * The custom `redirectTo` function is expected to return a string which will be used
  14051. * to update `$location.path()` and `$location.search()`.
  14052. *
  14053. * - `[reloadOnSearch=true]` - {boolean=} - reload route when only $location.search()
  14054. * changes.
  14055. *
  14056. * If the option is set to `false` and url in the browser changes, then
  14057. * `$routeUpdate` event is broadcasted on the root scope.
  14058. *
  14059. * @returns {Object} self
  14060. *
  14061. * @description
  14062. * Adds a new route definition to the `$route` service.
  14063. */
  14064. this.when = function(path, route) {
  14065. routes[path] = extend({reloadOnSearch: true}, route);
  14066. // create redirection for trailing slashes
  14067. if (path) {
  14068. var redirectPath = (path[path.length-1] == '/')
  14069. ? path.substr(0, path.length-1)
  14070. : path +'/';
  14071. routes[redirectPath] = {redirectTo: path};
  14072. }
  14073. return this;
  14074. };
  14075. /**
  14076. * @ngdoc method
  14077. * @name ng.$routeProvider#otherwise
  14078. * @methodOf ng.$routeProvider
  14079. *
  14080. * @description
  14081. * Sets route definition that will be used on route change when no other route definition
  14082. * is matched.
  14083. *
  14084. * @param {Object} params Mapping information to be assigned to `$route.current`.
  14085. * @returns {Object} self
  14086. */
  14087. this.otherwise = function(params) {
  14088. this.when(null, params);
  14089. return this;
  14090. };
  14091. this.$get = ['$rootScope', '$location', '$routeParams', '$q', '$injector', '$http', '$templateCache',
  14092. function( $rootScope, $location, $routeParams, $q, $injector, $http, $templateCache) {
  14093. /**
  14094. * @ngdoc object
  14095. * @name ng.$route
  14096. * @requires $location
  14097. * @requires $routeParams
  14098. *
  14099. * @property {Object} current Reference to the current route definition.
  14100. * The route definition contains:
  14101. *
  14102. * - `controller`: The controller constructor as define in route definition.
  14103. * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
  14104. * controller instantiation. The `locals` contain
  14105. * the resolved values of the `resolve` map. Additionally the `locals` also contain:
  14106. *
  14107. * - `$scope` - The current route scope.
  14108. * - `$template` - The current route template HTML.
  14109. *
  14110. * @property {Array.<Object>} routes Array of all configured routes.
  14111. *
  14112. * @description
  14113. * Is used for deep-linking URLs to controllers and views (HTML partials).
  14114. * It watches `$location.url()` and tries to map the path to an existing route definition.
  14115. *
  14116. * You can define routes through {@link ng.$routeProvider $routeProvider}'s API.
  14117. *
  14118. * The `$route` service is typically used in conjunction with {@link ng.directive:ngView ngView}
  14119. * directive and the {@link ng.$routeParams $routeParams} service.
  14120. *
  14121. * @example
  14122. This example shows how changing the URL hash causes the `$route` to match a route against the
  14123. URL, and the `ngView` pulls in the partial.
  14124. Note that this example is using {@link ng.directive:script inlined templates}
  14125. to get it working on jsfiddle as well.
  14126. <example module="ngView">
  14127. <file name="index.html">
  14128. <div ng-controller="MainCntl">
  14129. Choose:
  14130. <a href="Book/Moby">Moby</a> |
  14131. <a href="Book/Moby/ch/1">Moby: Ch1</a> |
  14132. <a href="Book/Gatsby">Gatsby</a> |
  14133. <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
  14134. <a href="Book/Scarlet">Scarlet Letter</a><br/>
  14135. <div ng-view></div>
  14136. <hr />
  14137. <pre>$location.path() = {{$location.path()}}</pre>
  14138. <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
  14139. <pre>$route.current.params = {{$route.current.params}}</pre>
  14140. <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
  14141. <pre>$routeParams = {{$routeParams}}</pre>
  14142. </div>
  14143. </file>
  14144. <file name="book.html">
  14145. controller: {{name}}<br />
  14146. Book Id: {{params.bookId}}<br />
  14147. </file>
  14148. <file name="chapter.html">
  14149. controller: {{name}}<br />
  14150. Book Id: {{params.bookId}}<br />
  14151. Chapter Id: {{params.chapterId}}
  14152. </file>
  14153. <file name="script.js">
  14154. angular.module('ngView', [], function($routeProvider, $locationProvider) {
  14155. $routeProvider.when('/Book/:bookId', {
  14156. templateUrl: 'book.html',
  14157. controller: BookCntl,
  14158. resolve: {
  14159. // I will cause a 1 second delay
  14160. delay: function($q, $timeout) {
  14161. var delay = $q.defer();
  14162. $timeout(delay.resolve, 1000);
  14163. return delay.promise;
  14164. }
  14165. }
  14166. });
  14167. $routeProvider.when('/Book/:bookId/ch/:chapterId', {
  14168. templateUrl: 'chapter.html',
  14169. controller: ChapterCntl
  14170. });
  14171. // configure html5 to get links working on jsfiddle
  14172. $locationProvider.html5Mode(true);
  14173. });
  14174. function MainCntl($scope, $route, $routeParams, $location) {
  14175. $scope.$route = $route;
  14176. $scope.$location = $location;
  14177. $scope.$routeParams = $routeParams;
  14178. }
  14179. function BookCntl($scope, $routeParams) {
  14180. $scope.name = "BookCntl";
  14181. $scope.params = $routeParams;
  14182. }
  14183. function ChapterCntl($scope, $routeParams) {
  14184. $scope.name = "ChapterCntl";
  14185. $scope.params = $routeParams;
  14186. }
  14187. </file>
  14188. <file name="scenario.js">
  14189. it('should load and compile correct template', function() {
  14190. element('a:contains("Moby: Ch1")').click();
  14191. var content = element('.doc-example-live [ng-view]').text();
  14192. expect(content).toMatch(/controller\: ChapterCntl/);
  14193. expect(content).toMatch(/Book Id\: Moby/);
  14194. expect(content).toMatch(/Chapter Id\: 1/);
  14195. element('a:contains("Scarlet")').click();
  14196. sleep(2); // promises are not part of scenario waiting
  14197. content = element('.doc-example-live [ng-view]').text();
  14198. expect(content).toMatch(/controller\: BookCntl/);
  14199. expect(content).toMatch(/Book Id\: Scarlet/);
  14200. });
  14201. </file>
  14202. </example>
  14203. */
  14204. /**
  14205. * @ngdoc event
  14206. * @name ng.$route#$routeChangeStart
  14207. * @eventOf ng.$route
  14208. * @eventType broadcast on root scope
  14209. * @description
  14210. * Broadcasted before a route change. At this point the route services starts
  14211. * resolving all of the dependencies needed for the route change to occurs.
  14212. * Typically this involves fetching the view template as well as any dependencies
  14213. * defined in `resolve` route property. Once all of the dependencies are resolved
  14214. * `$routeChangeSuccess` is fired.
  14215. *
  14216. * @param {Route} next Future route information.
  14217. * @param {Route} current Current route information.
  14218. */
  14219. /**
  14220. * @ngdoc event
  14221. * @name ng.$route#$routeChangeSuccess
  14222. * @eventOf ng.$route
  14223. * @eventType broadcast on root scope
  14224. * @description
  14225. * Broadcasted after a route dependencies are resolved.
  14226. * {@link ng.directive:ngView ngView} listens for the directive
  14227. * to instantiate the controller and render the view.
  14228. *
  14229. * @param {Object} angularEvent Synthetic event object.
  14230. * @param {Route} current Current route information.
  14231. * @param {Route|Undefined} previous Previous route information, or undefined if current is first route entered.
  14232. */
  14233. /**
  14234. * @ngdoc event
  14235. * @name ng.$route#$routeChangeError
  14236. * @eventOf ng.$route
  14237. * @eventType broadcast on root scope
  14238. * @description
  14239. * Broadcasted if any of the resolve promises are rejected.
  14240. *
  14241. * @param {Route} current Current route information.
  14242. * @param {Route} previous Previous route information.
  14243. * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
  14244. */
  14245. /**
  14246. * @ngdoc event
  14247. * @name ng.$route#$routeUpdate
  14248. * @eventOf ng.$route
  14249. * @eventType broadcast on root scope
  14250. * @description
  14251. *
  14252. * The `reloadOnSearch` property has been set to false, and we are reusing the same
  14253. * instance of the Controller.
  14254. */
  14255. var forceReload = false,
  14256. $route = {
  14257. routes: routes,
  14258. /**
  14259. * @ngdoc method
  14260. * @name ng.$route#reload
  14261. * @methodOf ng.$route
  14262. *
  14263. * @description
  14264. * Causes `$route` service to reload the current route even if
  14265. * {@link ng.$location $location} hasn't changed.
  14266. *
  14267. * As a result of that, {@link ng.directive:ngView ngView}
  14268. * creates new scope, reinstantiates the controller.
  14269. */
  14270. reload: function() {
  14271. forceReload = true;
  14272. $rootScope.$evalAsync(updateRoute);
  14273. }
  14274. };
  14275. $rootScope.$on('$locationChangeSuccess', updateRoute);
  14276. return $route;
  14277. /////////////////////////////////////////////////////
  14278. /**
  14279. * @param on {string} current url
  14280. * @param when {string} route when template to match the url against
  14281. * @return {?Object}
  14282. */
  14283. function switchRouteMatcher(on, when) {
  14284. // TODO(i): this code is convoluted and inefficient, we should construct the route matching
  14285. // regex only once and then reuse it
  14286. // Escape regexp special characters.
  14287. when = '^' + when.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&") + '$';
  14288. var regex = '',
  14289. params = [],
  14290. dst = {};
  14291. var re = /:(\w+)/g,
  14292. paramMatch,
  14293. lastMatchedIndex = 0;
  14294. while ((paramMatch = re.exec(when)) !== null) {
  14295. // Find each :param in `when` and replace it with a capturing group.
  14296. // Append all other sections of when unchanged.
  14297. regex += when.slice(lastMatchedIndex, paramMatch.index);
  14298. regex += '([^\\/]*)';
  14299. params.push(paramMatch[1]);
  14300. lastMatchedIndex = re.lastIndex;
  14301. }
  14302. // Append trailing path part.
  14303. regex += when.substr(lastMatchedIndex);
  14304. var match = on.match(new RegExp(regex));
  14305. if (match) {
  14306. forEach(params, function(name, index) {
  14307. dst[name] = match[index + 1];
  14308. });
  14309. }
  14310. return match ? dst : null;
  14311. }
  14312. function updateRoute() {
  14313. var next = parseRoute(),
  14314. last = $route.current;
  14315. if (next && last && next.$$route === last.$$route
  14316. && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
  14317. last.params = next.params;
  14318. copy(last.params, $routeParams);
  14319. $rootScope.$broadcast('$routeUpdate', last);
  14320. } else if (next || last) {
  14321. forceReload = false;
  14322. $rootScope.$broadcast('$routeChangeStart', next, last);
  14323. $route.current = next;
  14324. if (next) {
  14325. if (next.redirectTo) {
  14326. if (isString(next.redirectTo)) {
  14327. $location.path(interpolate(next.redirectTo, next.params)).search(next.params)
  14328. .replace();
  14329. } else {
  14330. $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
  14331. .replace();
  14332. }
  14333. }
  14334. }
  14335. $q.when(next).
  14336. then(function() {
  14337. if (next) {
  14338. var keys = [],
  14339. values = [],
  14340. template;
  14341. forEach(next.resolve || {}, function(value, key) {
  14342. keys.push(key);
  14343. values.push(isString(value) ? $injector.get(value) : $injector.invoke(value));
  14344. });
  14345. if (isDefined(template = next.template)) {
  14346. } else if (isDefined(template = next.templateUrl)) {
  14347. template = $http.get(template, {cache: $templateCache}).
  14348. then(function(response) { return response.data; });
  14349. }
  14350. if (isDefined(template)) {
  14351. keys.push('$template');
  14352. values.push(template);
  14353. }
  14354. return $q.all(values).then(function(values) {
  14355. var locals = {};
  14356. forEach(values, function(value, index) {
  14357. locals[keys[index]] = value;
  14358. });
  14359. return locals;
  14360. });
  14361. }
  14362. }).
  14363. // after route change
  14364. then(function(locals) {
  14365. if (next == $route.current) {
  14366. if (next) {
  14367. next.locals = locals;
  14368. copy(next.params, $routeParams);
  14369. }
  14370. $rootScope.$broadcast('$routeChangeSuccess', next, last);
  14371. }
  14372. }, function(error) {
  14373. if (next == $route.current) {
  14374. $rootScope.$broadcast('$routeChangeError', next, last, error);
  14375. }
  14376. });
  14377. }
  14378. }
  14379. /**
  14380. * @returns the current active route, by matching it against the URL
  14381. */
  14382. function parseRoute() {
  14383. // Match a route
  14384. var params, match;
  14385. forEach(routes, function(route, path) {
  14386. if (!match && (params = switchRouteMatcher($location.path(), path))) {
  14387. match = inherit(route, {
  14388. params: extend({}, $location.search(), params),
  14389. pathParams: params});
  14390. match.$$route = route;
  14391. }
  14392. });
  14393. // No route matched; fallback to "otherwise" route
  14394. return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
  14395. }
  14396. /**
  14397. * @returns interpolation of the redirect path with the parametrs
  14398. */
  14399. function interpolate(string, params) {
  14400. var result = [];
  14401. forEach((string||'').split(':'), function(segment, i) {
  14402. if (i == 0) {
  14403. result.push(segment);
  14404. } else {
  14405. var segmentMatch = segment.match(/(\w+)(.*)/);
  14406. var key = segmentMatch[1];
  14407. result.push(params[key]);
  14408. result.push(segmentMatch[2] || '');
  14409. delete params[key];
  14410. }
  14411. });
  14412. return result.join('');
  14413. }
  14414. }];
  14415. }
  14416. /**
  14417. * @ngdoc object
  14418. * @name ng.$routeParams
  14419. * @requires $route
  14420. *
  14421. * @description
  14422. * Current set of route parameters. The route parameters are a combination of the
  14423. * {@link ng.$location $location} `search()`, and `path()`. The `path` parameters
  14424. * are extracted when the {@link ng.$route $route} path is matched.
  14425. *
  14426. * In case of parameter name collision, `path` params take precedence over `search` params.
  14427. *
  14428. * The service guarantees that the identity of the `$routeParams` object will remain unchanged
  14429. * (but its properties will likely change) even when a route change occurs.
  14430. *
  14431. * @example
  14432. * <pre>
  14433. * // Given:
  14434. * // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
  14435. * // Route: /Chapter/:chapterId/Section/:sectionId
  14436. * //
  14437. * // Then
  14438. * $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
  14439. * </pre>
  14440. */
  14441. function $RouteParamsProvider() {
  14442. this.$get = valueFn({});
  14443. }
  14444. /**
  14445. * DESIGN NOTES
  14446. *
  14447. * The design decisions behind the scope ware heavily favored for speed and memory consumption.
  14448. *
  14449. * The typical use of scope is to watch the expressions, which most of the time return the same
  14450. * value as last time so we optimize the operation.
  14451. *
  14452. * Closures construction is expensive from speed as well as memory:
  14453. * - no closures, instead ups prototypical inheritance for API
  14454. * - Internal state needs to be stored on scope directly, which means that private state is
  14455. * exposed as $$____ properties
  14456. *
  14457. * Loop operations are optimized by using while(count--) { ... }
  14458. * - this means that in order to keep the same order of execution as addition we have to add
  14459. * items to the array at the begging (shift) instead of at the end (push)
  14460. *
  14461. * Child scopes are created and removed often
  14462. * - Using array would be slow since inserts in meddle are expensive so we use linked list
  14463. *
  14464. * There are few watches then a lot of observers. This is why you don't want the observer to be
  14465. * implemented in the same way as watch. Watch requires return of initialization function which
  14466. * are expensive to construct.
  14467. */
  14468. /**
  14469. * @ngdoc object
  14470. * @name ng.$rootScopeProvider
  14471. * @description
  14472. *
  14473. * Provider for the $rootScope service.
  14474. */
  14475. /**
  14476. * @ngdoc function
  14477. * @name ng.$rootScopeProvider#digestTtl
  14478. * @methodOf ng.$rootScopeProvider
  14479. * @description
  14480. *
  14481. * Sets the number of digest iteration the scope should attempt to execute before giving up and
  14482. * assuming that the model is unstable.
  14483. *
  14484. * The current default is 10 iterations.
  14485. *
  14486. * @param {number} limit The number of digest iterations.
  14487. */
  14488. /**
  14489. * @ngdoc object
  14490. * @name ng.$rootScope
  14491. * @description
  14492. *
  14493. * Every application has a single root {@link ng.$rootScope.Scope scope}.
  14494. * All other scopes are child scopes of the root scope. Scopes provide mechanism for watching the model and provide
  14495. * event processing life-cycle. See {@link guide/scope developer guide on scopes}.
  14496. */
  14497. function $RootScopeProvider(){
  14498. var TTL = 10;
  14499. this.digestTtl = function(value) {
  14500. if (arguments.length) {
  14501. TTL = value;
  14502. }
  14503. return TTL;
  14504. };
  14505. this.$get = ['$injector', '$exceptionHandler', '$parse',
  14506. function( $injector, $exceptionHandler, $parse) {
  14507. /**
  14508. * @ngdoc function
  14509. * @name ng.$rootScope.Scope
  14510. *
  14511. * @description
  14512. * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
  14513. * {@link AUTO.$injector $injector}. Child scopes are created using the
  14514. * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
  14515. * compiled HTML template is executed.)
  14516. *
  14517. * Here is a simple scope snippet to show how you can interact with the scope.
  14518. * <pre>
  14519. angular.injector(['ng']).invoke(function($rootScope) {
  14520. var scope = $rootScope.$new();
  14521. scope.salutation = 'Hello';
  14522. scope.name = 'World';
  14523. expect(scope.greeting).toEqual(undefined);
  14524. scope.$watch('name', function() {
  14525. scope.greeting = scope.salutation + ' ' + scope.name + '!';
  14526. }); // initialize the watch
  14527. expect(scope.greeting).toEqual(undefined);
  14528. scope.name = 'Misko';
  14529. // still old value, since watches have not been called yet
  14530. expect(scope.greeting).toEqual(undefined);
  14531. scope.$digest(); // fire all the watches
  14532. expect(scope.greeting).toEqual('Hello Misko!');
  14533. });
  14534. * </pre>
  14535. *
  14536. * # Inheritance
  14537. * A scope can inherit from a parent scope, as in this example:
  14538. * <pre>
  14539. var parent = $rootScope;
  14540. var child = parent.$new();
  14541. parent.salutation = "Hello";
  14542. child.name = "World";
  14543. expect(child.salutation).toEqual('Hello');
  14544. child.salutation = "Welcome";
  14545. expect(child.salutation).toEqual('Welcome');
  14546. expect(parent.salutation).toEqual('Hello');
  14547. * </pre>
  14548. *
  14549. *
  14550. * @param {Object.<string, function()>=} providers Map of service factory which need to be provided
  14551. * for the current scope. Defaults to {@link ng}.
  14552. * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
  14553. * append/override services provided by `providers`. This is handy when unit-testing and having
  14554. * the need to override a default service.
  14555. * @returns {Object} Newly created scope.
  14556. *
  14557. */
  14558. function Scope() {
  14559. this.$id = nextUid();
  14560. this.$$phase = this.$parent = this.$$watchers =
  14561. this.$$nextSibling = this.$$prevSibling =
  14562. this.$$childHead = this.$$childTail = null;
  14563. this['this'] = this.$root = this;
  14564. this.$$destroyed = false;
  14565. this.$$asyncQueue = [];
  14566. this.$$listeners = {};
  14567. this.$$isolateBindings = {};
  14568. }
  14569. /**
  14570. * @ngdoc property
  14571. * @name ng.$rootScope.Scope#$id
  14572. * @propertyOf ng.$rootScope.Scope
  14573. * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
  14574. * debugging.
  14575. */
  14576. Scope.prototype = {
  14577. /**
  14578. * @ngdoc function
  14579. * @name ng.$rootScope.Scope#$new
  14580. * @methodOf ng.$rootScope.Scope
  14581. * @function
  14582. *
  14583. * @description
  14584. * Creates a new child {@link ng.$rootScope.Scope scope}.
  14585. *
  14586. * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
  14587. * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the scope
  14588. * hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
  14589. *
  14590. * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is desired for
  14591. * the scope and its child scopes to be permanently detached from the parent and thus stop
  14592. * participating in model change detection and listener notification by invoking.
  14593. *
  14594. * @param {boolean} isolate if true then the scope does not prototypically inherit from the
  14595. * parent scope. The scope is isolated, as it can not see parent scope properties.
  14596. * When creating widgets it is useful for the widget to not accidentally read parent
  14597. * state.
  14598. *
  14599. * @returns {Object} The newly created child scope.
  14600. *
  14601. */
  14602. $new: function(isolate) {
  14603. var Child,
  14604. child;
  14605. if (isFunction(isolate)) {
  14606. // TODO: remove at some point
  14607. throw Error('API-CHANGE: Use $controller to instantiate controllers.');
  14608. }
  14609. if (isolate) {
  14610. child = new Scope();
  14611. child.$root = this.$root;
  14612. } else {
  14613. Child = function() {}; // should be anonymous; This is so that when the minifier munges
  14614. // the name it does not become random set of chars. These will then show up as class
  14615. // name in the debugger.
  14616. Child.prototype = this;
  14617. child = new Child();
  14618. child.$id = nextUid();
  14619. }
  14620. child['this'] = child;
  14621. child.$$listeners = {};
  14622. child.$parent = this;
  14623. child.$$asyncQueue = [];
  14624. child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
  14625. child.$$prevSibling = this.$$childTail;
  14626. if (this.$$childHead) {
  14627. this.$$childTail.$$nextSibling = child;
  14628. this.$$childTail = child;
  14629. } else {
  14630. this.$$childHead = this.$$childTail = child;
  14631. }
  14632. return child;
  14633. },
  14634. /**
  14635. * @ngdoc function
  14636. * @name ng.$rootScope.Scope#$watch
  14637. * @methodOf ng.$rootScope.Scope
  14638. * @function
  14639. *
  14640. * @description
  14641. * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
  14642. *
  14643. * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest $digest()} and
  14644. * should return the value which will be watched. (Since {@link ng.$rootScope.Scope#$digest $digest()}
  14645. * reruns when it detects changes the `watchExpression` can execute multiple times per
  14646. * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
  14647. * - The `listener` is called only when the value from the current `watchExpression` and the
  14648. * previous call to `watchExpression` are not equal (with the exception of the initial run,
  14649. * see below). The inequality is determined according to
  14650. * {@link angular.equals} function. To save the value of the object for later comparison, the
  14651. * {@link angular.copy} function is used. It also means that watching complex options will
  14652. * have adverse memory and performance implications.
  14653. * - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
  14654. * is achieved by rerunning the watchers until no changes are detected. The rerun iteration
  14655. * limit is 10 to prevent an infinite loop deadlock.
  14656. *
  14657. *
  14658. * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
  14659. * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
  14660. * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a change is
  14661. * detected, be prepared for multiple calls to your listener.)
  14662. *
  14663. * After a watcher is registered with the scope, the `listener` fn is called asynchronously
  14664. * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
  14665. * watcher. In rare cases, this is undesirable because the listener is called when the result
  14666. * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
  14667. * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
  14668. * listener was called due to initialization.
  14669. *
  14670. *
  14671. * # Example
  14672. * <pre>
  14673. // let's assume that scope was dependency injected as the $rootScope
  14674. var scope = $rootScope;
  14675. scope.name = 'misko';
  14676. scope.counter = 0;
  14677. expect(scope.counter).toEqual(0);
  14678. scope.$watch('name', function(newValue, oldValue) { scope.counter = scope.counter + 1; });
  14679. expect(scope.counter).toEqual(0);
  14680. scope.$digest();
  14681. // no variable change
  14682. expect(scope.counter).toEqual(0);
  14683. scope.name = 'adam';
  14684. scope.$digest();
  14685. expect(scope.counter).toEqual(1);
  14686. * </pre>
  14687. *
  14688. *
  14689. *
  14690. * @param {(function()|string)} watchExpression Expression that is evaluated on each
  14691. * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers a
  14692. * call to the `listener`.
  14693. *
  14694. * - `string`: Evaluated as {@link guide/expression expression}
  14695. * - `function(scope)`: called with current `scope` as a parameter.
  14696. * @param {(function()|string)=} listener Callback called whenever the return value of
  14697. * the `watchExpression` changes.
  14698. *
  14699. * - `string`: Evaluated as {@link guide/expression expression}
  14700. * - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
  14701. *
  14702. * @param {boolean=} objectEquality Compare object for equality rather than for reference.
  14703. * @returns {function()} Returns a deregistration function for this listener.
  14704. */
  14705. $watch: function(watchExp, listener, objectEquality) {
  14706. var scope = this,
  14707. get = compileToFn(watchExp, 'watch'),
  14708. array = scope.$$watchers,
  14709. watcher = {
  14710. fn: listener,
  14711. last: initWatchVal,
  14712. get: get,
  14713. exp: watchExp,
  14714. eq: !!objectEquality
  14715. };
  14716. // in the case user pass string, we need to compile it, do we really need this ?
  14717. if (!isFunction(listener)) {
  14718. var listenFn = compileToFn(listener || noop, 'listener');
  14719. watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
  14720. }
  14721. if (!array) {
  14722. array = scope.$$watchers = [];
  14723. }
  14724. // we use unshift since we use a while loop in $digest for speed.
  14725. // the while loop reads in reverse order.
  14726. array.unshift(watcher);
  14727. return function() {
  14728. arrayRemove(array, watcher);
  14729. };
  14730. },
  14731. /**
  14732. * @ngdoc function
  14733. * @name ng.$rootScope.Scope#$digest
  14734. * @methodOf ng.$rootScope.Scope
  14735. * @function
  14736. *
  14737. * @description
  14738. * Process all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
  14739. * Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
  14740. * `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are
  14741. * firing. This means that it is possible to get into an infinite loop. This function will throw
  14742. * `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 10.
  14743. *
  14744. * Usually you don't call `$digest()` directly in
  14745. * {@link ng.directive:ngController controllers} or in
  14746. * {@link ng.$compileProvider#directive directives}.
  14747. * Instead a call to {@link ng.$rootScope.Scope#$apply $apply()} (typically from within a
  14748. * {@link ng.$compileProvider#directive directives}) will force a `$digest()`.
  14749. *
  14750. * If you want to be notified whenever `$digest()` is called,
  14751. * you can register a `watchExpression` function with {@link ng.$rootScope.Scope#$watch $watch()}
  14752. * with no `listener`.
  14753. *
  14754. * You may have a need to call `$digest()` from within unit-tests, to simulate the scope
  14755. * life-cycle.
  14756. *
  14757. * # Example
  14758. * <pre>
  14759. var scope = ...;
  14760. scope.name = 'misko';
  14761. scope.counter = 0;
  14762. expect(scope.counter).toEqual(0);
  14763. scope.$watch('name', function(newValue, oldValue) {
  14764. scope.counter = scope.counter + 1;
  14765. });
  14766. expect(scope.counter).toEqual(0);
  14767. scope.$digest();
  14768. // no variable change
  14769. expect(scope.counter).toEqual(0);
  14770. scope.name = 'adam';
  14771. scope.$digest();
  14772. expect(scope.counter).toEqual(1);
  14773. * </pre>
  14774. *
  14775. */
  14776. $digest: function() {
  14777. var watch, value, last,
  14778. watchers,
  14779. asyncQueue,
  14780. length,
  14781. dirty, ttl = TTL,
  14782. next, current, target = this,
  14783. watchLog = [],
  14784. logIdx, logMsg;
  14785. beginPhase('$digest');
  14786. do {
  14787. dirty = false;
  14788. current = target;
  14789. do {
  14790. asyncQueue = current.$$asyncQueue;
  14791. while(asyncQueue.length) {
  14792. try {
  14793. current.$eval(asyncQueue.shift());
  14794. } catch (e) {
  14795. $exceptionHandler(e);
  14796. }
  14797. }
  14798. if ((watchers = current.$$watchers)) {
  14799. // process our watches
  14800. length = watchers.length;
  14801. while (length--) {
  14802. try {
  14803. watch = watchers[length];
  14804. // Most common watches are on primitives, in which case we can short
  14805. // circuit it with === operator, only when === fails do we use .equals
  14806. if ((value = watch.get(current)) !== (last = watch.last) &&
  14807. !(watch.eq
  14808. ? equals(value, last)
  14809. : (typeof value == 'number' && typeof last == 'number'
  14810. && isNaN(value) && isNaN(last)))) {
  14811. dirty = true;
  14812. watch.last = watch.eq ? copy(value) : value;
  14813. watch.fn(value, ((last === initWatchVal) ? value : last), current);
  14814. if (ttl < 5) {
  14815. logIdx = 4 - ttl;
  14816. if (!watchLog[logIdx]) watchLog[logIdx] = [];
  14817. logMsg = (isFunction(watch.exp))
  14818. ? 'fn: ' + (watch.exp.name || watch.exp.toString())
  14819. : watch.exp;
  14820. logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
  14821. watchLog[logIdx].push(logMsg);
  14822. }
  14823. }
  14824. } catch (e) {
  14825. $exceptionHandler(e);
  14826. }
  14827. }
  14828. }
  14829. // Insanity Warning: scope depth-first traversal
  14830. // yes, this code is a bit crazy, but it works and we have tests to prove it!
  14831. // this piece should be kept in sync with the traversal in $broadcast
  14832. if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
  14833. while(current !== target && !(next = current.$$nextSibling)) {
  14834. current = current.$parent;
  14835. }
  14836. }
  14837. } while ((current = next));
  14838. if(dirty && !(ttl--)) {
  14839. clearPhase();
  14840. throw Error(TTL + ' $digest() iterations reached. Aborting!\n' +
  14841. 'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
  14842. }
  14843. } while (dirty || asyncQueue.length);
  14844. clearPhase();
  14845. },
  14846. /**
  14847. * @ngdoc event
  14848. * @name ng.$rootScope.Scope#$destroy
  14849. * @eventOf ng.$rootScope.Scope
  14850. * @eventType broadcast on scope being destroyed
  14851. *
  14852. * @description
  14853. * Broadcasted when a scope and its children are being destroyed.
  14854. */
  14855. /**
  14856. * @ngdoc function
  14857. * @name ng.$rootScope.Scope#$destroy
  14858. * @methodOf ng.$rootScope.Scope
  14859. * @function
  14860. *
  14861. * @description
  14862. * Removes the current scope (and all of its children) from the parent scope. Removal implies
  14863. * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
  14864. * propagate to the current scope and its children. Removal also implies that the current
  14865. * scope is eligible for garbage collection.
  14866. *
  14867. * The `$destroy()` is usually used by directives such as
  14868. * {@link ng.directive:ngRepeat ngRepeat} for managing the
  14869. * unrolling of the loop.
  14870. *
  14871. * Just before a scope is destroyed a `$destroy` event is broadcasted on this scope.
  14872. * Application code can register a `$destroy` event handler that will give it chance to
  14873. * perform any necessary cleanup.
  14874. */
  14875. $destroy: function() {
  14876. // we can't destroy the root scope or a scope that has been already destroyed
  14877. if ($rootScope == this || this.$$destroyed) return;
  14878. var parent = this.$parent;
  14879. this.$broadcast('$destroy');
  14880. this.$$destroyed = true;
  14881. if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
  14882. if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
  14883. if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
  14884. if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
  14885. // This is bogus code that works around Chrome's GC leak
  14886. // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
  14887. this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
  14888. this.$$childTail = null;
  14889. },
  14890. /**
  14891. * @ngdoc function
  14892. * @name ng.$rootScope.Scope#$eval
  14893. * @methodOf ng.$rootScope.Scope
  14894. * @function
  14895. *
  14896. * @description
  14897. * Executes the `expression` on the current scope returning the result. Any exceptions in the
  14898. * expression are propagated (uncaught). This is useful when evaluating Angular expressions.
  14899. *
  14900. * # Example
  14901. * <pre>
  14902. var scope = ng.$rootScope.Scope();
  14903. scope.a = 1;
  14904. scope.b = 2;
  14905. expect(scope.$eval('a+b')).toEqual(3);
  14906. expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
  14907. * </pre>
  14908. *
  14909. * @param {(string|function())=} expression An angular expression to be executed.
  14910. *
  14911. * - `string`: execute using the rules as defined in {@link guide/expression expression}.
  14912. * - `function(scope)`: execute the function with the current `scope` parameter.
  14913. *
  14914. * @returns {*} The result of evaluating the expression.
  14915. */
  14916. $eval: function(expr, locals) {
  14917. return $parse(expr)(this, locals);
  14918. },
  14919. /**
  14920. * @ngdoc function
  14921. * @name ng.$rootScope.Scope#$evalAsync
  14922. * @methodOf ng.$rootScope.Scope
  14923. * @function
  14924. *
  14925. * @description
  14926. * Executes the expression on the current scope at a later point in time.
  14927. *
  14928. * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only that:
  14929. *
  14930. * - it will execute in the current script execution context (before any DOM rendering).
  14931. * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
  14932. * `expression` execution.
  14933. *
  14934. * Any exceptions from the execution of the expression are forwarded to the
  14935. * {@link ng.$exceptionHandler $exceptionHandler} service.
  14936. *
  14937. * @param {(string|function())=} expression An angular expression to be executed.
  14938. *
  14939. * - `string`: execute using the rules as defined in {@link guide/expression expression}.
  14940. * - `function(scope)`: execute the function with the current `scope` parameter.
  14941. *
  14942. */
  14943. $evalAsync: function(expr) {
  14944. this.$$asyncQueue.push(expr);
  14945. },
  14946. /**
  14947. * @ngdoc function
  14948. * @name ng.$rootScope.Scope#$apply
  14949. * @methodOf ng.$rootScope.Scope
  14950. * @function
  14951. *
  14952. * @description
  14953. * `$apply()` is used to execute an expression in angular from outside of the angular framework.
  14954. * (For example from browser DOM events, setTimeout, XHR or third party libraries).
  14955. * Because we are calling into the angular framework we need to perform proper scope life-cycle
  14956. * of {@link ng.$exceptionHandler exception handling},
  14957. * {@link ng.$rootScope.Scope#$digest executing watches}.
  14958. *
  14959. * ## Life cycle
  14960. *
  14961. * # Pseudo-Code of `$apply()`
  14962. * <pre>
  14963. function $apply(expr) {
  14964. try {
  14965. return $eval(expr);
  14966. } catch (e) {
  14967. $exceptionHandler(e);
  14968. } finally {
  14969. $root.$digest();
  14970. }
  14971. }
  14972. * </pre>
  14973. *
  14974. *
  14975. * Scope's `$apply()` method transitions through the following stages:
  14976. *
  14977. * 1. The {@link guide/expression expression} is executed using the
  14978. * {@link ng.$rootScope.Scope#$eval $eval()} method.
  14979. * 2. Any exceptions from the execution of the expression are forwarded to the
  14980. * {@link ng.$exceptionHandler $exceptionHandler} service.
  14981. * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the expression
  14982. * was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
  14983. *
  14984. *
  14985. * @param {(string|function())=} exp An angular expression to be executed.
  14986. *
  14987. * - `string`: execute using the rules as defined in {@link guide/expression expression}.
  14988. * - `function(scope)`: execute the function with current `scope` parameter.
  14989. *
  14990. * @returns {*} The result of evaluating the expression.
  14991. */
  14992. $apply: function(expr) {
  14993. try {
  14994. beginPhase('$apply');
  14995. return this.$eval(expr);
  14996. } catch (e) {
  14997. $exceptionHandler(e);
  14998. } finally {
  14999. clearPhase();
  15000. try {
  15001. $rootScope.$digest();
  15002. } catch (e) {
  15003. $exceptionHandler(e);
  15004. throw e;
  15005. }
  15006. }
  15007. },
  15008. /**
  15009. * @ngdoc function
  15010. * @name ng.$rootScope.Scope#$on
  15011. * @methodOf ng.$rootScope.Scope
  15012. * @function
  15013. *
  15014. * @description
  15015. * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
  15016. * event life cycle.
  15017. *
  15018. * The event listener function format is: `function(event, args...)`. The `event` object
  15019. * passed into the listener has the following attributes:
  15020. *
  15021. * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
  15022. * - `currentScope` - `{Scope}`: the current scope which is handling the event.
  15023. * - `name` - `{string}`: Name of the event.
  15024. * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event
  15025. * propagation (available only for events that were `$emit`-ed).
  15026. * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
  15027. * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
  15028. *
  15029. * @param {string} name Event name to listen on.
  15030. * @param {function(event, args...)} listener Function to call when the event is emitted.
  15031. * @returns {function()} Returns a deregistration function for this listener.
  15032. */
  15033. $on: function(name, listener) {
  15034. var namedListeners = this.$$listeners[name];
  15035. if (!namedListeners) {
  15036. this.$$listeners[name] = namedListeners = [];
  15037. }
  15038. namedListeners.push(listener);
  15039. return function() {
  15040. namedListeners[indexOf(namedListeners, listener)] = null;
  15041. };
  15042. },
  15043. /**
  15044. * @ngdoc function
  15045. * @name ng.$rootScope.Scope#$emit
  15046. * @methodOf ng.$rootScope.Scope
  15047. * @function
  15048. *
  15049. * @description
  15050. * Dispatches an event `name` upwards through the scope hierarchy notifying the
  15051. * registered {@link ng.$rootScope.Scope#$on} listeners.
  15052. *
  15053. * The event life cycle starts at the scope on which `$emit` was called. All
  15054. * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
  15055. * Afterwards, the event traverses upwards toward the root scope and calls all registered
  15056. * listeners along the way. The event will stop propagating if one of the listeners cancels it.
  15057. *
  15058. * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed
  15059. * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
  15060. *
  15061. * @param {string} name Event name to emit.
  15062. * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
  15063. * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
  15064. */
  15065. $emit: function(name, args) {
  15066. var empty = [],
  15067. namedListeners,
  15068. scope = this,
  15069. stopPropagation = false,
  15070. event = {
  15071. name: name,
  15072. targetScope: scope,
  15073. stopPropagation: function() {stopPropagation = true;},
  15074. preventDefault: function() {
  15075. event.defaultPrevented = true;
  15076. },
  15077. defaultPrevented: false
  15078. },
  15079. listenerArgs = concat([event], arguments, 1),
  15080. i, length;
  15081. do {
  15082. namedListeners = scope.$$listeners[name] || empty;
  15083. event.currentScope = scope;
  15084. for (i=0, length=namedListeners.length; i<length; i++) {
  15085. // if listeners were deregistered, defragment the array
  15086. if (!namedListeners[i]) {
  15087. namedListeners.splice(i, 1);
  15088. i--;
  15089. length--;
  15090. continue;
  15091. }
  15092. try {
  15093. namedListeners[i].apply(null, listenerArgs);
  15094. if (stopPropagation) return event;
  15095. } catch (e) {
  15096. $exceptionHandler(e);
  15097. }
  15098. }
  15099. //traverse upwards
  15100. scope = scope.$parent;
  15101. } while (scope);
  15102. return event;
  15103. },
  15104. /**
  15105. * @ngdoc function
  15106. * @name ng.$rootScope.Scope#$broadcast
  15107. * @methodOf ng.$rootScope.Scope
  15108. * @function
  15109. *
  15110. * @description
  15111. * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
  15112. * registered {@link ng.$rootScope.Scope#$on} listeners.
  15113. *
  15114. * The event life cycle starts at the scope on which `$broadcast` was called. All
  15115. * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
  15116. * Afterwards, the event propagates to all direct and indirect scopes of the current scope and
  15117. * calls all registered listeners along the way. The event cannot be canceled.
  15118. *
  15119. * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed
  15120. * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
  15121. *
  15122. * @param {string} name Event name to emit.
  15123. * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
  15124. * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
  15125. */
  15126. $broadcast: function(name, args) {
  15127. var target = this,
  15128. current = target,
  15129. next = target,
  15130. event = {
  15131. name: name,
  15132. targetScope: target,
  15133. preventDefault: function() {
  15134. event.defaultPrevented = true;
  15135. },
  15136. defaultPrevented: false
  15137. },
  15138. listenerArgs = concat([event], arguments, 1),
  15139. listeners, i, length;
  15140. //down while you can, then up and next sibling or up and next sibling until back at root
  15141. do {
  15142. current = next;
  15143. event.currentScope = current;
  15144. listeners = current.$$listeners[name] || [];
  15145. for (i=0, length = listeners.length; i<length; i++) {
  15146. // if listeners were deregistered, defragment the array
  15147. if (!listeners[i]) {
  15148. listeners.splice(i, 1);
  15149. i--;
  15150. length--;
  15151. continue;
  15152. }
  15153. try {
  15154. listeners[i].apply(null, listenerArgs);
  15155. } catch(e) {
  15156. $exceptionHandler(e);
  15157. }
  15158. }
  15159. // Insanity Warning: scope depth-first traversal
  15160. // yes, this code is a bit crazy, but it works and we have tests to prove it!
  15161. // this piece should be kept in sync with the traversal in $digest
  15162. if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
  15163. while(current !== target && !(next = current.$$nextSibling)) {
  15164. current = current.$parent;
  15165. }
  15166. }
  15167. } while ((current = next));
  15168. return event;
  15169. }
  15170. };
  15171. var $rootScope = new Scope();
  15172. return $rootScope;
  15173. function beginPhase(phase) {
  15174. if ($rootScope.$$phase) {
  15175. throw Error($rootScope.$$phase + ' already in progress');
  15176. }
  15177. $rootScope.$$phase = phase;
  15178. }
  15179. function clearPhase() {
  15180. $rootScope.$$phase = null;
  15181. }
  15182. function compileToFn(exp, name) {
  15183. var fn = $parse(exp);
  15184. assertArgFn(fn, name);
  15185. return fn;
  15186. }
  15187. /**
  15188. * function used as an initial value for watchers.
  15189. * because it's unique we can easily tell it apart from other values
  15190. */
  15191. function initWatchVal() {}
  15192. }];
  15193. }
  15194. /**
  15195. * !!! This is an undocumented "private" service !!!
  15196. *
  15197. * @name ng.$sniffer
  15198. * @requires $window
  15199. *
  15200. * @property {boolean} history Does the browser support html5 history api ?
  15201. * @property {boolean} hashchange Does the browser support hashchange event ?
  15202. *
  15203. * @description
  15204. * This is very simple implementation of testing browser's features.
  15205. */
  15206. function $SnifferProvider() {
  15207. this.$get = ['$window', function($window) {
  15208. var eventSupport = {},
  15209. android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1]);
  15210. return {
  15211. // Android has history.pushState, but it does not update location correctly
  15212. // so let's not use the history API at all.
  15213. // http://code.google.com/p/android/issues/detail?id=17471
  15214. // https://github.com/angular/angular.js/issues/904
  15215. history: !!($window.history && $window.history.pushState && !(android < 4)),
  15216. hashchange: 'onhashchange' in $window &&
  15217. // IE8 compatible mode lies
  15218. (!$window.document.documentMode || $window.document.documentMode > 7),
  15219. hasEvent: function(event) {
  15220. // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
  15221. // it. In particular the event is not fired when backspace or delete key are pressed or
  15222. // when cut operation is performed.
  15223. if (event == 'input' && msie == 9) return false;
  15224. if (isUndefined(eventSupport[event])) {
  15225. var divElm = $window.document.createElement('div');
  15226. eventSupport[event] = 'on' + event in divElm;
  15227. }
  15228. return eventSupport[event];
  15229. },
  15230. // TODO(i): currently there is no way to feature detect CSP without triggering alerts
  15231. csp: false
  15232. };
  15233. }];
  15234. }
  15235. /**
  15236. * @ngdoc object
  15237. * @name ng.$window
  15238. *
  15239. * @description
  15240. * A reference to the browser's `window` object. While `window`
  15241. * is globally available in JavaScript, it causes testability problems, because
  15242. * it is a global variable. In angular we always refer to it through the
  15243. * `$window` service, so it may be overriden, removed or mocked for testing.
  15244. *
  15245. * All expressions are evaluated with respect to current scope so they don't
  15246. * suffer from window globality.
  15247. *
  15248. * @example
  15249. <doc:example>
  15250. <doc:source>
  15251. <input ng-init="$window = $service('$window'); greeting='Hello World!'" type="text" ng-model="greeting" />
  15252. <button ng-click="$window.alert(greeting)">ALERT</button>
  15253. </doc:source>
  15254. <doc:scenario>
  15255. </doc:scenario>
  15256. </doc:example>
  15257. */
  15258. function $WindowProvider(){
  15259. this.$get = valueFn(window);
  15260. }
  15261. /**
  15262. * Parse headers into key value object
  15263. *
  15264. * @param {string} headers Raw headers as a string
  15265. * @returns {Object} Parsed headers as key value object
  15266. */
  15267. function parseHeaders(headers) {
  15268. var parsed = {}, key, val, i;
  15269. if (!headers) return parsed;
  15270. forEach(headers.split('\n'), function(line) {
  15271. i = line.indexOf(':');
  15272. key = lowercase(trim(line.substr(0, i)));
  15273. val = trim(line.substr(i + 1));
  15274. if (key) {
  15275. if (parsed[key]) {
  15276. parsed[key] += ', ' + val;
  15277. } else {
  15278. parsed[key] = val;
  15279. }
  15280. }
  15281. });
  15282. return parsed;
  15283. }
  15284. /**
  15285. * Returns a function that provides access to parsed headers.
  15286. *
  15287. * Headers are lazy parsed when first requested.
  15288. * @see parseHeaders
  15289. *
  15290. * @param {(string|Object)} headers Headers to provide access to.
  15291. * @returns {function(string=)} Returns a getter function which if called with:
  15292. *
  15293. * - if called with single an argument returns a single header value or null
  15294. * - if called with no arguments returns an object containing all headers.
  15295. */
  15296. function headersGetter(headers) {
  15297. var headersObj = isObject(headers) ? headers : undefined;
  15298. return function(name) {
  15299. if (!headersObj) headersObj = parseHeaders(headers);
  15300. if (name) {
  15301. return headersObj[lowercase(name)] || null;
  15302. }
  15303. return headersObj;
  15304. };
  15305. }
  15306. /**
  15307. * Chain all given functions
  15308. *
  15309. * This function is used for both request and response transforming
  15310. *
  15311. * @param {*} data Data to transform.
  15312. * @param {function(string=)} headers Http headers getter fn.
  15313. * @param {(function|Array.<function>)} fns Function or an array of functions.
  15314. * @returns {*} Transformed data.
  15315. */
  15316. function transformData(data, headers, fns) {
  15317. if (isFunction(fns))
  15318. return fns(data, headers);
  15319. forEach(fns, function(fn) {
  15320. data = fn(data, headers);
  15321. });
  15322. return data;
  15323. }
  15324. function isSuccess(status) {
  15325. return 200 <= status && status < 300;
  15326. }
  15327. function $HttpProvider() {
  15328. var JSON_START = /^\s*(\[|\{[^\{])/,
  15329. JSON_END = /[\}\]]\s*$/,
  15330. PROTECTION_PREFIX = /^\)\]\}',?\n/;
  15331. var $config = this.defaults = {
  15332. // transform incoming response data
  15333. transformResponse: [function(data) {
  15334. if (isString(data)) {
  15335. // strip json vulnerability protection prefix
  15336. data = data.replace(PROTECTION_PREFIX, '');
  15337. if (JSON_START.test(data) && JSON_END.test(data))
  15338. data = fromJson(data, true);
  15339. }
  15340. return data;
  15341. }],
  15342. // transform outgoing request data
  15343. transformRequest: [function(d) {
  15344. return isObject(d) && !isFile(d) ? toJson(d) : d;
  15345. }],
  15346. // default headers
  15347. headers: {
  15348. common: {
  15349. 'Accept': 'application/json, text/plain, */*',
  15350. 'X-Requested-With': 'XMLHttpRequest'
  15351. },
  15352. post: {'Content-Type': 'application/json;charset=utf-8'},
  15353. put: {'Content-Type': 'application/json;charset=utf-8'}
  15354. }
  15355. };
  15356. var providerResponseInterceptors = this.responseInterceptors = [];
  15357. this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
  15358. function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
  15359. var defaultCache = $cacheFactory('$http'),
  15360. responseInterceptors = [];
  15361. forEach(providerResponseInterceptors, function(interceptor) {
  15362. responseInterceptors.push(
  15363. isString(interceptor)
  15364. ? $injector.get(interceptor)
  15365. : $injector.invoke(interceptor)
  15366. );
  15367. });
  15368. /**
  15369. * @ngdoc function
  15370. * @name ng.$http
  15371. * @requires $httpBackend
  15372. * @requires $browser
  15373. * @requires $cacheFactory
  15374. * @requires $rootScope
  15375. * @requires $q
  15376. * @requires $injector
  15377. *
  15378. * @description
  15379. * The `$http` service is a core Angular service that facilitates communication with the remote
  15380. * HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest
  15381. * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
  15382. *
  15383. * For unit testing applications that use `$http` service, see
  15384. * {@link ngMock.$httpBackend $httpBackend mock}.
  15385. *
  15386. * For a higher level of abstraction, please check out the {@link ngResource.$resource
  15387. * $resource} service.
  15388. *
  15389. * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
  15390. * the $q service. While for simple usage patters this doesn't matter much, for advanced usage,
  15391. * it is important to familiarize yourself with these apis and guarantees they provide.
  15392. *
  15393. *
  15394. * # General usage
  15395. * The `$http` service is a function which takes a single argument — a configuration object —
  15396. * that is used to generate an http request and returns a {@link ng.$q promise}
  15397. * with two $http specific methods: `success` and `error`.
  15398. *
  15399. * <pre>
  15400. * $http({method: 'GET', url: '/someUrl'}).
  15401. * success(function(data, status, headers, config) {
  15402. * // this callback will be called asynchronously
  15403. * // when the response is available
  15404. * }).
  15405. * error(function(data, status, headers, config) {
  15406. * // called asynchronously if an error occurs
  15407. * // or server returns response with an error status.
  15408. * });
  15409. * </pre>
  15410. *
  15411. * Since the returned value of calling the $http function is a Promise object, you can also use
  15412. * the `then` method to register callbacks, and these callbacks will receive a single argument –
  15413. * an object representing the response. See the api signature and type info below for more
  15414. * details.
  15415. *
  15416. * A response status code that falls in the [200, 300) range is considered a success status and
  15417. * will result in the success callback being called. Note that if the response is a redirect,
  15418. * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
  15419. * called for such responses.
  15420. *
  15421. * # Shortcut methods
  15422. *
  15423. * Since all invocation of the $http service require definition of the http method and url and
  15424. * POST and PUT requests require response body/data to be provided as well, shortcut methods
  15425. * were created to simplify using the api:
  15426. *
  15427. * <pre>
  15428. * $http.get('/someUrl').success(successCallback);
  15429. * $http.post('/someUrl', data).success(successCallback);
  15430. * </pre>
  15431. *
  15432. * Complete list of shortcut methods:
  15433. *
  15434. * - {@link ng.$http#get $http.get}
  15435. * - {@link ng.$http#head $http.head}
  15436. * - {@link ng.$http#post $http.post}
  15437. * - {@link ng.$http#put $http.put}
  15438. * - {@link ng.$http#delete $http.delete}
  15439. * - {@link ng.$http#jsonp $http.jsonp}
  15440. *
  15441. *
  15442. * # Setting HTTP Headers
  15443. *
  15444. * The $http service will automatically add certain http headers to all requests. These defaults
  15445. * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
  15446. * object, which currently contains this default configuration:
  15447. *
  15448. * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
  15449. * - `Accept: application/json, text/plain, * / *`
  15450. * - `X-Requested-With: XMLHttpRequest`
  15451. * - `$httpProvider.defaults.headers.post`: (header defaults for HTTP POST requests)
  15452. * - `Content-Type: application/json`
  15453. * - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests)
  15454. * - `Content-Type: application/json`
  15455. *
  15456. * To add or overwrite these defaults, simply add or remove a property from this configuration
  15457. * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
  15458. * with name equal to the lower-cased http method name, e.g.
  15459. * `$httpProvider.defaults.headers.get['My-Header']='value'`.
  15460. *
  15461. * Additionally, the defaults can be set at runtime via the `$http.defaults` object in a similar
  15462. * fassion as described above.
  15463. *
  15464. *
  15465. * # Transforming Requests and Responses
  15466. *
  15467. * Both requests and responses can be transformed using transform functions. By default, Angular
  15468. * applies these transformations:
  15469. *
  15470. * Request transformations:
  15471. *
  15472. * - if the `data` property of the request config object contains an object, serialize it into
  15473. * JSON format.
  15474. *
  15475. * Response transformations:
  15476. *
  15477. * - if XSRF prefix is detected, strip it (see Security Considerations section below)
  15478. * - if json response is detected, deserialize it using a JSON parser
  15479. *
  15480. * To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
  15481. * `$httpProvider.defaults.transformResponse` properties of the `$httpProvider`. These properties are by default an
  15482. * array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
  15483. * transformation chain. You can also decide to completely override any default transformations by assigning your
  15484. * transformation functions to these properties directly without the array wrapper.
  15485. *
  15486. * Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
  15487. * `transformResponse` properties of the config object passed into `$http`.
  15488. *
  15489. *
  15490. * # Caching
  15491. *
  15492. * To enable caching set the configuration property `cache` to `true`. When the cache is
  15493. * enabled, `$http` stores the response from the server in local cache. Next time the
  15494. * response is served from the cache without sending a request to the server.
  15495. *
  15496. * Note that even if the response is served from cache, delivery of the data is asynchronous in
  15497. * the same way that real requests are.
  15498. *
  15499. * If there are multiple GET requests for the same url that should be cached using the same
  15500. * cache, but the cache is not populated yet, only one request to the server will be made and
  15501. * the remaining requests will be fulfilled using the response for the first request.
  15502. *
  15503. *
  15504. * # Response interceptors
  15505. *
  15506. * Before you start creating interceptors, be sure to understand the
  15507. * {@link ng.$q $q and deferred/promise APIs}.
  15508. *
  15509. * For purposes of global error handling, authentication or any kind of synchronous or
  15510. * asynchronous preprocessing of received responses, it is desirable to be able to intercept
  15511. * responses for http requests before they are handed over to the application code that
  15512. * initiated these requests. The response interceptors leverage the {@link ng.$q
  15513. * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
  15514. *
  15515. * The interceptors are service factories that are registered with the $httpProvider by
  15516. * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
  15517. * injected with dependencies (if specified) and returns the interceptor — a function that
  15518. * takes a {@link ng.$q promise} and returns the original or a new promise.
  15519. *
  15520. * <pre>
  15521. * // register the interceptor as a service
  15522. * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
  15523. * return function(promise) {
  15524. * return promise.then(function(response) {
  15525. * // do something on success
  15526. * }, function(response) {
  15527. * // do something on error
  15528. * if (canRecover(response)) {
  15529. * return responseOrNewPromise
  15530. * }
  15531. * return $q.reject(response);
  15532. * });
  15533. * }
  15534. * });
  15535. *
  15536. * $httpProvider.responseInterceptors.push('myHttpInterceptor');
  15537. *
  15538. *
  15539. * // register the interceptor via an anonymous factory
  15540. * $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
  15541. * return function(promise) {
  15542. * // same as above
  15543. * }
  15544. * });
  15545. * </pre>
  15546. *
  15547. *
  15548. * # Security Considerations
  15549. *
  15550. * When designing web applications, consider security threats from:
  15551. *
  15552. * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
  15553. * JSON Vulnerability}
  15554. * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
  15555. *
  15556. * Both server and the client must cooperate in order to eliminate these threats. Angular comes
  15557. * pre-configured with strategies that address these issues, but for this to work backend server
  15558. * cooperation is required.
  15559. *
  15560. * ## JSON Vulnerability Protection
  15561. *
  15562. * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
  15563. * JSON Vulnerability} allows third party web-site to turn your JSON resource URL into
  15564. * {@link http://en.wikipedia.org/wiki/JSON#JSONP JSONP} request under some conditions. To
  15565. * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
  15566. * Angular will automatically strip the prefix before processing it as JSON.
  15567. *
  15568. * For example if your server needs to return:
  15569. * <pre>
  15570. * ['one','two']
  15571. * </pre>
  15572. *
  15573. * which is vulnerable to attack, your server can return:
  15574. * <pre>
  15575. * )]}',
  15576. * ['one','two']
  15577. * </pre>
  15578. *
  15579. * Angular will strip the prefix, before processing the JSON.
  15580. *
  15581. *
  15582. * ## Cross Site Request Forgery (XSRF) Protection
  15583. *
  15584. * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
  15585. * an unauthorized site can gain your user's private data. Angular provides following mechanism
  15586. * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
  15587. * called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
  15588. * runs on your domain could read the cookie, your server can be assured that the XHR came from
  15589. * JavaScript running on your domain.
  15590. *
  15591. * To take advantage of this, your server needs to set a token in a JavaScript readable session
  15592. * cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the
  15593. * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
  15594. * that only JavaScript running on your domain could have read the token. The token must be
  15595. * unique for each user and must be verifiable by the server (to prevent the JavaScript making
  15596. * up its own tokens). We recommend that the token is a digest of your site's authentication
  15597. * cookie with {@link http://en.wikipedia.org/wiki/Rainbow_table salt for added security}.
  15598. *
  15599. *
  15600. * @param {object} config Object describing the request to be made and how it should be
  15601. * processed. The object has following properties:
  15602. *
  15603. * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
  15604. * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
  15605. * - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned to
  15606. * `?key1=value1&key2=value2` after the url. If the value is not a string, it will be JSONified.
  15607. * - **data** – `{string|Object}` – Data to be sent as the request message data.
  15608. * - **headers** – `{Object}` – Map of strings representing HTTP headers to send to the server.
  15609. * - **transformRequest** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
  15610. * transform function or an array of such functions. The transform function takes the http
  15611. * request body and headers and returns its transformed (typically serialized) version.
  15612. * - **transformResponse** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
  15613. * transform function or an array of such functions. The transform function takes the http
  15614. * response body and headers and returns its transformed (typically deserialized) version.
  15615. * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
  15616. * GET request, otherwise if a cache instance built with
  15617. * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
  15618. * caching.
  15619. * - **timeout** – `{number}` – timeout in milliseconds.
  15620. * - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
  15621. * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
  15622. * requests with credentials} for more information.
  15623. *
  15624. * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
  15625. * standard `then` method and two http specific methods: `success` and `error`. The `then`
  15626. * method takes two arguments a success and an error callback which will be called with a
  15627. * response object. The `success` and `error` methods take a single argument - a function that
  15628. * will be called when the request succeeds or fails respectively. The arguments passed into
  15629. * these functions are destructured representation of the response object passed into the
  15630. * `then` method. The response object has these properties:
  15631. *
  15632. * - **data** – `{string|Object}` – The response body transformed with the transform functions.
  15633. * - **status** – `{number}` – HTTP status code of the response.
  15634. * - **headers** – `{function([headerName])}` – Header getter function.
  15635. * - **config** – `{Object}` – The configuration object that was used to generate the request.
  15636. *
  15637. * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
  15638. * requests. This is primarily meant to be used for debugging purposes.
  15639. *
  15640. *
  15641. * @example
  15642. <example>
  15643. <file name="index.html">
  15644. <div ng-controller="FetchCtrl">
  15645. <select ng-model="method">
  15646. <option>GET</option>
  15647. <option>JSONP</option>
  15648. </select>
  15649. <input type="text" ng-model="url" size="80"/>
  15650. <button ng-click="fetch()">fetch</button><br>
  15651. <button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
  15652. <button ng-click="updateModel('JSONP', 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">Sample JSONP</button>
  15653. <button ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">Invalid JSONP</button>
  15654. <pre>http status code: {{status}}</pre>
  15655. <pre>http response data: {{data}}</pre>
  15656. </div>
  15657. </file>
  15658. <file name="script.js">
  15659. function FetchCtrl($scope, $http, $templateCache) {
  15660. $scope.method = 'GET';
  15661. $scope.url = 'http-hello.html';
  15662. $scope.fetch = function() {
  15663. $scope.code = null;
  15664. $scope.response = null;
  15665. $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
  15666. success(function(data, status) {
  15667. $scope.status = status;
  15668. $scope.data = data;
  15669. }).
  15670. error(function(data, status) {
  15671. $scope.data = data || "Request failed";
  15672. $scope.status = status;
  15673. });
  15674. };
  15675. $scope.updateModel = function(method, url) {
  15676. $scope.method = method;
  15677. $scope.url = url;
  15678. };
  15679. }
  15680. </file>
  15681. <file name="http-hello.html">
  15682. Hello, $http!
  15683. </file>
  15684. <file name="scenario.js">
  15685. it('should make an xhr GET request', function() {
  15686. element(':button:contains("Sample GET")').click();
  15687. element(':button:contains("fetch")').click();
  15688. expect(binding('status')).toBe('200');
  15689. expect(binding('data')).toMatch(/Hello, \$http!/);
  15690. });
  15691. it('should make a JSONP request to angularjs.org', function() {
  15692. element(':button:contains("Sample JSONP")').click();
  15693. element(':button:contains("fetch")').click();
  15694. expect(binding('status')).toBe('200');
  15695. expect(binding('data')).toMatch(/Super Hero!/);
  15696. });
  15697. it('should make JSONP request to invalid URL and invoke the error handler',
  15698. function() {
  15699. element(':button:contains("Invalid JSONP")').click();
  15700. element(':button:contains("fetch")').click();
  15701. expect(binding('status')).toBe('0');
  15702. expect(binding('data')).toBe('Request failed');
  15703. });
  15704. </file>
  15705. </example>
  15706. */
  15707. function $http(config) {
  15708. config.method = uppercase(config.method);
  15709. var reqTransformFn = config.transformRequest || $config.transformRequest,
  15710. respTransformFn = config.transformResponse || $config.transformResponse,
  15711. defHeaders = $config.headers,
  15712. reqHeaders = extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
  15713. defHeaders.common, defHeaders[lowercase(config.method)], config.headers),
  15714. reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn),
  15715. promise;
  15716. // strip content-type if data is undefined
  15717. if (isUndefined(config.data)) {
  15718. delete reqHeaders['Content-Type'];
  15719. }
  15720. // send request
  15721. promise = sendReq(config, reqData, reqHeaders);
  15722. // transform future response
  15723. promise = promise.then(transformResponse, transformResponse);
  15724. // apply interceptors
  15725. forEach(responseInterceptors, function(interceptor) {
  15726. promise = interceptor(promise);
  15727. });
  15728. promise.success = function(fn) {
  15729. promise.then(function(response) {
  15730. fn(response.data, response.status, response.headers, config);
  15731. });
  15732. return promise;
  15733. };
  15734. promise.error = function(fn) {
  15735. promise.then(null, function(response) {
  15736. fn(response.data, response.status, response.headers, config);
  15737. });
  15738. return promise;
  15739. };
  15740. return promise;
  15741. function transformResponse(response) {
  15742. // make a copy since the response must be cacheable
  15743. var resp = extend({}, response, {
  15744. data: transformData(response.data, response.headers, respTransformFn)
  15745. });
  15746. return (isSuccess(response.status))
  15747. ? resp
  15748. : $q.reject(resp);
  15749. }
  15750. }
  15751. $http.pendingRequests = [];
  15752. /**
  15753. * @ngdoc method
  15754. * @name ng.$http#get
  15755. * @methodOf ng.$http
  15756. *
  15757. * @description
  15758. * Shortcut method to perform `GET` request
  15759. *
  15760. * @param {string} url Relative or absolute URL specifying the destination of the request
  15761. * @param {Object=} config Optional configuration object
  15762. * @returns {HttpPromise} Future object
  15763. */
  15764. /**
  15765. * @ngdoc method
  15766. * @name ng.$http#delete
  15767. * @methodOf ng.$http
  15768. *
  15769. * @description
  15770. * Shortcut method to perform `DELETE` request
  15771. *
  15772. * @param {string} url Relative or absolute URL specifying the destination of the request
  15773. * @param {Object=} config Optional configuration object
  15774. * @returns {HttpPromise} Future object
  15775. */
  15776. /**
  15777. * @ngdoc method
  15778. * @name ng.$http#head
  15779. * @methodOf ng.$http
  15780. *
  15781. * @description
  15782. * Shortcut method to perform `HEAD` request
  15783. *
  15784. * @param {string} url Relative or absolute URL specifying the destination of the request
  15785. * @param {Object=} config Optional configuration object
  15786. * @returns {HttpPromise} Future object
  15787. */
  15788. /**
  15789. * @ngdoc method
  15790. * @name ng.$http#jsonp
  15791. * @methodOf ng.$http
  15792. *
  15793. * @description
  15794. * Shortcut method to perform `JSONP` request
  15795. *
  15796. * @param {string} url Relative or absolute URL specifying the destination of the request.
  15797. * Should contain `JSON_CALLBACK` string.
  15798. * @param {Object=} config Optional configuration object
  15799. * @returns {HttpPromise} Future object
  15800. */
  15801. createShortMethods('get', 'delete', 'head', 'jsonp');
  15802. /**
  15803. * @ngdoc method
  15804. * @name ng.$http#post
  15805. * @methodOf ng.$http
  15806. *
  15807. * @description
  15808. * Shortcut method to perform `POST` request
  15809. *
  15810. * @param {string} url Relative or absolute URL specifying the destination of the request
  15811. * @param {*} data Request content
  15812. * @param {Object=} config Optional configuration object
  15813. * @returns {HttpPromise} Future object
  15814. */
  15815. /**
  15816. * @ngdoc method
  15817. * @name ng.$http#put
  15818. * @methodOf ng.$http
  15819. *
  15820. * @description
  15821. * Shortcut method to perform `PUT` request
  15822. *
  15823. * @param {string} url Relative or absolute URL specifying the destination of the request
  15824. * @param {*} data Request content
  15825. * @param {Object=} config Optional configuration object
  15826. * @returns {HttpPromise} Future object
  15827. */
  15828. createShortMethodsWithData('post', 'put');
  15829. /**
  15830. * @ngdoc property
  15831. * @name ng.$http#defaults
  15832. * @propertyOf ng.$http
  15833. *
  15834. * @description
  15835. * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
  15836. * default headers as well as request and response transformations.
  15837. *
  15838. * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
  15839. */
  15840. $http.defaults = $config;
  15841. return $http;
  15842. function createShortMethods(names) {
  15843. forEach(arguments, function(name) {
  15844. $http[name] = function(url, config) {
  15845. return $http(extend(config || {}, {
  15846. method: name,
  15847. url: url
  15848. }));
  15849. };
  15850. });
  15851. }
  15852. function createShortMethodsWithData(name) {
  15853. forEach(arguments, function(name) {
  15854. $http[name] = function(url, data, config) {
  15855. return $http(extend(config || {}, {
  15856. method: name,
  15857. url: url,
  15858. data: data
  15859. }));
  15860. };
  15861. });
  15862. }
  15863. /**
  15864. * Makes the request
  15865. *
  15866. * !!! ACCESSES CLOSURE VARS:
  15867. * $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
  15868. */
  15869. function sendReq(config, reqData, reqHeaders) {
  15870. var deferred = $q.defer(),
  15871. promise = deferred.promise,
  15872. cache,
  15873. cachedResp,
  15874. url = buildUrl(config.url, config.params);
  15875. $http.pendingRequests.push(config);
  15876. promise.then(removePendingReq, removePendingReq);
  15877. if (config.cache && config.method == 'GET') {
  15878. cache = isObject(config.cache) ? config.cache : defaultCache;
  15879. }
  15880. if (cache) {
  15881. cachedResp = cache.get(url);
  15882. if (cachedResp) {
  15883. if (cachedResp.then) {
  15884. // cached request has already been sent, but there is no response yet
  15885. cachedResp.then(removePendingReq, removePendingReq);
  15886. return cachedResp;
  15887. } else {
  15888. // serving from cache
  15889. if (isArray(cachedResp)) {
  15890. resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]));
  15891. } else {
  15892. resolvePromise(cachedResp, 200, {});
  15893. }
  15894. }
  15895. } else {
  15896. // put the promise for the non-transformed response into cache as a placeholder
  15897. cache.put(url, promise);
  15898. }
  15899. }
  15900. // if we won't have the response in cache, send the request to the backend
  15901. if (!cachedResp) {
  15902. $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
  15903. config.withCredentials);
  15904. }
  15905. return promise;
  15906. /**
  15907. * Callback registered to $httpBackend():
  15908. * - caches the response if desired
  15909. * - resolves the raw $http promise
  15910. * - calls $apply
  15911. */
  15912. function done(status, response, headersString) {
  15913. if (cache) {
  15914. if (isSuccess(status)) {
  15915. cache.put(url, [status, response, parseHeaders(headersString)]);
  15916. } else {
  15917. // remove promise from the cache
  15918. cache.remove(url);
  15919. }
  15920. }
  15921. resolvePromise(response, status, headersString);
  15922. $rootScope.$apply();
  15923. }
  15924. /**
  15925. * Resolves the raw $http promise.
  15926. */
  15927. function resolvePromise(response, status, headers) {
  15928. // normalize internal statuses to 0
  15929. status = Math.max(status, 0);
  15930. (isSuccess(status) ? deferred.resolve : deferred.reject)({
  15931. data: response,
  15932. status: status,
  15933. headers: headersGetter(headers),
  15934. config: config
  15935. });
  15936. }
  15937. function removePendingReq() {
  15938. var idx = indexOf($http.pendingRequests, config);
  15939. if (idx !== -1) $http.pendingRequests.splice(idx, 1);
  15940. }
  15941. }
  15942. function buildUrl(url, params) {
  15943. if (!params) return url;
  15944. var parts = [];
  15945. forEachSorted(params, function(value, key) {
  15946. if (value == null || value == undefined) return;
  15947. if (isObject(value)) {
  15948. value = toJson(value);
  15949. }
  15950. parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
  15951. });
  15952. return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
  15953. }
  15954. }];
  15955. }
  15956. var XHR = window.XMLHttpRequest || function() {
  15957. try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
  15958. try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
  15959. try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
  15960. throw new Error("This browser does not support XMLHttpRequest.");
  15961. };
  15962. /**
  15963. * @ngdoc object
  15964. * @name ng.$httpBackend
  15965. * @requires $browser
  15966. * @requires $window
  15967. * @requires $document
  15968. *
  15969. * @description
  15970. * HTTP backend used by the {@link ng.$http service} that delegates to
  15971. * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
  15972. *
  15973. * You should never need to use this service directly, instead use the higher-level abstractions:
  15974. * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
  15975. *
  15976. * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
  15977. * $httpBackend} which can be trained with responses.
  15978. */
  15979. function $HttpBackendProvider() {
  15980. this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
  15981. return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks,
  15982. $document[0], $window.location.protocol.replace(':', ''));
  15983. }];
  15984. }
  15985. function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
  15986. // TODO(vojta): fix the signature
  15987. return function(method, url, post, callback, headers, timeout, withCredentials) {
  15988. $browser.$$incOutstandingRequestCount();
  15989. url = url || $browser.url();
  15990. if (lowercase(method) == 'jsonp') {
  15991. var callbackId = '_' + (callbacks.counter++).toString(36);
  15992. callbacks[callbackId] = function(data) {
  15993. callbacks[callbackId].data = data;
  15994. };
  15995. jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
  15996. function() {
  15997. if (callbacks[callbackId].data) {
  15998. completeRequest(callback, 200, callbacks[callbackId].data);
  15999. } else {
  16000. completeRequest(callback, -2);
  16001. }
  16002. delete callbacks[callbackId];
  16003. });
  16004. } else {
  16005. var xhr = new XHR();
  16006. xhr.open(method, url, true);
  16007. forEach(headers, function(value, key) {
  16008. if (value) xhr.setRequestHeader(key, value);
  16009. });
  16010. var status;
  16011. // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
  16012. // response is in the cache. the promise api will ensure that to the app code the api is
  16013. // always async
  16014. xhr.onreadystatechange = function() {
  16015. if (xhr.readyState == 4) {
  16016. var responseHeaders = xhr.getAllResponseHeaders();
  16017. // TODO(vojta): remove once Firefox 21 gets released.
  16018. // begin: workaround to overcome Firefox CORS http response headers bug
  16019. // https://bugzilla.mozilla.org/show_bug.cgi?id=608735
  16020. // Firefox already patched in nightly. Should land in Firefox 21.
  16021. // CORS "simple response headers" http://www.w3.org/TR/cors/
  16022. var value,
  16023. simpleHeaders = ["Cache-Control", "Content-Language", "Content-Type",
  16024. "Expires", "Last-Modified", "Pragma"];
  16025. if (!responseHeaders) {
  16026. responseHeaders = "";
  16027. forEach(simpleHeaders, function (header) {
  16028. var value = xhr.getResponseHeader(header);
  16029. if (value) {
  16030. responseHeaders += header + ": " + value + "\n";
  16031. }
  16032. });
  16033. }
  16034. // end of the workaround.
  16035. completeRequest(callback, status || xhr.status, xhr.responseText,
  16036. responseHeaders);
  16037. }
  16038. };
  16039. if (withCredentials) {
  16040. xhr.withCredentials = true;
  16041. }
  16042. xhr.send(post || '');
  16043. if (timeout > 0) {
  16044. $browserDefer(function() {
  16045. status = -1;
  16046. xhr.abort();
  16047. }, timeout);
  16048. }
  16049. }
  16050. function completeRequest(callback, status, response, headersString) {
  16051. // URL_MATCH is defined in src/service/location.js
  16052. var protocol = (url.match(URL_MATCH) || ['', locationProtocol])[1];
  16053. // fix status code for file protocol (it's always 0)
  16054. status = (protocol == 'file') ? (response ? 200 : 404) : status;
  16055. // normalize IE bug (http://bugs.jquery.com/ticket/1450)
  16056. status = status == 1223 ? 204 : status;
  16057. callback(status, response, headersString);
  16058. $browser.$$completeOutstandingRequest(noop);
  16059. }
  16060. };
  16061. function jsonpReq(url, done) {
  16062. // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
  16063. // - fetches local scripts via XHR and evals them
  16064. // - adds and immediately removes script elements from the document
  16065. var script = rawDocument.createElement('script'),
  16066. doneWrapper = function() {
  16067. rawDocument.body.removeChild(script);
  16068. if (done) done();
  16069. };
  16070. script.type = 'text/javascript';
  16071. script.src = url;
  16072. if (msie) {
  16073. script.onreadystatechange = function() {
  16074. if (/loaded|complete/.test(script.readyState)) doneWrapper();
  16075. };
  16076. } else {
  16077. script.onload = script.onerror = doneWrapper;
  16078. }
  16079. rawDocument.body.appendChild(script);
  16080. }
  16081. }
  16082. /**
  16083. * @ngdoc object
  16084. * @name ng.$locale
  16085. *
  16086. * @description
  16087. * $locale service provides localization rules for various Angular components. As of right now the
  16088. * only public api is:
  16089. *
  16090. * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
  16091. */
  16092. function $LocaleProvider(){
  16093. this.$get = function() {
  16094. return {
  16095. id: 'en-us',
  16096. NUMBER_FORMATS: {
  16097. DECIMAL_SEP: '.',
  16098. GROUP_SEP: ',',
  16099. PATTERNS: [
  16100. { // Decimal Pattern
  16101. minInt: 1,
  16102. minFrac: 0,
  16103. maxFrac: 3,
  16104. posPre: '',
  16105. posSuf: '',
  16106. negPre: '-',
  16107. negSuf: '',
  16108. gSize: 3,
  16109. lgSize: 3
  16110. },{ //Currency Pattern
  16111. minInt: 1,
  16112. minFrac: 2,
  16113. maxFrac: 2,
  16114. posPre: '\u00A4',
  16115. posSuf: '',
  16116. negPre: '(\u00A4',
  16117. negSuf: ')',
  16118. gSize: 3,
  16119. lgSize: 3
  16120. }
  16121. ],
  16122. CURRENCY_SYM: '$'
  16123. },
  16124. DATETIME_FORMATS: {
  16125. MONTH: 'January,February,March,April,May,June,July,August,September,October,November,December'
  16126. .split(','),
  16127. SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
  16128. DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
  16129. SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
  16130. AMPMS: ['AM','PM'],
  16131. medium: 'MMM d, y h:mm:ss a',
  16132. short: 'M/d/yy h:mm a',
  16133. fullDate: 'EEEE, MMMM d, y',
  16134. longDate: 'MMMM d, y',
  16135. mediumDate: 'MMM d, y',
  16136. shortDate: 'M/d/yy',
  16137. mediumTime: 'h:mm:ss a',
  16138. shortTime: 'h:mm a'
  16139. },
  16140. pluralCat: function(num) {
  16141. if (num === 1) {
  16142. return 'one';
  16143. }
  16144. return 'other';
  16145. }
  16146. };
  16147. };
  16148. }
  16149. function $TimeoutProvider() {
  16150. this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
  16151. function($rootScope, $browser, $q, $exceptionHandler) {
  16152. var deferreds = {};
  16153. /**
  16154. * @ngdoc function
  16155. * @name ng.$timeout
  16156. * @requires $browser
  16157. *
  16158. * @description
  16159. * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
  16160. * block and delegates any exceptions to
  16161. * {@link ng.$exceptionHandler $exceptionHandler} service.
  16162. *
  16163. * The return value of registering a timeout function is a promise which will be resolved when
  16164. * the timeout is reached and the timeout function is executed.
  16165. *
  16166. * To cancel a the timeout request, call `$timeout.cancel(promise)`.
  16167. *
  16168. * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
  16169. * synchronously flush the queue of deferred functions.
  16170. *
  16171. * @param {function()} fn A function, who's execution should be delayed.
  16172. * @param {number=} [delay=0] Delay in milliseconds.
  16173. * @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
  16174. * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
  16175. * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
  16176. * promise will be resolved with is the return value of the `fn` function.
  16177. */
  16178. function timeout(fn, delay, invokeApply) {
  16179. var deferred = $q.defer(),
  16180. promise = deferred.promise,
  16181. skipApply = (isDefined(invokeApply) && !invokeApply),
  16182. timeoutId, cleanup;
  16183. timeoutId = $browser.defer(function() {
  16184. try {
  16185. deferred.resolve(fn());
  16186. } catch(e) {
  16187. deferred.reject(e);
  16188. $exceptionHandler(e);
  16189. }
  16190. if (!skipApply) $rootScope.$apply();
  16191. }, delay);
  16192. cleanup = function() {
  16193. delete deferreds[promise.$$timeoutId];
  16194. };
  16195. promise.$$timeoutId = timeoutId;
  16196. deferreds[timeoutId] = deferred;
  16197. promise.then(cleanup, cleanup);
  16198. return promise;
  16199. }
  16200. /**
  16201. * @ngdoc function
  16202. * @name ng.$timeout#cancel
  16203. * @methodOf ng.$timeout
  16204. *
  16205. * @description
  16206. * Cancels a task associated with the `promise`. As a result of this the promise will be
  16207. * resolved with a rejection.
  16208. *
  16209. * @param {Promise=} promise Promise returned by the `$timeout` function.
  16210. * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
  16211. * canceled.
  16212. */
  16213. timeout.cancel = function(promise) {
  16214. if (promise && promise.$$timeoutId in deferreds) {
  16215. deferreds[promise.$$timeoutId].reject('canceled');
  16216. return $browser.defer.cancel(promise.$$timeoutId);
  16217. }
  16218. return false;
  16219. };
  16220. return timeout;
  16221. }];
  16222. }
  16223. /**
  16224. * @ngdoc object
  16225. * @name ng.$filterProvider
  16226. * @description
  16227. *
  16228. * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
  16229. * achieve this a filter definition consists of a factory function which is annotated with dependencies and is
  16230. * responsible for creating a filter function.
  16231. *
  16232. * <pre>
  16233. * // Filter registration
  16234. * function MyModule($provide, $filterProvider) {
  16235. * // create a service to demonstrate injection (not always needed)
  16236. * $provide.value('greet', function(name){
  16237. * return 'Hello ' + name + '!';
  16238. * });
  16239. *
  16240. * // register a filter factory which uses the
  16241. * // greet service to demonstrate DI.
  16242. * $filterProvider.register('greet', function(greet){
  16243. * // return the filter function which uses the greet service
  16244. * // to generate salutation
  16245. * return function(text) {
  16246. * // filters need to be forgiving so check input validity
  16247. * return text && greet(text) || text;
  16248. * };
  16249. * });
  16250. * }
  16251. * </pre>
  16252. *
  16253. * The filter function is registered with the `$injector` under the filter name suffixe with `Filter`.
  16254. * <pre>
  16255. * it('should be the same instance', inject(
  16256. * function($filterProvider) {
  16257. * $filterProvider.register('reverse', function(){
  16258. * return ...;
  16259. * });
  16260. * },
  16261. * function($filter, reverseFilter) {
  16262. * expect($filter('reverse')).toBe(reverseFilter);
  16263. * });
  16264. * </pre>
  16265. *
  16266. *
  16267. * For more information about how angular filters work, and how to create your own filters, see
  16268. * {@link guide/dev_guide.templates.filters Understanding Angular Filters} in the angular Developer
  16269. * Guide.
  16270. */
  16271. /**
  16272. * @ngdoc method
  16273. * @name ng.$filterProvider#register
  16274. * @methodOf ng.$filterProvider
  16275. * @description
  16276. * Register filter factory function.
  16277. *
  16278. * @param {String} name Name of the filter.
  16279. * @param {function} fn The filter factory function which is injectable.
  16280. */
  16281. /**
  16282. * @ngdoc function
  16283. * @name ng.$filter
  16284. * @function
  16285. * @description
  16286. * Filters are used for formatting data displayed to the user.
  16287. *
  16288. * The general syntax in templates is as follows:
  16289. *
  16290. * {{ expression | [ filter_name ] }}
  16291. *
  16292. * @param {String} name Name of the filter function to retrieve
  16293. * @return {Function} the filter function
  16294. */
  16295. $FilterProvider.$inject = ['$provide'];
  16296. function $FilterProvider($provide) {
  16297. var suffix = 'Filter';
  16298. function register(name, factory) {
  16299. return $provide.factory(name + suffix, factory);
  16300. }
  16301. this.register = register;
  16302. this.$get = ['$injector', function($injector) {
  16303. return function(name) {
  16304. return $injector.get(name + suffix);
  16305. }
  16306. }];
  16307. ////////////////////////////////////////
  16308. register('currency', currencyFilter);
  16309. register('date', dateFilter);
  16310. register('filter', filterFilter);
  16311. register('json', jsonFilter);
  16312. register('limitTo', limitToFilter);
  16313. register('lowercase', lowercaseFilter);
  16314. register('number', numberFilter);
  16315. register('orderBy', orderByFilter);
  16316. register('uppercase', uppercaseFilter);
  16317. }
  16318. /**
  16319. * @ngdoc filter
  16320. * @name ng.filter:filter
  16321. * @function
  16322. *
  16323. * @description
  16324. * Selects a subset of items from `array` and returns it as a new array.
  16325. *
  16326. * Note: This function is used to augment the `Array` type in Angular expressions. See
  16327. * {@link ng.$filter} for more information about Angular arrays.
  16328. *
  16329. * @param {Array} array The source array.
  16330. * @param {string|Object|function()} expression The predicate to be used for selecting items from
  16331. * `array`.
  16332. *
  16333. * Can be one of:
  16334. *
  16335. * - `string`: Predicate that results in a substring match using the value of `expression`
  16336. * string. All strings or objects with string properties in `array` that contain this string
  16337. * will be returned. The predicate can be negated by prefixing the string with `!`.
  16338. *
  16339. * - `Object`: A pattern object can be used to filter specific properties on objects contained
  16340. * by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
  16341. * which have property `name` containing "M" and property `phone` containing "1". A special
  16342. * property name `$` can be used (as in `{$:"text"}`) to accept a match against any
  16343. * property of the object. That's equivalent to the simple substring match with a `string`
  16344. * as described above.
  16345. *
  16346. * - `function`: A predicate function can be used to write arbitrary filters. The function is
  16347. * called for each element of `array`. The final result is an array of those elements that
  16348. * the predicate returned true for.
  16349. *
  16350. * @example
  16351. <doc:example>
  16352. <doc:source>
  16353. <div ng-init="friends = [{name:'John', phone:'555-1276'},
  16354. {name:'Mary', phone:'800-BIG-MARY'},
  16355. {name:'Mike', phone:'555-4321'},
  16356. {name:'Adam', phone:'555-5678'},
  16357. {name:'Julie', phone:'555-8765'}]"></div>
  16358. Search: <input ng-model="searchText">
  16359. <table id="searchTextResults">
  16360. <tr><th>Name</th><th>Phone</th></tr>
  16361. <tr ng-repeat="friend in friends | filter:searchText">
  16362. <td>{{friend.name}}</td>
  16363. <td>{{friend.phone}}</td>
  16364. </tr>
  16365. </table>
  16366. <hr>
  16367. Any: <input ng-model="search.$"> <br>
  16368. Name only <input ng-model="search.name"><br>
  16369. Phone only <input ng-model="search.phone"å><br>
  16370. <table id="searchObjResults">
  16371. <tr><th>Name</th><th>Phone</th></tr>
  16372. <tr ng-repeat="friend in friends | filter:search">
  16373. <td>{{friend.name}}</td>
  16374. <td>{{friend.phone}}</td>
  16375. </tr>
  16376. </table>
  16377. </doc:source>
  16378. <doc:scenario>
  16379. it('should search across all fields when filtering with a string', function() {
  16380. input('searchText').enter('m');
  16381. expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
  16382. toEqual(['Mary', 'Mike', 'Adam']);
  16383. input('searchText').enter('76');
  16384. expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
  16385. toEqual(['John', 'Julie']);
  16386. });
  16387. it('should search in specific fields when filtering with a predicate object', function() {
  16388. input('search.$').enter('i');
  16389. expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
  16390. toEqual(['Mary', 'Mike', 'Julie']);
  16391. });
  16392. </doc:scenario>
  16393. </doc:example>
  16394. */
  16395. function filterFilter() {
  16396. return function(array, expression) {
  16397. if (!isArray(array)) return array;
  16398. var predicates = [];
  16399. predicates.check = function(value) {
  16400. for (var j = 0; j < predicates.length; j++) {
  16401. if(!predicates[j](value)) {
  16402. return false;
  16403. }
  16404. }
  16405. return true;
  16406. };
  16407. var search = function(obj, text){
  16408. if (text.charAt(0) === '!') {
  16409. return !search(obj, text.substr(1));
  16410. }
  16411. switch (typeof obj) {
  16412. case "boolean":
  16413. case "number":
  16414. case "string":
  16415. return ('' + obj).toLowerCase().indexOf(text) > -1;
  16416. case "object":
  16417. for ( var objKey in obj) {
  16418. if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
  16419. return true;
  16420. }
  16421. }
  16422. return false;
  16423. case "array":
  16424. for ( var i = 0; i < obj.length; i++) {
  16425. if (search(obj[i], text)) {
  16426. return true;
  16427. }
  16428. }
  16429. return false;
  16430. default:
  16431. return false;
  16432. }
  16433. };
  16434. switch (typeof expression) {
  16435. case "boolean":
  16436. case "number":
  16437. case "string":
  16438. expression = {$:expression};
  16439. case "object":
  16440. for (var key in expression) {
  16441. if (key == '$') {
  16442. (function() {
  16443. var text = (''+expression[key]).toLowerCase();
  16444. if (!text) return;
  16445. predicates.push(function(value) {
  16446. return search(value, text);
  16447. });
  16448. })();
  16449. } else {
  16450. (function() {
  16451. var path = key;
  16452. var text = (''+expression[key]).toLowerCase();
  16453. if (!text) return;
  16454. predicates.push(function(value) {
  16455. return search(getter(value, path), text);
  16456. });
  16457. })();
  16458. }
  16459. }
  16460. break;
  16461. case 'function':
  16462. predicates.push(expression);
  16463. break;
  16464. default:
  16465. return array;
  16466. }
  16467. var filtered = [];
  16468. for ( var j = 0; j < array.length; j++) {
  16469. var value = array[j];
  16470. if (predicates.check(value)) {
  16471. filtered.push(value);
  16472. }
  16473. }
  16474. return filtered;
  16475. }
  16476. }
  16477. /**
  16478. * @ngdoc filter
  16479. * @name ng.filter:currency
  16480. * @function
  16481. *
  16482. * @description
  16483. * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
  16484. * symbol for current locale is used.
  16485. *
  16486. * @param {number} amount Input to filter.
  16487. * @param {string=} symbol Currency symbol or identifier to be displayed.
  16488. * @returns {string} Formatted number.
  16489. *
  16490. *
  16491. * @example
  16492. <doc:example>
  16493. <doc:source>
  16494. <script>
  16495. function Ctrl($scope) {
  16496. $scope.amount = 1234.56;
  16497. }
  16498. </script>
  16499. <div ng-controller="Ctrl">
  16500. <input type="number" ng-model="amount"> <br>
  16501. default currency symbol ($): {{amount | currency}}<br>
  16502. custom currency identifier (USD$): {{amount | currency:"USD$"}}
  16503. </div>
  16504. </doc:source>
  16505. <doc:scenario>
  16506. it('should init with 1234.56', function() {
  16507. expect(binding('amount | currency')).toBe('$1,234.56');
  16508. expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56');
  16509. });
  16510. it('should update', function() {
  16511. input('amount').enter('-1234');
  16512. expect(binding('amount | currency')).toBe('($1,234.00)');
  16513. expect(binding('amount | currency:"USD$"')).toBe('(USD$1,234.00)');
  16514. });
  16515. </doc:scenario>
  16516. </doc:example>
  16517. */
  16518. currencyFilter.$inject = ['$locale'];
  16519. function currencyFilter($locale) {
  16520. var formats = $locale.NUMBER_FORMATS;
  16521. return function(amount, currencySymbol){
  16522. if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
  16523. return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
  16524. replace(/\u00A4/g, currencySymbol);
  16525. };
  16526. }
  16527. /**
  16528. * @ngdoc filter
  16529. * @name ng.filter:number
  16530. * @function
  16531. *
  16532. * @description
  16533. * Formats a number as text.
  16534. *
  16535. * If the input is not a number an empty string is returned.
  16536. *
  16537. * @param {number|string} number Number to format.
  16538. * @param {(number|string)=} [fractionSize=2] Number of decimal places to round the number to.
  16539. * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
  16540. *
  16541. * @example
  16542. <doc:example>
  16543. <doc:source>
  16544. <script>
  16545. function Ctrl($scope) {
  16546. $scope.val = 1234.56789;
  16547. }
  16548. </script>
  16549. <div ng-controller="Ctrl">
  16550. Enter number: <input ng-model='val'><br>
  16551. Default formatting: {{val | number}}<br>
  16552. No fractions: {{val | number:0}}<br>
  16553. Negative number: {{-val | number:4}}
  16554. </div>
  16555. </doc:source>
  16556. <doc:scenario>
  16557. it('should format numbers', function() {
  16558. expect(binding('val | number')).toBe('1,234.568');
  16559. expect(binding('val | number:0')).toBe('1,235');
  16560. expect(binding('-val | number:4')).toBe('-1,234.5679');
  16561. });
  16562. it('should update', function() {
  16563. input('val').enter('3374.333');
  16564. expect(binding('val | number')).toBe('3,374.333');
  16565. expect(binding('val | number:0')).toBe('3,374');
  16566. expect(binding('-val | number:4')).toBe('-3,374.3330');
  16567. });
  16568. </doc:scenario>
  16569. </doc:example>
  16570. */
  16571. numberFilter.$inject = ['$locale'];
  16572. function numberFilter($locale) {
  16573. var formats = $locale.NUMBER_FORMATS;
  16574. return function(number, fractionSize) {
  16575. return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
  16576. fractionSize);
  16577. };
  16578. }
  16579. var DECIMAL_SEP = '.';
  16580. function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
  16581. if (isNaN(number) || !isFinite(number)) return '';
  16582. var isNegative = number < 0;
  16583. number = Math.abs(number);
  16584. var numStr = number + '',
  16585. formatedText = '',
  16586. parts = [];
  16587. var hasExponent = false;
  16588. if (numStr.indexOf('e') !== -1) {
  16589. var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
  16590. if (match && match[2] == '-' && match[3] > fractionSize + 1) {
  16591. numStr = '0';
  16592. } else {
  16593. formatedText = numStr;
  16594. hasExponent = true;
  16595. }
  16596. }
  16597. if (!hasExponent) {
  16598. var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
  16599. // determine fractionSize if it is not specified
  16600. if (isUndefined(fractionSize)) {
  16601. fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
  16602. }
  16603. var pow = Math.pow(10, fractionSize);
  16604. number = Math.round(number * pow) / pow;
  16605. var fraction = ('' + number).split(DECIMAL_SEP);
  16606. var whole = fraction[0];
  16607. fraction = fraction[1] || '';
  16608. var pos = 0,
  16609. lgroup = pattern.lgSize,
  16610. group = pattern.gSize;
  16611. if (whole.length >= (lgroup + group)) {
  16612. pos = whole.length - lgroup;
  16613. for (var i = 0; i < pos; i++) {
  16614. if ((pos - i)%group === 0 && i !== 0) {
  16615. formatedText += groupSep;
  16616. }
  16617. formatedText += whole.charAt(i);
  16618. }
  16619. }
  16620. for (i = pos; i < whole.length; i++) {
  16621. if ((whole.length - i)%lgroup === 0 && i !== 0) {
  16622. formatedText += groupSep;
  16623. }
  16624. formatedText += whole.charAt(i);
  16625. }
  16626. // format fraction part.
  16627. while(fraction.length < fractionSize) {
  16628. fraction += '0';
  16629. }
  16630. if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
  16631. }
  16632. parts.push(isNegative ? pattern.negPre : pattern.posPre);
  16633. parts.push(formatedText);
  16634. parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
  16635. return parts.join('');
  16636. }
  16637. function padNumber(num, digits, trim) {
  16638. var neg = '';
  16639. if (num < 0) {
  16640. neg = '-';
  16641. num = -num;
  16642. }
  16643. num = '' + num;
  16644. while(num.length < digits) num = '0' + num;
  16645. if (trim)
  16646. num = num.substr(num.length - digits);
  16647. return neg + num;
  16648. }
  16649. function dateGetter(name, size, offset, trim) {
  16650. return function(date) {
  16651. var value = date['get' + name]();
  16652. if (offset > 0 || value > -offset)
  16653. value += offset;
  16654. if (value === 0 && offset == -12 ) value = 12;
  16655. return padNumber(value, size, trim);
  16656. };
  16657. }
  16658. function dateStrGetter(name, shortForm) {
  16659. return function(date, formats) {
  16660. var value = date['get' + name]();
  16661. var get = uppercase(shortForm ? ('SHORT' + name) : name);
  16662. return formats[get][value];
  16663. };
  16664. }
  16665. function timeZoneGetter(date) {
  16666. var zone = -1 * date.getTimezoneOffset();
  16667. var paddedZone = (zone >= 0) ? "+" : "";
  16668. paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
  16669. padNumber(Math.abs(zone % 60), 2);
  16670. return paddedZone;
  16671. }
  16672. function ampmGetter(date, formats) {
  16673. return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
  16674. }
  16675. var DATE_FORMATS = {
  16676. yyyy: dateGetter('FullYear', 4),
  16677. yy: dateGetter('FullYear', 2, 0, true),
  16678. y: dateGetter('FullYear', 1),
  16679. MMMM: dateStrGetter('Month'),
  16680. MMM: dateStrGetter('Month', true),
  16681. MM: dateGetter('Month', 2, 1),
  16682. M: dateGetter('Month', 1, 1),
  16683. dd: dateGetter('Date', 2),
  16684. d: dateGetter('Date', 1),
  16685. HH: dateGetter('Hours', 2),
  16686. H: dateGetter('Hours', 1),
  16687. hh: dateGetter('Hours', 2, -12),
  16688. h: dateGetter('Hours', 1, -12),
  16689. mm: dateGetter('Minutes', 2),
  16690. m: dateGetter('Minutes', 1),
  16691. ss: dateGetter('Seconds', 2),
  16692. s: dateGetter('Seconds', 1),
  16693. EEEE: dateStrGetter('Day'),
  16694. EEE: dateStrGetter('Day', true),
  16695. a: ampmGetter,
  16696. Z: timeZoneGetter
  16697. };
  16698. var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
  16699. NUMBER_STRING = /^\d+$/;
  16700. /**
  16701. * @ngdoc filter
  16702. * @name ng.filter:date
  16703. * @function
  16704. *
  16705. * @description
  16706. * Formats `date` to a string based on the requested `format`.
  16707. *
  16708. * `format` string can be composed of the following elements:
  16709. *
  16710. * * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
  16711. * * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
  16712. * * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
  16713. * * `'MMMM'`: Month in year (January-December)
  16714. * * `'MMM'`: Month in year (Jan-Dec)
  16715. * * `'MM'`: Month in year, padded (01-12)
  16716. * * `'M'`: Month in year (1-12)
  16717. * * `'dd'`: Day in month, padded (01-31)
  16718. * * `'d'`: Day in month (1-31)
  16719. * * `'EEEE'`: Day in Week,(Sunday-Saturday)
  16720. * * `'EEE'`: Day in Week, (Sun-Sat)
  16721. * * `'HH'`: Hour in day, padded (00-23)
  16722. * * `'H'`: Hour in day (0-23)
  16723. * * `'hh'`: Hour in am/pm, padded (01-12)
  16724. * * `'h'`: Hour in am/pm, (1-12)
  16725. * * `'mm'`: Minute in hour, padded (00-59)
  16726. * * `'m'`: Minute in hour (0-59)
  16727. * * `'ss'`: Second in minute, padded (00-59)
  16728. * * `'s'`: Second in minute (0-59)
  16729. * * `'a'`: am/pm marker
  16730. * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
  16731. *
  16732. * `format` string can also be one of the following predefined
  16733. * {@link guide/i18n localizable formats}:
  16734. *
  16735. * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
  16736. * (e.g. Sep 3, 2010 12:05:08 pm)
  16737. * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 pm)
  16738. * * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US locale
  16739. * (e.g. Friday, September 3, 2010)
  16740. * * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010
  16741. * * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010)
  16742. * * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
  16743. * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
  16744. * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
  16745. *
  16746. * `format` string can contain literal values. These need to be quoted with single quotes (e.g.
  16747. * `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
  16748. * (e.g. `"h o''clock"`).
  16749. *
  16750. * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
  16751. * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's
  16752. * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
  16753. * specified in the string input, the time is considered to be in the local timezone.
  16754. * @param {string=} format Formatting rules (see Description). If not specified,
  16755. * `mediumDate` is used.
  16756. * @returns {string} Formatted string or the input if input is not recognized as date/millis.
  16757. *
  16758. * @example
  16759. <doc:example>
  16760. <doc:source>
  16761. <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
  16762. {{1288323623006 | date:'medium'}}<br>
  16763. <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
  16764. {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br>
  16765. <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
  16766. {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}<br>
  16767. </doc:source>
  16768. <doc:scenario>
  16769. it('should format date', function() {
  16770. expect(binding("1288323623006 | date:'medium'")).
  16771. toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
  16772. expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
  16773. toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
  16774. expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
  16775. toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
  16776. });
  16777. </doc:scenario>
  16778. </doc:example>
  16779. */
  16780. dateFilter.$inject = ['$locale'];
  16781. function dateFilter($locale) {
  16782. var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
  16783. function jsonStringToDate(string){
  16784. var match;
  16785. if (match = string.match(R_ISO8601_STR)) {
  16786. var date = new Date(0),
  16787. tzHour = 0,
  16788. tzMin = 0;
  16789. if (match[9]) {
  16790. tzHour = int(match[9] + match[10]);
  16791. tzMin = int(match[9] + match[11]);
  16792. }
  16793. date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
  16794. date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
  16795. return date;
  16796. }
  16797. return string;
  16798. }
  16799. return function(date, format) {
  16800. var text = '',
  16801. parts = [],
  16802. fn, match;
  16803. format = format || 'mediumDate';
  16804. format = $locale.DATETIME_FORMATS[format] || format;
  16805. if (isString(date)) {
  16806. if (NUMBER_STRING.test(date)) {
  16807. date = int(date);
  16808. } else {
  16809. date = jsonStringToDate(date);
  16810. }
  16811. }
  16812. if (isNumber(date)) {
  16813. date = new Date(date);
  16814. }
  16815. if (!isDate(date)) {
  16816. return date;
  16817. }
  16818. while(format) {
  16819. match = DATE_FORMATS_SPLIT.exec(format);
  16820. if (match) {
  16821. parts = concat(parts, match, 1);
  16822. format = parts.pop();
  16823. } else {
  16824. parts.push(format);
  16825. format = null;
  16826. }
  16827. }
  16828. forEach(parts, function(value){
  16829. fn = DATE_FORMATS[value];
  16830. text += fn ? fn(date, $locale.DATETIME_FORMATS)
  16831. : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
  16832. });
  16833. return text;
  16834. };
  16835. }
  16836. /**
  16837. * @ngdoc filter
  16838. * @name ng.filter:json
  16839. * @function
  16840. *
  16841. * @description
  16842. * Allows you to convert a JavaScript object into JSON string.
  16843. *
  16844. * This filter is mostly useful for debugging. When using the double curly {{value}} notation
  16845. * the binding is automatically converted to JSON.
  16846. *
  16847. * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
  16848. * @returns {string} JSON string.
  16849. *
  16850. *
  16851. * @example:
  16852. <doc:example>
  16853. <doc:source>
  16854. <pre>{{ {'name':'value'} | json }}</pre>
  16855. </doc:source>
  16856. <doc:scenario>
  16857. it('should jsonify filtered objects', function() {
  16858. expect(binding("{'name':'value'}")).toMatch(/\{\n "name": ?"value"\n}/);
  16859. });
  16860. </doc:scenario>
  16861. </doc:example>
  16862. *
  16863. */
  16864. function jsonFilter() {
  16865. return function(object) {
  16866. return toJson(object, true);
  16867. };
  16868. }
  16869. /**
  16870. * @ngdoc filter
  16871. * @name ng.filter:lowercase
  16872. * @function
  16873. * @description
  16874. * Converts string to lowercase.
  16875. * @see angular.lowercase
  16876. */
  16877. var lowercaseFilter = valueFn(lowercase);
  16878. /**
  16879. * @ngdoc filter
  16880. * @name ng.filter:uppercase
  16881. * @function
  16882. * @description
  16883. * Converts string to uppercase.
  16884. * @see angular.uppercase
  16885. */
  16886. var uppercaseFilter = valueFn(uppercase);
  16887. /**
  16888. * @ngdoc function
  16889. * @name ng.filter:limitTo
  16890. * @function
  16891. *
  16892. * @description
  16893. * Creates a new array containing only a specified number of elements in an array. The elements
  16894. * are taken from either the beginning or the end of the source array, as specified by the
  16895. * value and sign (positive or negative) of `limit`.
  16896. *
  16897. * Note: This function is used to augment the `Array` type in Angular expressions. See
  16898. * {@link ng.$filter} for more information about Angular arrays.
  16899. *
  16900. * @param {Array} array Source array to be limited.
  16901. * @param {string|Number} limit The length of the returned array. If the `limit` number is
  16902. * positive, `limit` number of items from the beginning of the source array are copied.
  16903. * If the number is negative, `limit` number of items from the end of the source array are
  16904. * copied. The `limit` will be trimmed if it exceeds `array.length`
  16905. * @returns {Array} A new sub-array of length `limit` or less if input array had less than `limit`
  16906. * elements.
  16907. *
  16908. * @example
  16909. <doc:example>
  16910. <doc:source>
  16911. <script>
  16912. function Ctrl($scope) {
  16913. $scope.numbers = [1,2,3,4,5,6,7,8,9];
  16914. $scope.limit = 3;
  16915. }
  16916. </script>
  16917. <div ng-controller="Ctrl">
  16918. Limit {{numbers}} to: <input type="integer" ng-model="limit">
  16919. <p>Output: {{ numbers | limitTo:limit }}</p>
  16920. </div>
  16921. </doc:source>
  16922. <doc:scenario>
  16923. it('should limit the numer array to first three items', function() {
  16924. expect(element('.doc-example-live input[ng-model=limit]').val()).toBe('3');
  16925. expect(binding('numbers | limitTo:limit')).toEqual('[1,2,3]');
  16926. });
  16927. it('should update the output when -3 is entered', function() {
  16928. input('limit').enter(-3);
  16929. expect(binding('numbers | limitTo:limit')).toEqual('[7,8,9]');
  16930. });
  16931. it('should not exceed the maximum size of input array', function() {
  16932. input('limit').enter(100);
  16933. expect(binding('numbers | limitTo:limit')).toEqual('[1,2,3,4,5,6,7,8,9]');
  16934. });
  16935. </doc:scenario>
  16936. </doc:example>
  16937. */
  16938. function limitToFilter(){
  16939. return function(array, limit) {
  16940. if (!(array instanceof Array)) return array;
  16941. limit = int(limit);
  16942. var out = [],
  16943. i, n;
  16944. // check that array is iterable
  16945. if (!array || !(array instanceof Array))
  16946. return out;
  16947. // if abs(limit) exceeds maximum length, trim it
  16948. if (limit > array.length)
  16949. limit = array.length;
  16950. else if (limit < -array.length)
  16951. limit = -array.length;
  16952. if (limit > 0) {
  16953. i = 0;
  16954. n = limit;
  16955. } else {
  16956. i = array.length + limit;
  16957. n = array.length;
  16958. }
  16959. for (; i<n; i++) {
  16960. out.push(array[i]);
  16961. }
  16962. return out;
  16963. }
  16964. }
  16965. /**
  16966. * @ngdoc function
  16967. * @name ng.filter:orderBy
  16968. * @function
  16969. *
  16970. * @description
  16971. * Orders a specified `array` by the `expression` predicate.
  16972. *
  16973. * Note: this function is used to augment the `Array` type in Angular expressions. See
  16974. * {@link ng.$filter} for more informaton about Angular arrays.
  16975. *
  16976. * @param {Array} array The array to sort.
  16977. * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
  16978. * used by the comparator to determine the order of elements.
  16979. *
  16980. * Can be one of:
  16981. *
  16982. * - `function`: Getter function. The result of this function will be sorted using the
  16983. * `<`, `=`, `>` operator.
  16984. * - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
  16985. * to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
  16986. * ascending or descending sort order (for example, +name or -name).
  16987. * - `Array`: An array of function or string predicates. The first predicate in the array
  16988. * is used for sorting, but when two items are equivalent, the next predicate is used.
  16989. *
  16990. * @param {boolean=} reverse Reverse the order the array.
  16991. * @returns {Array} Sorted copy of the source array.
  16992. *
  16993. * @example
  16994. <doc:example>
  16995. <doc:source>
  16996. <script>
  16997. function Ctrl($scope) {
  16998. $scope.friends =
  16999. [{name:'John', phone:'555-1212', age:10},
  17000. {name:'Mary', phone:'555-9876', age:19},
  17001. {name:'Mike', phone:'555-4321', age:21},
  17002. {name:'Adam', phone:'555-5678', age:35},
  17003. {name:'Julie', phone:'555-8765', age:29}]
  17004. $scope.predicate = '-age';
  17005. }
  17006. </script>
  17007. <div ng-controller="Ctrl">
  17008. <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
  17009. <hr/>
  17010. [ <a href="" ng-click="predicate=''">unsorted</a> ]
  17011. <table class="friend">
  17012. <tr>
  17013. <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
  17014. (<a href ng-click="predicate = '-name'; reverse=false">^</a>)</th>
  17015. <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
  17016. <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
  17017. </tr>
  17018. <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
  17019. <td>{{friend.name}}</td>
  17020. <td>{{friend.phone}}</td>
  17021. <td>{{friend.age}}</td>
  17022. </tr>
  17023. </table>
  17024. </div>
  17025. </doc:source>
  17026. <doc:scenario>
  17027. it('should be reverse ordered by aged', function() {
  17028. expect(binding('predicate')).toBe('-age');
  17029. expect(repeater('table.friend', 'friend in friends').column('friend.age')).
  17030. toEqual(['35', '29', '21', '19', '10']);
  17031. expect(repeater('table.friend', 'friend in friends').column('friend.name')).
  17032. toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
  17033. });
  17034. it('should reorder the table when user selects different predicate', function() {
  17035. element('.doc-example-live a:contains("Name")').click();
  17036. expect(repeater('table.friend', 'friend in friends').column('friend.name')).
  17037. toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
  17038. expect(repeater('table.friend', 'friend in friends').column('friend.age')).
  17039. toEqual(['35', '10', '29', '19', '21']);
  17040. element('.doc-example-live a:contains("Phone")').click();
  17041. expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
  17042. toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
  17043. expect(repeater('table.friend', 'friend in friends').column('friend.name')).
  17044. toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
  17045. });
  17046. </doc:scenario>
  17047. </doc:example>
  17048. */
  17049. orderByFilter.$inject = ['$parse'];
  17050. function orderByFilter($parse){
  17051. return function(array, sortPredicate, reverseOrder) {
  17052. if (!isArray(array)) return array;
  17053. if (!sortPredicate) return array;
  17054. sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
  17055. sortPredicate = map(sortPredicate, function(predicate){
  17056. var descending = false, get = predicate || identity;
  17057. if (isString(predicate)) {
  17058. if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
  17059. descending = predicate.charAt(0) == '-';
  17060. predicate = predicate.substring(1);
  17061. }
  17062. get = $parse(predicate);
  17063. }
  17064. return reverseComparator(function(a,b){
  17065. return compare(get(a),get(b));
  17066. }, descending);
  17067. });
  17068. var arrayCopy = [];
  17069. for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
  17070. return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
  17071. function comparator(o1, o2){
  17072. for ( var i = 0; i < sortPredicate.length; i++) {
  17073. var comp = sortPredicate[i](o1, o2);
  17074. if (comp !== 0) return comp;
  17075. }
  17076. return 0;
  17077. }
  17078. function reverseComparator(comp, descending) {
  17079. return toBoolean(descending)
  17080. ? function(a,b){return comp(b,a);}
  17081. : comp;
  17082. }
  17083. function compare(v1, v2){
  17084. var t1 = typeof v1;
  17085. var t2 = typeof v2;
  17086. if (t1 == t2) {
  17087. if (t1 == "string") v1 = v1.toLowerCase();
  17088. if (t1 == "string") v2 = v2.toLowerCase();
  17089. if (v1 === v2) return 0;
  17090. return v1 < v2 ? -1 : 1;
  17091. } else {
  17092. return t1 < t2 ? -1 : 1;
  17093. }
  17094. }
  17095. }
  17096. }
  17097. function ngDirective(directive) {
  17098. if (isFunction(directive)) {
  17099. directive = {
  17100. link: directive
  17101. }
  17102. }
  17103. directive.restrict = directive.restrict || 'AC';
  17104. return valueFn(directive);
  17105. }
  17106. /**
  17107. * @ngdoc directive
  17108. * @name ng.directive:a
  17109. * @restrict E
  17110. *
  17111. * @description
  17112. * Modifies the default behavior of html A tag, so that the default action is prevented when href
  17113. * attribute is empty.
  17114. *
  17115. * The reasoning for this change is to allow easy creation of action links with `ngClick` directive
  17116. * without changing the location or causing page reloads, e.g.:
  17117. * `<a href="" ng-click="model.$save()">Save</a>`
  17118. */
  17119. var htmlAnchorDirective = valueFn({
  17120. restrict: 'E',
  17121. compile: function(element, attr) {
  17122. if (msie <= 8) {
  17123. // turn <a href ng-click="..">link</a> into a stylable link in IE
  17124. // but only if it doesn't have name attribute, in which case it's an anchor
  17125. if (!attr.href && !attr.name) {
  17126. attr.$set('href', '');
  17127. }
  17128. // add a comment node to anchors to workaround IE bug that causes element content to be reset
  17129. // to new attribute content if attribute is updated with value containing @ and element also
  17130. // contains value with @
  17131. // see issue #1949
  17132. element.append(document.createComment('IE fix'));
  17133. }
  17134. return function(scope, element) {
  17135. element.bind('click', function(event){
  17136. // if we have no href url, then don't navigate anywhere.
  17137. if (!element.attr('href')) {
  17138. event.preventDefault();
  17139. }
  17140. });
  17141. }
  17142. }
  17143. });
  17144. /**
  17145. * @ngdoc directive
  17146. * @name ng.directive:ngHref
  17147. * @restrict A
  17148. *
  17149. * @description
  17150. * Using Angular markup like {{hash}} in an href attribute makes
  17151. * the page open to a wrong URL, if the user clicks that link before
  17152. * angular has a chance to replace the {{hash}} with actual URL, the
  17153. * link will be broken and will most likely return a 404 error.
  17154. * The `ngHref` directive solves this problem.
  17155. *
  17156. * The buggy way to write it:
  17157. * <pre>
  17158. * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
  17159. * </pre>
  17160. *
  17161. * The correct way to write it:
  17162. * <pre>
  17163. * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
  17164. * </pre>
  17165. *
  17166. * @element A
  17167. * @param {template} ngHref any string which can contain `{{}}` markup.
  17168. *
  17169. * @example
  17170. * This example uses `link` variable inside `href` attribute:
  17171. <doc:example>
  17172. <doc:source>
  17173. <input ng-model="value" /><br />
  17174. <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
  17175. <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
  17176. <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
  17177. <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
  17178. <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
  17179. <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
  17180. </doc:source>
  17181. <doc:scenario>
  17182. it('should execute ng-click but not reload when href without value', function() {
  17183. element('#link-1').click();
  17184. expect(input('value').val()).toEqual('1');
  17185. expect(element('#link-1').attr('href')).toBe("");
  17186. });
  17187. it('should execute ng-click but not reload when href empty string', function() {
  17188. element('#link-2').click();
  17189. expect(input('value').val()).toEqual('2');
  17190. expect(element('#link-2').attr('href')).toBe("");
  17191. });
  17192. it('should execute ng-click and change url when ng-href specified', function() {
  17193. expect(element('#link-3').attr('href')).toBe("/123");
  17194. element('#link-3').click();
  17195. expect(browser().window().path()).toEqual('/123');
  17196. });
  17197. it('should execute ng-click but not reload when href empty string and name specified', function() {
  17198. element('#link-4').click();
  17199. expect(input('value').val()).toEqual('4');
  17200. expect(element('#link-4').attr('href')).toBe('');
  17201. });
  17202. it('should execute ng-click but not reload when no href but name specified', function() {
  17203. element('#link-5').click();
  17204. expect(input('value').val()).toEqual('5');
  17205. expect(element('#link-5').attr('href')).toBe(undefined);
  17206. });
  17207. it('should only change url when only ng-href', function() {
  17208. input('value').enter('6');
  17209. expect(element('#link-6').attr('href')).toBe('6');
  17210. element('#link-6').click();
  17211. expect(browser().location().url()).toEqual('/6');
  17212. });
  17213. </doc:scenario>
  17214. </doc:example>
  17215. */
  17216. /**
  17217. * @ngdoc directive
  17218. * @name ng.directive:ngSrc
  17219. * @restrict A
  17220. *
  17221. * @description
  17222. * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
  17223. * work right: The browser will fetch from the URL with the literal
  17224. * text `{{hash}}` until Angular replaces the expression inside
  17225. * `{{hash}}`. The `ngSrc` directive solves this problem.
  17226. *
  17227. * The buggy way to write it:
  17228. * <pre>
  17229. * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
  17230. * </pre>
  17231. *
  17232. * The correct way to write it:
  17233. * <pre>
  17234. * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
  17235. * </pre>
  17236. *
  17237. * @element IMG
  17238. * @param {template} ngSrc any string which can contain `{{}}` markup.
  17239. */
  17240. /**
  17241. * @ngdoc directive
  17242. * @name ng.directive:ngDisabled
  17243. * @restrict A
  17244. *
  17245. * @description
  17246. *
  17247. * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
  17248. * <pre>
  17249. * <div ng-init="scope = { isDisabled: false }">
  17250. * <button disabled="{{scope.isDisabled}}">Disabled</button>
  17251. * </div>
  17252. * </pre>
  17253. *
  17254. * The HTML specs do not require browsers to preserve the special attributes such as disabled.
  17255. * (The presence of them means true and absence means false)
  17256. * This prevents the angular compiler from correctly retrieving the binding expression.
  17257. * To solve this problem, we introduce the `ngDisabled` directive.
  17258. *
  17259. * @example
  17260. <doc:example>
  17261. <doc:source>
  17262. Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
  17263. <button ng-model="button" ng-disabled="checked">Button</button>
  17264. </doc:source>
  17265. <doc:scenario>
  17266. it('should toggle button', function() {
  17267. expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy();
  17268. input('checked').check();
  17269. expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy();
  17270. });
  17271. </doc:scenario>
  17272. </doc:example>
  17273. *
  17274. * @element INPUT
  17275. * @param {expression} ngDisabled Angular expression that will be evaluated.
  17276. */
  17277. /**
  17278. * @ngdoc directive
  17279. * @name ng.directive:ngChecked
  17280. * @restrict A
  17281. *
  17282. * @description
  17283. * The HTML specs do not require browsers to preserve the special attributes such as checked.
  17284. * (The presence of them means true and absence means false)
  17285. * This prevents the angular compiler from correctly retrieving the binding expression.
  17286. * To solve this problem, we introduce the `ngChecked` directive.
  17287. * @example
  17288. <doc:example>
  17289. <doc:source>
  17290. Check me to check both: <input type="checkbox" ng-model="master"><br/>
  17291. <input id="checkSlave" type="checkbox" ng-checked="master">
  17292. </doc:source>
  17293. <doc:scenario>
  17294. it('should check both checkBoxes', function() {
  17295. expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy();
  17296. input('master').check();
  17297. expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy();
  17298. });
  17299. </doc:scenario>
  17300. </doc:example>
  17301. *
  17302. * @element INPUT
  17303. * @param {expression} ngChecked Angular expression that will be evaluated.
  17304. */
  17305. /**
  17306. * @ngdoc directive
  17307. * @name ng.directive:ngMultiple
  17308. * @restrict A
  17309. *
  17310. * @description
  17311. * The HTML specs do not require browsers to preserve the special attributes such as multiple.
  17312. * (The presence of them means true and absence means false)
  17313. * This prevents the angular compiler from correctly retrieving the binding expression.
  17314. * To solve this problem, we introduce the `ngMultiple` directive.
  17315. *
  17316. * @example
  17317. <doc:example>
  17318. <doc:source>
  17319. Check me check multiple: <input type="checkbox" ng-model="checked"><br/>
  17320. <select id="select" ng-multiple="checked">
  17321. <option>Misko</option>
  17322. <option>Igor</option>
  17323. <option>Vojta</option>
  17324. <option>Di</option>
  17325. </select>
  17326. </doc:source>
  17327. <doc:scenario>
  17328. it('should toggle multiple', function() {
  17329. expect(element('.doc-example-live #select').prop('multiple')).toBeFalsy();
  17330. input('checked').check();
  17331. expect(element('.doc-example-live #select').prop('multiple')).toBeTruthy();
  17332. });
  17333. </doc:scenario>
  17334. </doc:example>
  17335. *
  17336. * @element SELECT
  17337. * @param {expression} ngMultiple Angular expression that will be evaluated.
  17338. */
  17339. /**
  17340. * @ngdoc directive
  17341. * @name ng.directive:ngReadonly
  17342. * @restrict A
  17343. *
  17344. * @description
  17345. * The HTML specs do not require browsers to preserve the special attributes such as readonly.
  17346. * (The presence of them means true and absence means false)
  17347. * This prevents the angular compiler from correctly retrieving the binding expression.
  17348. * To solve this problem, we introduce the `ngReadonly` directive.
  17349. * @example
  17350. <doc:example>
  17351. <doc:source>
  17352. Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
  17353. <input type="text" ng-readonly="checked" value="I'm Angular"/>
  17354. </doc:source>
  17355. <doc:scenario>
  17356. it('should toggle readonly attr', function() {
  17357. expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy();
  17358. input('checked').check();
  17359. expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy();
  17360. });
  17361. </doc:scenario>
  17362. </doc:example>
  17363. *
  17364. * @element INPUT
  17365. * @param {string} expression Angular expression that will be evaluated.
  17366. */
  17367. /**
  17368. * @ngdoc directive
  17369. * @name ng.directive:ngSelected
  17370. * @restrict A
  17371. *
  17372. * @description
  17373. * The HTML specs do not require browsers to preserve the special attributes such as selected.
  17374. * (The presence of them means true and absence means false)
  17375. * This prevents the angular compiler from correctly retrieving the binding expression.
  17376. * To solve this problem, we introduced the `ngSelected` directive.
  17377. * @example
  17378. <doc:example>
  17379. <doc:source>
  17380. Check me to select: <input type="checkbox" ng-model="selected"><br/>
  17381. <select>
  17382. <option>Hello!</option>
  17383. <option id="greet" ng-selected="selected">Greetings!</option>
  17384. </select>
  17385. </doc:source>
  17386. <doc:scenario>
  17387. it('should select Greetings!', function() {
  17388. expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
  17389. input('selected').check();
  17390. expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
  17391. });
  17392. </doc:scenario>
  17393. </doc:example>
  17394. *
  17395. * @element OPTION
  17396. * @param {string} expression Angular expression that will be evaluated.
  17397. */
  17398. var ngAttributeAliasDirectives = {};
  17399. // boolean attrs are evaluated
  17400. forEach(BOOLEAN_ATTR, function(propName, attrName) {
  17401. var normalized = directiveNormalize('ng-' + attrName);
  17402. ngAttributeAliasDirectives[normalized] = function() {
  17403. return {
  17404. priority: 100,
  17405. compile: function() {
  17406. return function(scope, element, attr) {
  17407. scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
  17408. attr.$set(attrName, !!value);
  17409. });
  17410. };
  17411. }
  17412. };
  17413. };
  17414. });
  17415. // ng-src, ng-href are interpolated
  17416. forEach(['src', 'href'], function(attrName) {
  17417. var normalized = directiveNormalize('ng-' + attrName);
  17418. ngAttributeAliasDirectives[normalized] = function() {
  17419. return {
  17420. priority: 99, // it needs to run after the attributes are interpolated
  17421. link: function(scope, element, attr) {
  17422. attr.$observe(normalized, function(value) {
  17423. if (!value)
  17424. return;
  17425. attr.$set(attrName, value);
  17426. // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
  17427. // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
  17428. // to set the property as well to achieve the desired effect.
  17429. // we use attr[attrName] value since $set can sanitize the url.
  17430. if (msie) element.prop(attrName, attr[attrName]);
  17431. });
  17432. }
  17433. };
  17434. };
  17435. });
  17436. var nullFormCtrl = {
  17437. $addControl: noop,
  17438. $removeControl: noop,
  17439. $setValidity: noop,
  17440. $setDirty: noop
  17441. };
  17442. /**
  17443. * @ngdoc object
  17444. * @name ng.directive:form.FormController
  17445. *
  17446. * @property {boolean} $pristine True if user has not interacted with the form yet.
  17447. * @property {boolean} $dirty True if user has already interacted with the form.
  17448. * @property {boolean} $valid True if all of the containing forms and controls are valid.
  17449. * @property {boolean} $invalid True if at least one containing control or form is invalid.
  17450. *
  17451. * @property {Object} $error Is an object hash, containing references to all invalid controls or
  17452. * forms, where:
  17453. *
  17454. * - keys are validation tokens (error names) — such as `required`, `url` or `email`),
  17455. * - values are arrays of controls or forms that are invalid with given error.
  17456. *
  17457. * @description
  17458. * `FormController` keeps track of all its controls and nested forms as well as state of them,
  17459. * such as being valid/invalid or dirty/pristine.
  17460. *
  17461. * Each {@link ng.directive:form form} directive creates an instance
  17462. * of `FormController`.
  17463. *
  17464. */
  17465. //asks for $scope to fool the BC controller module
  17466. FormController.$inject = ['$element', '$attrs', '$scope'];
  17467. function FormController(element, attrs) {
  17468. var form = this,
  17469. parentForm = element.parent().controller('form') || nullFormCtrl,
  17470. invalidCount = 0, // used to easily determine if we are valid
  17471. errors = form.$error = {};
  17472. // init state
  17473. form.$name = attrs.name;
  17474. form.$dirty = false;
  17475. form.$pristine = true;
  17476. form.$valid = true;
  17477. form.$invalid = false;
  17478. parentForm.$addControl(form);
  17479. // Setup initial state of the control
  17480. element.addClass(PRISTINE_CLASS);
  17481. toggleValidCss(true);
  17482. // convenience method for easy toggling of classes
  17483. function toggleValidCss(isValid, validationErrorKey) {
  17484. validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
  17485. element.
  17486. removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
  17487. addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
  17488. }
  17489. form.$addControl = function(control) {
  17490. if (control.$name && !form.hasOwnProperty(control.$name)) {
  17491. form[control.$name] = control;
  17492. }
  17493. };
  17494. form.$removeControl = function(control) {
  17495. if (control.$name && form[control.$name] === control) {
  17496. delete form[control.$name];
  17497. }
  17498. forEach(errors, function(queue, validationToken) {
  17499. form.$setValidity(validationToken, true, control);
  17500. });
  17501. };
  17502. form.$setValidity = function(validationToken, isValid, control) {
  17503. var queue = errors[validationToken];
  17504. if (isValid) {
  17505. if (queue) {
  17506. arrayRemove(queue, control);
  17507. if (!queue.length) {
  17508. invalidCount--;
  17509. if (!invalidCount) {
  17510. toggleValidCss(isValid);
  17511. form.$valid = true;
  17512. form.$invalid = false;
  17513. }
  17514. errors[validationToken] = false;
  17515. toggleValidCss(true, validationToken);
  17516. parentForm.$setValidity(validationToken, true, form);
  17517. }
  17518. }
  17519. } else {
  17520. if (!invalidCount) {
  17521. toggleValidCss(isValid);
  17522. }
  17523. if (queue) {
  17524. if (includes(queue, control)) return;
  17525. } else {
  17526. errors[validationToken] = queue = [];
  17527. invalidCount++;
  17528. toggleValidCss(false, validationToken);
  17529. parentForm.$setValidity(validationToken, false, form);
  17530. }
  17531. queue.push(control);
  17532. form.$valid = false;
  17533. form.$invalid = true;
  17534. }
  17535. };
  17536. form.$setDirty = function() {
  17537. element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
  17538. form.$dirty = true;
  17539. form.$pristine = false;
  17540. parentForm.$setDirty();
  17541. };
  17542. }
  17543. /**
  17544. * @ngdoc directive
  17545. * @name ng.directive:ngForm
  17546. * @restrict EAC
  17547. *
  17548. * @description
  17549. * Nestable alias of {@link ng.directive:form `form`} directive. HTML
  17550. * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
  17551. * sub-group of controls needs to be determined.
  17552. *
  17553. * @param {string=} name|ngForm Name of the form. If specified, the form controller will be published into
  17554. * related scope, under this name.
  17555. *
  17556. */
  17557. /**
  17558. * @ngdoc directive
  17559. * @name ng.directive:form
  17560. * @restrict E
  17561. *
  17562. * @description
  17563. * Directive that instantiates
  17564. * {@link ng.directive:form.FormController FormController}.
  17565. *
  17566. * If `name` attribute is specified, the form controller is published onto the current scope under
  17567. * this name.
  17568. *
  17569. * # Alias: {@link ng.directive:ngForm `ngForm`}
  17570. *
  17571. * In angular forms can be nested. This means that the outer form is valid when all of the child
  17572. * forms are valid as well. However browsers do not allow nesting of `<form>` elements, for this
  17573. * reason angular provides {@link ng.directive:ngForm `ngForm`} alias
  17574. * which behaves identical to `<form>` but allows form nesting.
  17575. *
  17576. *
  17577. * # CSS classes
  17578. * - `ng-valid` Is set if the form is valid.
  17579. * - `ng-invalid` Is set if the form is invalid.
  17580. * - `ng-pristine` Is set if the form is pristine.
  17581. * - `ng-dirty` Is set if the form is dirty.
  17582. *
  17583. *
  17584. * # Submitting a form and preventing default action
  17585. *
  17586. * Since the role of forms in client-side Angular applications is different than in classical
  17587. * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
  17588. * page reload that sends the data to the server. Instead some javascript logic should be triggered
  17589. * to handle the form submission in application specific way.
  17590. *
  17591. * For this reason, Angular prevents the default action (form submission to the server) unless the
  17592. * `<form>` element has an `action` attribute specified.
  17593. *
  17594. * You can use one of the following two ways to specify what javascript method should be called when
  17595. * a form is submitted:
  17596. *
  17597. * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
  17598. * - {@link ng.directive:ngClick ngClick} directive on the first
  17599. * button or input field of type submit (input[type=submit])
  17600. *
  17601. * To prevent double execution of the handler, use only one of ngSubmit or ngClick directives. This
  17602. * is because of the following form submission rules coming from the html spec:
  17603. *
  17604. * - If a form has only one input field then hitting enter in this field triggers form submit
  17605. * (`ngSubmit`)
  17606. * - if a form has has 2+ input fields and no buttons or input[type=submit] then hitting enter
  17607. * doesn't trigger submit
  17608. * - if a form has one or more input fields and one or more buttons or input[type=submit] then
  17609. * hitting enter in any of the input fields will trigger the click handler on the *first* button or
  17610. * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
  17611. *
  17612. * @param {string=} name Name of the form. If specified, the form controller will be published into
  17613. * related scope, under this name.
  17614. *
  17615. * @example
  17616. <doc:example>
  17617. <doc:source>
  17618. <script>
  17619. function Ctrl($scope) {
  17620. $scope.userType = 'guest';
  17621. }
  17622. </script>
  17623. <form name="myForm" ng-controller="Ctrl">
  17624. userType: <input name="input" ng-model="userType" required>
  17625. <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
  17626. <tt>userType = {{userType}}</tt><br>
  17627. <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
  17628. <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
  17629. <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
  17630. <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
  17631. </form>
  17632. </doc:source>
  17633. <doc:scenario>
  17634. it('should initialize to model', function() {
  17635. expect(binding('userType')).toEqual('guest');
  17636. expect(binding('myForm.input.$valid')).toEqual('true');
  17637. });
  17638. it('should be invalid if empty', function() {
  17639. input('userType').enter('');
  17640. expect(binding('userType')).toEqual('');
  17641. expect(binding('myForm.input.$valid')).toEqual('false');
  17642. });
  17643. </doc:scenario>
  17644. </doc:example>
  17645. */
  17646. var formDirectiveFactory = function(isNgForm) {
  17647. return ['$timeout', function($timeout) {
  17648. var formDirective = {
  17649. name: 'form',
  17650. restrict: 'E',
  17651. controller: FormController,
  17652. compile: function() {
  17653. return {
  17654. pre: function(scope, formElement, attr, controller) {
  17655. if (!attr.action) {
  17656. // we can't use jq events because if a form is destroyed during submission the default
  17657. // action is not prevented. see #1238
  17658. //
  17659. // IE 9 is not affected because it doesn't fire a submit event and try to do a full
  17660. // page reload if the form was destroyed by submission of the form via a click handler
  17661. // on a button in the form. Looks like an IE9 specific bug.
  17662. var preventDefaultListener = function(event) {
  17663. event.preventDefault
  17664. ? event.preventDefault()
  17665. : event.returnValue = false; // IE
  17666. };
  17667. addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
  17668. // unregister the preventDefault listener so that we don't not leak memory but in a
  17669. // way that will achieve the prevention of the default action.
  17670. formElement.bind('$destroy', function() {
  17671. $timeout(function() {
  17672. removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
  17673. }, 0, false);
  17674. });
  17675. }
  17676. var parentFormCtrl = formElement.parent().controller('form'),
  17677. alias = attr.name || attr.ngForm;
  17678. if (alias) {
  17679. scope[alias] = controller;
  17680. }
  17681. if (parentFormCtrl) {
  17682. formElement.bind('$destroy', function() {
  17683. parentFormCtrl.$removeControl(controller);
  17684. if (alias) {
  17685. scope[alias] = undefined;
  17686. }
  17687. extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
  17688. });
  17689. }
  17690. }
  17691. };
  17692. }
  17693. };
  17694. return isNgForm ? extend(copy(formDirective), {restrict: 'EAC'}) : formDirective;
  17695. }];
  17696. };
  17697. var formDirective = formDirectiveFactory();
  17698. var ngFormDirective = formDirectiveFactory(true);
  17699. var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
  17700. var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/;
  17701. var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
  17702. var inputType = {
  17703. /**
  17704. * @ngdoc inputType
  17705. * @name ng.directive:input.text
  17706. *
  17707. * @description
  17708. * Standard HTML text input with angular data binding.
  17709. *
  17710. * @param {string} ngModel Assignable angular expression to data-bind to.
  17711. * @param {string=} name Property name of the form under which the control is published.
  17712. * @param {string=} required Adds `required` validation error key if the value is not entered.
  17713. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
  17714. * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
  17715. * `required` when you want to data-bind to the `required` attribute.
  17716. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
  17717. * minlength.
  17718. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
  17719. * maxlength.
  17720. * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
  17721. * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
  17722. * patterns defined as scope expressions.
  17723. * @param {string=} ngChange Angular expression to be executed when input changes due to user
  17724. * interaction with the input element.
  17725. *
  17726. * @example
  17727. <doc:example>
  17728. <doc:source>
  17729. <script>
  17730. function Ctrl($scope) {
  17731. $scope.text = 'guest';
  17732. $scope.word = /^\w*$/;
  17733. }
  17734. </script>
  17735. <form name="myForm" ng-controller="Ctrl">
  17736. Single word: <input type="text" name="input" ng-model="text"
  17737. ng-pattern="word" required>
  17738. <span class="error" ng-show="myForm.input.$error.required">
  17739. Required!</span>
  17740. <span class="error" ng-show="myForm.input.$error.pattern">
  17741. Single word only!</span>
  17742. <tt>text = {{text}}</tt><br/>
  17743. <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
  17744. <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
  17745. <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
  17746. <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
  17747. </form>
  17748. </doc:source>
  17749. <doc:scenario>
  17750. it('should initialize to model', function() {
  17751. expect(binding('text')).toEqual('guest');
  17752. expect(binding('myForm.input.$valid')).toEqual('true');
  17753. });
  17754. it('should be invalid if empty', function() {
  17755. input('text').enter('');
  17756. expect(binding('text')).toEqual('');
  17757. expect(binding('myForm.input.$valid')).toEqual('false');
  17758. });
  17759. it('should be invalid if multi word', function() {
  17760. input('text').enter('hello world');
  17761. expect(binding('myForm.input.$valid')).toEqual('false');
  17762. });
  17763. </doc:scenario>
  17764. </doc:example>
  17765. */
  17766. 'text': textInputType,
  17767. /**
  17768. * @ngdoc inputType
  17769. * @name ng.directive:input.number
  17770. *
  17771. * @description
  17772. * Text input with number validation and transformation. Sets the `number` validation
  17773. * error if not a valid number.
  17774. *
  17775. * @param {string} ngModel Assignable angular expression to data-bind to.
  17776. * @param {string=} name Property name of the form under which the control is published.
  17777. * @param {string=} min Sets the `min` validation error key if the value entered is less then `min`.
  17778. * @param {string=} max Sets the `max` validation error key if the value entered is greater then `min`.
  17779. * @param {string=} required Sets `required` validation error key if the value is not entered.
  17780. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
  17781. * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
  17782. * `required` when you want to data-bind to the `required` attribute.
  17783. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
  17784. * minlength.
  17785. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
  17786. * maxlength.
  17787. * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
  17788. * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
  17789. * patterns defined as scope expressions.
  17790. * @param {string=} ngChange Angular expression to be executed when input changes due to user
  17791. * interaction with the input element.
  17792. *
  17793. * @example
  17794. <doc:example>
  17795. <doc:source>
  17796. <script>
  17797. function Ctrl($scope) {
  17798. $scope.value = 12;
  17799. }
  17800. </script>
  17801. <form name="myForm" ng-controller="Ctrl">
  17802. Number: <input type="number" name="input" ng-model="value"
  17803. min="0" max="99" required>
  17804. <span class="error" ng-show="myForm.list.$error.required">
  17805. Required!</span>
  17806. <span class="error" ng-show="myForm.list.$error.number">
  17807. Not valid number!</span>
  17808. <tt>value = {{value}}</tt><br/>
  17809. <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
  17810. <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
  17811. <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
  17812. <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
  17813. </form>
  17814. </doc:source>
  17815. <doc:scenario>
  17816. it('should initialize to model', function() {
  17817. expect(binding('value')).toEqual('12');
  17818. expect(binding('myForm.input.$valid')).toEqual('true');
  17819. });
  17820. it('should be invalid if empty', function() {
  17821. input('value').enter('');
  17822. expect(binding('value')).toEqual('');
  17823. expect(binding('myForm.input.$valid')).toEqual('false');
  17824. });
  17825. it('should be invalid if over max', function() {
  17826. input('value').enter('123');
  17827. expect(binding('value')).toEqual('');
  17828. expect(binding('myForm.input.$valid')).toEqual('false');
  17829. });
  17830. </doc:scenario>
  17831. </doc:example>
  17832. */
  17833. 'number': numberInputType,
  17834. /**
  17835. * @ngdoc inputType
  17836. * @name ng.directive:input.url
  17837. *
  17838. * @description
  17839. * Text input with URL validation. Sets the `url` validation error key if the content is not a
  17840. * valid URL.
  17841. *
  17842. * @param {string} ngModel Assignable angular expression to data-bind to.
  17843. * @param {string=} name Property name of the form under which the control is published.
  17844. * @param {string=} required Sets `required` validation error key if the value is not entered.
  17845. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
  17846. * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
  17847. * `required` when you want to data-bind to the `required` attribute.
  17848. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
  17849. * minlength.
  17850. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
  17851. * maxlength.
  17852. * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
  17853. * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
  17854. * patterns defined as scope expressions.
  17855. * @param {string=} ngChange Angular expression to be executed when input changes due to user
  17856. * interaction with the input element.
  17857. *
  17858. * @example
  17859. <doc:example>
  17860. <doc:source>
  17861. <script>
  17862. function Ctrl($scope) {
  17863. $scope.text = 'http://google.com';
  17864. }
  17865. </script>
  17866. <form name="myForm" ng-controller="Ctrl">
  17867. URL: <input type="url" name="input" ng-model="text" required>
  17868. <span class="error" ng-show="myForm.input.$error.required">
  17869. Required!</span>
  17870. <span class="error" ng-show="myForm.input.$error.url">
  17871. Not valid url!</span>
  17872. <tt>text = {{text}}</tt><br/>
  17873. <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
  17874. <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
  17875. <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
  17876. <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
  17877. <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
  17878. </form>
  17879. </doc:source>
  17880. <doc:scenario>
  17881. it('should initialize to model', function() {
  17882. expect(binding('text')).toEqual('http://google.com');
  17883. expect(binding('myForm.input.$valid')).toEqual('true');
  17884. });
  17885. it('should be invalid if empty', function() {
  17886. input('text').enter('');
  17887. expect(binding('text')).toEqual('');
  17888. expect(binding('myForm.input.$valid')).toEqual('false');
  17889. });
  17890. it('should be invalid if not url', function() {
  17891. input('text').enter('xxx');
  17892. expect(binding('myForm.input.$valid')).toEqual('false');
  17893. });
  17894. </doc:scenario>
  17895. </doc:example>
  17896. */
  17897. 'url': urlInputType,
  17898. /**
  17899. * @ngdoc inputType
  17900. * @name ng.directive:input.email
  17901. *
  17902. * @description
  17903. * Text input with email validation. Sets the `email` validation error key if not a valid email
  17904. * address.
  17905. *
  17906. * @param {string} ngModel Assignable angular expression to data-bind to.
  17907. * @param {string=} name Property name of the form under which the control is published.
  17908. * @param {string=} required Sets `required` validation error key if the value is not entered.
  17909. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
  17910. * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
  17911. * `required` when you want to data-bind to the `required` attribute.
  17912. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
  17913. * minlength.
  17914. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
  17915. * maxlength.
  17916. * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
  17917. * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
  17918. * patterns defined as scope expressions.
  17919. *
  17920. * @example
  17921. <doc:example>
  17922. <doc:source>
  17923. <script>
  17924. function Ctrl($scope) {
  17925. $scope.text = 'me@example.com';
  17926. }
  17927. </script>
  17928. <form name="myForm" ng-controller="Ctrl">
  17929. Email: <input type="email" name="input" ng-model="text" required>
  17930. <span class="error" ng-show="myForm.input.$error.required">
  17931. Required!</span>
  17932. <span class="error" ng-show="myForm.input.$error.email">
  17933. Not valid email!</span>
  17934. <tt>text = {{text}}</tt><br/>
  17935. <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
  17936. <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
  17937. <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
  17938. <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
  17939. <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
  17940. </form>
  17941. </doc:source>
  17942. <doc:scenario>
  17943. it('should initialize to model', function() {
  17944. expect(binding('text')).toEqual('me@example.com');
  17945. expect(binding('myForm.input.$valid')).toEqual('true');
  17946. });
  17947. it('should be invalid if empty', function() {
  17948. input('text').enter('');
  17949. expect(binding('text')).toEqual('');
  17950. expect(binding('myForm.input.$valid')).toEqual('false');
  17951. });
  17952. it('should be invalid if not email', function() {
  17953. input('text').enter('xxx');
  17954. expect(binding('myForm.input.$valid')).toEqual('false');
  17955. });
  17956. </doc:scenario>
  17957. </doc:example>
  17958. */
  17959. 'email': emailInputType,
  17960. /**
  17961. * @ngdoc inputType
  17962. * @name ng.directive:input.radio
  17963. *
  17964. * @description
  17965. * HTML radio button.
  17966. *
  17967. * @param {string} ngModel Assignable angular expression to data-bind to.
  17968. * @param {string} value The value to which the expression should be set when selected.
  17969. * @param {string=} name Property name of the form under which the control is published.
  17970. * @param {string=} ngChange Angular expression to be executed when input changes due to user
  17971. * interaction with the input element.
  17972. *
  17973. * @example
  17974. <doc:example>
  17975. <doc:source>
  17976. <script>
  17977. function Ctrl($scope) {
  17978. $scope.color = 'blue';
  17979. }
  17980. </script>
  17981. <form name="myForm" ng-controller="Ctrl">
  17982. <input type="radio" ng-model="color" value="red"> Red <br/>
  17983. <input type="radio" ng-model="color" value="green"> Green <br/>
  17984. <input type="radio" ng-model="color" value="blue"> Blue <br/>
  17985. <tt>color = {{color}}</tt><br/>
  17986. </form>
  17987. </doc:source>
  17988. <doc:scenario>
  17989. it('should change state', function() {
  17990. expect(binding('color')).toEqual('blue');
  17991. input('color').select('red');
  17992. expect(binding('color')).toEqual('red');
  17993. });
  17994. </doc:scenario>
  17995. </doc:example>
  17996. */
  17997. 'radio': radioInputType,
  17998. /**
  17999. * @ngdoc inputType
  18000. * @name ng.directive:input.checkbox
  18001. *
  18002. * @description
  18003. * HTML checkbox.
  18004. *
  18005. * @param {string} ngModel Assignable angular expression to data-bind to.
  18006. * @param {string=} name Property name of the form under which the control is published.
  18007. * @param {string=} ngTrueValue The value to which the expression should be set when selected.
  18008. * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
  18009. * @param {string=} ngChange Angular expression to be executed when input changes due to user
  18010. * interaction with the input element.
  18011. *
  18012. * @example
  18013. <doc:example>
  18014. <doc:source>
  18015. <script>
  18016. function Ctrl($scope) {
  18017. $scope.value1 = true;
  18018. $scope.value2 = 'YES'
  18019. }
  18020. </script>
  18021. <form name="myForm" ng-controller="Ctrl">
  18022. Value1: <input type="checkbox" ng-model="value1"> <br/>
  18023. Value2: <input type="checkbox" ng-model="value2"
  18024. ng-true-value="YES" ng-false-value="NO"> <br/>
  18025. <tt>value1 = {{value1}}</tt><br/>
  18026. <tt>value2 = {{value2}}</tt><br/>
  18027. </form>
  18028. </doc:source>
  18029. <doc:scenario>
  18030. it('should change state', function() {
  18031. expect(binding('value1')).toEqual('true');
  18032. expect(binding('value2')).toEqual('YES');
  18033. input('value1').check();
  18034. input('value2').check();
  18035. expect(binding('value1')).toEqual('false');
  18036. expect(binding('value2')).toEqual('NO');
  18037. });
  18038. </doc:scenario>
  18039. </doc:example>
  18040. */
  18041. 'checkbox': checkboxInputType,
  18042. 'hidden': noop,
  18043. 'button': noop,
  18044. 'submit': noop,
  18045. 'reset': noop
  18046. };
  18047. function isEmpty(value) {
  18048. return isUndefined(value) || value === '' || value === null || value !== value;
  18049. }
  18050. function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  18051. var listener = function() {
  18052. var value = trim(element.val());
  18053. if (ctrl.$viewValue !== value) {
  18054. scope.$apply(function() {
  18055. ctrl.$setViewValue(value);
  18056. });
  18057. }
  18058. };
  18059. // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
  18060. // input event on backspace, delete or cut
  18061. if ($sniffer.hasEvent('input')) {
  18062. element.bind('input', listener);
  18063. } else {
  18064. var timeout;
  18065. element.bind('keydown', function(event) {
  18066. var key = event.keyCode;
  18067. // ignore
  18068. // command modifiers arrows
  18069. if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
  18070. if (!timeout) {
  18071. timeout = $browser.defer(function() {
  18072. listener();
  18073. timeout = null;
  18074. });
  18075. }
  18076. });
  18077. // if user paste into input using mouse, we need "change" event to catch it
  18078. element.bind('change', listener);
  18079. }
  18080. ctrl.$render = function() {
  18081. element.val(isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
  18082. };
  18083. // pattern validator
  18084. var pattern = attr.ngPattern,
  18085. patternValidator;
  18086. var validate = function(regexp, value) {
  18087. if (isEmpty(value) || regexp.test(value)) {
  18088. ctrl.$setValidity('pattern', true);
  18089. return value;
  18090. } else {
  18091. ctrl.$setValidity('pattern', false);
  18092. return undefined;
  18093. }
  18094. };
  18095. if (pattern) {
  18096. if (pattern.match(/^\/(.*)\/$/)) {
  18097. pattern = new RegExp(pattern.substr(1, pattern.length - 2));
  18098. patternValidator = function(value) {
  18099. return validate(pattern, value)
  18100. };
  18101. } else {
  18102. patternValidator = function(value) {
  18103. var patternObj = scope.$eval(pattern);
  18104. if (!patternObj || !patternObj.test) {
  18105. throw new Error('Expected ' + pattern + ' to be a RegExp but was ' + patternObj);
  18106. }
  18107. return validate(patternObj, value);
  18108. };
  18109. }
  18110. ctrl.$formatters.push(patternValidator);
  18111. ctrl.$parsers.push(patternValidator);
  18112. }
  18113. // min length validator
  18114. if (attr.ngMinlength) {
  18115. var minlength = int(attr.ngMinlength);
  18116. var minLengthValidator = function(value) {
  18117. if (!isEmpty(value) && value.length < minlength) {
  18118. ctrl.$setValidity('minlength', false);
  18119. return undefined;
  18120. } else {
  18121. ctrl.$setValidity('minlength', true);
  18122. return value;
  18123. }
  18124. };
  18125. ctrl.$parsers.push(minLengthValidator);
  18126. ctrl.$formatters.push(minLengthValidator);
  18127. }
  18128. // max length validator
  18129. if (attr.ngMaxlength) {
  18130. var maxlength = int(attr.ngMaxlength);
  18131. var maxLengthValidator = function(value) {
  18132. if (!isEmpty(value) && value.length > maxlength) {
  18133. ctrl.$setValidity('maxlength', false);
  18134. return undefined;
  18135. } else {
  18136. ctrl.$setValidity('maxlength', true);
  18137. return value;
  18138. }
  18139. };
  18140. ctrl.$parsers.push(maxLengthValidator);
  18141. ctrl.$formatters.push(maxLengthValidator);
  18142. }
  18143. }
  18144. function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  18145. textInputType(scope, element, attr, ctrl, $sniffer, $browser);
  18146. ctrl.$parsers.push(function(value) {
  18147. var empty = isEmpty(value);
  18148. if (empty || NUMBER_REGEXP.test(value)) {
  18149. ctrl.$setValidity('number', true);
  18150. return value === '' ? null : (empty ? value : parseFloat(value));
  18151. } else {
  18152. ctrl.$setValidity('number', false);
  18153. return undefined;
  18154. }
  18155. });
  18156. ctrl.$formatters.push(function(value) {
  18157. return isEmpty(value) ? '' : '' + value;
  18158. });
  18159. if (attr.min) {
  18160. var min = parseFloat(attr.min);
  18161. var minValidator = function(value) {
  18162. if (!isEmpty(value) && value < min) {
  18163. ctrl.$setValidity('min', false);
  18164. return undefined;
  18165. } else {
  18166. ctrl.$setValidity('min', true);
  18167. return value;
  18168. }
  18169. };
  18170. ctrl.$parsers.push(minValidator);
  18171. ctrl.$formatters.push(minValidator);
  18172. }
  18173. if (attr.max) {
  18174. var max = parseFloat(attr.max);
  18175. var maxValidator = function(value) {
  18176. if (!isEmpty(value) && value > max) {
  18177. ctrl.$setValidity('max', false);
  18178. return undefined;
  18179. } else {
  18180. ctrl.$setValidity('max', true);
  18181. return value;
  18182. }
  18183. };
  18184. ctrl.$parsers.push(maxValidator);
  18185. ctrl.$formatters.push(maxValidator);
  18186. }
  18187. ctrl.$formatters.push(function(value) {
  18188. if (isEmpty(value) || isNumber(value)) {
  18189. ctrl.$setValidity('number', true);
  18190. return value;
  18191. } else {
  18192. ctrl.$setValidity('number', false);
  18193. return undefined;
  18194. }
  18195. });
  18196. }
  18197. function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  18198. textInputType(scope, element, attr, ctrl, $sniffer, $browser);
  18199. var urlValidator = function(value) {
  18200. if (isEmpty(value) || URL_REGEXP.test(value)) {
  18201. ctrl.$setValidity('url', true);
  18202. return value;
  18203. } else {
  18204. ctrl.$setValidity('url', false);
  18205. return undefined;
  18206. }
  18207. };
  18208. ctrl.$formatters.push(urlValidator);
  18209. ctrl.$parsers.push(urlValidator);
  18210. }
  18211. function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  18212. textInputType(scope, element, attr, ctrl, $sniffer, $browser);
  18213. var emailValidator = function(value) {
  18214. if (isEmpty(value) || EMAIL_REGEXP.test(value)) {
  18215. ctrl.$setValidity('email', true);
  18216. return value;
  18217. } else {
  18218. ctrl.$setValidity('email', false);
  18219. return undefined;
  18220. }
  18221. };
  18222. ctrl.$formatters.push(emailValidator);
  18223. ctrl.$parsers.push(emailValidator);
  18224. }
  18225. function radioInputType(scope, element, attr, ctrl) {
  18226. // make the name unique, if not defined
  18227. if (isUndefined(attr.name)) {
  18228. element.attr('name', nextUid());
  18229. }
  18230. element.bind('click', function() {
  18231. if (element[0].checked) {
  18232. scope.$apply(function() {
  18233. ctrl.$setViewValue(attr.value);
  18234. });
  18235. }
  18236. });
  18237. ctrl.$render = function() {
  18238. var value = attr.value;
  18239. element[0].checked = (value == ctrl.$viewValue);
  18240. };
  18241. attr.$observe('value', ctrl.$render);
  18242. }
  18243. function checkboxInputType(scope, element, attr, ctrl) {
  18244. var trueValue = attr.ngTrueValue,
  18245. falseValue = attr.ngFalseValue;
  18246. if (!isString(trueValue)) trueValue = true;
  18247. if (!isString(falseValue)) falseValue = false;
  18248. element.bind('click', function() {
  18249. scope.$apply(function() {
  18250. ctrl.$setViewValue(element[0].checked);
  18251. });
  18252. });
  18253. ctrl.$render = function() {
  18254. element[0].checked = ctrl.$viewValue;
  18255. };
  18256. ctrl.$formatters.push(function(value) {
  18257. return value === trueValue;
  18258. });
  18259. ctrl.$parsers.push(function(value) {
  18260. return value ? trueValue : falseValue;
  18261. });
  18262. }
  18263. /**
  18264. * @ngdoc directive
  18265. * @name ng.directive:textarea
  18266. * @restrict E
  18267. *
  18268. * @description
  18269. * HTML textarea element control with angular data-binding. The data-binding and validation
  18270. * properties of this element are exactly the same as those of the
  18271. * {@link ng.directive:input input element}.
  18272. *
  18273. * @param {string} ngModel Assignable angular expression to data-bind to.
  18274. * @param {string=} name Property name of the form under which the control is published.
  18275. * @param {string=} required Sets `required` validation error key if the value is not entered.
  18276. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
  18277. * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
  18278. * `required` when you want to data-bind to the `required` attribute.
  18279. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
  18280. * minlength.
  18281. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
  18282. * maxlength.
  18283. * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
  18284. * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
  18285. * patterns defined as scope expressions.
  18286. * @param {string=} ngChange Angular expression to be executed when input changes due to user
  18287. * interaction with the input element.
  18288. */
  18289. /**
  18290. * @ngdoc directive
  18291. * @name ng.directive:input
  18292. * @restrict E
  18293. *
  18294. * @description
  18295. * HTML input element control with angular data-binding. Input control follows HTML5 input types
  18296. * and polyfills the HTML5 validation behavior for older browsers.
  18297. *
  18298. * @param {string} ngModel Assignable angular expression to data-bind to.
  18299. * @param {string=} name Property name of the form under which the control is published.
  18300. * @param {string=} required Sets `required` validation error key if the value is not entered.
  18301. * @param {boolean=} ngRequired Sets `required` attribute if set to true
  18302. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
  18303. * minlength.
  18304. * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
  18305. * maxlength.
  18306. * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
  18307. * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
  18308. * patterns defined as scope expressions.
  18309. * @param {string=} ngChange Angular expression to be executed when input changes due to user
  18310. * interaction with the input element.
  18311. *
  18312. * @example
  18313. <doc:example>
  18314. <doc:source>
  18315. <script>
  18316. function Ctrl($scope) {
  18317. $scope.user = {name: 'guest', last: 'visitor'};
  18318. }
  18319. </script>
  18320. <div ng-controller="Ctrl">
  18321. <form name="myForm">
  18322. User name: <input type="text" name="userName" ng-model="user.name" required>
  18323. <span class="error" ng-show="myForm.userName.$error.required">
  18324. Required!</span><br>
  18325. Last name: <input type="text" name="lastName" ng-model="user.last"
  18326. ng-minlength="3" ng-maxlength="10">
  18327. <span class="error" ng-show="myForm.lastName.$error.minlength">
  18328. Too short!</span>
  18329. <span class="error" ng-show="myForm.lastName.$error.maxlength">
  18330. Too long!</span><br>
  18331. </form>
  18332. <hr>
  18333. <tt>user = {{user}}</tt><br/>
  18334. <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
  18335. <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
  18336. <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
  18337. <tt>myForm.userName.$error = {{myForm.lastName.$error}}</tt><br>
  18338. <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
  18339. <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
  18340. <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
  18341. <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
  18342. </div>
  18343. </doc:source>
  18344. <doc:scenario>
  18345. it('should initialize to model', function() {
  18346. expect(binding('user')).toEqual('{"name":"guest","last":"visitor"}');
  18347. expect(binding('myForm.userName.$valid')).toEqual('true');
  18348. expect(binding('myForm.$valid')).toEqual('true');
  18349. });
  18350. it('should be invalid if empty when required', function() {
  18351. input('user.name').enter('');
  18352. expect(binding('user')).toEqual('{"last":"visitor"}');
  18353. expect(binding('myForm.userName.$valid')).toEqual('false');
  18354. expect(binding('myForm.$valid')).toEqual('false');
  18355. });
  18356. it('should be valid if empty when min length is set', function() {
  18357. input('user.last').enter('');
  18358. expect(binding('user')).toEqual('{"name":"guest","last":""}');
  18359. expect(binding('myForm.lastName.$valid')).toEqual('true');
  18360. expect(binding('myForm.$valid')).toEqual('true');
  18361. });
  18362. it('should be invalid if less than required min length', function() {
  18363. input('user.last').enter('xx');
  18364. expect(binding('user')).toEqual('{"name":"guest"}');
  18365. expect(binding('myForm.lastName.$valid')).toEqual('false');
  18366. expect(binding('myForm.lastName.$error')).toMatch(/minlength/);
  18367. expect(binding('myForm.$valid')).toEqual('false');
  18368. });
  18369. it('should be invalid if longer than max length', function() {
  18370. input('user.last').enter('some ridiculously long name');
  18371. expect(binding('user'))
  18372. .toEqual('{"name":"guest"}');
  18373. expect(binding('myForm.lastName.$valid')).toEqual('false');
  18374. expect(binding('myForm.lastName.$error')).toMatch(/maxlength/);
  18375. expect(binding('myForm.$valid')).toEqual('false');
  18376. });
  18377. </doc:scenario>
  18378. </doc:example>
  18379. */
  18380. var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
  18381. return {
  18382. restrict: 'E',
  18383. require: '?ngModel',
  18384. link: function(scope, element, attr, ctrl) {
  18385. if (ctrl) {
  18386. (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
  18387. $browser);
  18388. }
  18389. }
  18390. };
  18391. }];
  18392. var VALID_CLASS = 'ng-valid',
  18393. INVALID_CLASS = 'ng-invalid',
  18394. PRISTINE_CLASS = 'ng-pristine',
  18395. DIRTY_CLASS = 'ng-dirty';
  18396. /**
  18397. * @ngdoc object
  18398. * @name ng.directive:ngModel.NgModelController
  18399. *
  18400. * @property {string} $viewValue Actual string value in the view.
  18401. * @property {*} $modelValue The value in the model, that the control is bound to.
  18402. * @property {Array.<Function>} $parsers Whenever the control reads value from the DOM, it executes
  18403. * all of these functions to sanitize / convert the value as well as validate.
  18404. *
  18405. * @property {Array.<Function>} $formatters Whenever the model value changes, it executes all of
  18406. * these functions to convert the value as well as validate.
  18407. *
  18408. * @property {Object} $error An bject hash with all errors as keys.
  18409. *
  18410. * @property {boolean} $pristine True if user has not interacted with the control yet.
  18411. * @property {boolean} $dirty True if user has already interacted with the control.
  18412. * @property {boolean} $valid True if there is no error.
  18413. * @property {boolean} $invalid True if at least one error on the control.
  18414. *
  18415. * @description
  18416. *
  18417. * `NgModelController` provides API for the `ng-model` directive. The controller contains
  18418. * services for data-binding, validation, CSS update, value formatting and parsing. It
  18419. * specifically does not contain any logic which deals with DOM rendering or listening to
  18420. * DOM events. The `NgModelController` is meant to be extended by other directives where, the
  18421. * directive provides DOM manipulation and the `NgModelController` provides the data-binding.
  18422. *
  18423. * This example shows how to use `NgModelController` with a custom control to achieve
  18424. * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
  18425. * collaborate together to achieve the desired result.
  18426. *
  18427. * <example module="customControl">
  18428. <file name="style.css">
  18429. [contenteditable] {
  18430. border: 1px solid black;
  18431. background-color: white;
  18432. min-height: 20px;
  18433. }
  18434. .ng-invalid {
  18435. border: 1px solid red;
  18436. }
  18437. </file>
  18438. <file name="script.js">
  18439. angular.module('customControl', []).
  18440. directive('contenteditable', function() {
  18441. return {
  18442. restrict: 'A', // only activate on element attribute
  18443. require: '?ngModel', // get a hold of NgModelController
  18444. link: function(scope, element, attrs, ngModel) {
  18445. if(!ngModel) return; // do nothing if no ng-model
  18446. // Specify how UI should be updated
  18447. ngModel.$render = function() {
  18448. element.html(ngModel.$viewValue || '');
  18449. };
  18450. // Listen for change events to enable binding
  18451. element.bind('blur keyup change', function() {
  18452. scope.$apply(read);
  18453. });
  18454. read(); // initialize
  18455. // Write data to the model
  18456. function read() {
  18457. ngModel.$setViewValue(element.html());
  18458. }
  18459. }
  18460. };
  18461. });
  18462. </file>
  18463. <file name="index.html">
  18464. <form name="myForm">
  18465. <div contenteditable
  18466. name="myWidget" ng-model="userContent"
  18467. required>Change me!</div>
  18468. <span ng-show="myForm.myWidget.$error.required">Required!</span>
  18469. <hr>
  18470. <textarea ng-model="userContent"></textarea>
  18471. </form>
  18472. </file>
  18473. <file name="scenario.js">
  18474. it('should data-bind and become invalid', function() {
  18475. var contentEditable = element('[contenteditable]');
  18476. expect(contentEditable.text()).toEqual('Change me!');
  18477. input('userContent').enter('');
  18478. expect(contentEditable.text()).toEqual('');
  18479. expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/);
  18480. });
  18481. </file>
  18482. * </example>
  18483. *
  18484. */
  18485. var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',
  18486. function($scope, $exceptionHandler, $attr, $element, $parse) {
  18487. this.$viewValue = Number.NaN;
  18488. this.$modelValue = Number.NaN;
  18489. this.$parsers = [];
  18490. this.$formatters = [];
  18491. this.$viewChangeListeners = [];
  18492. this.$pristine = true;
  18493. this.$dirty = false;
  18494. this.$valid = true;
  18495. this.$invalid = false;
  18496. this.$name = $attr.name;
  18497. var ngModelGet = $parse($attr.ngModel),
  18498. ngModelSet = ngModelGet.assign;
  18499. if (!ngModelSet) {
  18500. throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + $attr.ngModel +
  18501. ' (' + startingTag($element) + ')');
  18502. }
  18503. /**
  18504. * @ngdoc function
  18505. * @name ng.directive:ngModel.NgModelController#$render
  18506. * @methodOf ng.directive:ngModel.NgModelController
  18507. *
  18508. * @description
  18509. * Called when the view needs to be updated. It is expected that the user of the ng-model
  18510. * directive will implement this method.
  18511. */
  18512. this.$render = noop;
  18513. var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
  18514. invalidCount = 0, // used to easily determine if we are valid
  18515. $error = this.$error = {}; // keep invalid keys here
  18516. // Setup initial state of the control
  18517. $element.addClass(PRISTINE_CLASS);
  18518. toggleValidCss(true);
  18519. // convenience method for easy toggling of classes
  18520. function toggleValidCss(isValid, validationErrorKey) {
  18521. validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
  18522. $element.
  18523. removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
  18524. addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
  18525. }
  18526. /**
  18527. * @ngdoc function
  18528. * @name ng.directive:ngModel.NgModelController#$setValidity
  18529. * @methodOf ng.directive:ngModel.NgModelController
  18530. *
  18531. * @description
  18532. * Change the validity state, and notifies the form when the control changes validity. (i.e. it
  18533. * does not notify form if given validator is already marked as invalid).
  18534. *
  18535. * This method should be called by validators - i.e. the parser or formatter functions.
  18536. *
  18537. * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
  18538. * to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
  18539. * The `validationErrorKey` should be in camelCase and will get converted into dash-case
  18540. * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
  18541. * class and can be bound to as `{{someForm.someControl.$error.myError}}` .
  18542. * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
  18543. */
  18544. this.$setValidity = function(validationErrorKey, isValid) {
  18545. if ($error[validationErrorKey] === !isValid) return;
  18546. if (isValid) {
  18547. if ($error[validationErrorKey]) invalidCount--;
  18548. if (!invalidCount) {
  18549. toggleValidCss(true);
  18550. this.$valid = true;
  18551. this.$invalid = false;
  18552. }
  18553. } else {
  18554. toggleValidCss(false);
  18555. this.$invalid = true;
  18556. this.$valid = false;
  18557. invalidCount++;
  18558. }
  18559. $error[validationErrorKey] = !isValid;
  18560. toggleValidCss(isValid, validationErrorKey);
  18561. parentForm.$setValidity(validationErrorKey, isValid, this);
  18562. };
  18563. /**
  18564. * @ngdoc function
  18565. * @name ng.directive:ngModel.NgModelController#$setViewValue
  18566. * @methodOf ng.directive:ngModel.NgModelController
  18567. *
  18568. * @description
  18569. * Read a value from view.
  18570. *
  18571. * This method should be called from within a DOM event handler.
  18572. * For example {@link ng.directive:input input} or
  18573. * {@link ng.directive:select select} directives call it.
  18574. *
  18575. * It internally calls all `formatters` and if resulted value is valid, updates the model and
  18576. * calls all registered change listeners.
  18577. *
  18578. * @param {string} value Value from the view.
  18579. */
  18580. this.$setViewValue = function(value) {
  18581. this.$viewValue = value;
  18582. // change to dirty
  18583. if (this.$pristine) {
  18584. this.$dirty = true;
  18585. this.$pristine = false;
  18586. $element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
  18587. parentForm.$setDirty();
  18588. }
  18589. forEach(this.$parsers, function(fn) {
  18590. value = fn(value);
  18591. });
  18592. if (this.$modelValue !== value) {
  18593. this.$modelValue = value;
  18594. ngModelSet($scope, value);
  18595. forEach(this.$viewChangeListeners, function(listener) {
  18596. try {
  18597. listener();
  18598. } catch(e) {
  18599. $exceptionHandler(e);
  18600. }
  18601. })
  18602. }
  18603. };
  18604. // model -> value
  18605. var ctrl = this;
  18606. $scope.$watch(function ngModelWatch() {
  18607. var value = ngModelGet($scope);
  18608. // if scope model value and ngModel value are out of sync
  18609. if (ctrl.$modelValue !== value) {
  18610. var formatters = ctrl.$formatters,
  18611. idx = formatters.length;
  18612. ctrl.$modelValue = value;
  18613. while(idx--) {
  18614. value = formatters[idx](value);
  18615. }
  18616. if (ctrl.$viewValue !== value) {
  18617. ctrl.$viewValue = value;
  18618. ctrl.$render();
  18619. }
  18620. }
  18621. });
  18622. }];
  18623. /**
  18624. * @ngdoc directive
  18625. * @name ng.directive:ngModel
  18626. *
  18627. * @element input
  18628. *
  18629. * @description
  18630. * Is directive that tells Angular to do two-way data binding. It works together with `input`,
  18631. * `select`, `textarea`. You can easily write your own directives to use `ngModel` as well.
  18632. *
  18633. * `ngModel` is responsible for:
  18634. *
  18635. * - binding the view into the model, which other directives such as `input`, `textarea` or `select`
  18636. * require,
  18637. * - providing validation behavior (i.e. required, number, email, url),
  18638. * - keeping state of the control (valid/invalid, dirty/pristine, validation errors),
  18639. * - setting related css class onto the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`),
  18640. * - register the control with parent {@link ng.directive:form form}.
  18641. *
  18642. * For basic examples, how to use `ngModel`, see:
  18643. *
  18644. * - {@link ng.directive:input input}
  18645. * - {@link ng.directive:input.text text}
  18646. * - {@link ng.directive:input.checkbox checkbox}
  18647. * - {@link ng.directive:input.radio radio}
  18648. * - {@link ng.directive:input.number number}
  18649. * - {@link ng.directive:input.email email}
  18650. * - {@link ng.directive:input.url url}
  18651. * - {@link ng.directive:select select}
  18652. * - {@link ng.directive:textarea textarea}
  18653. *
  18654. */
  18655. var ngModelDirective = function() {
  18656. return {
  18657. require: ['ngModel', '^?form'],
  18658. controller: NgModelController,
  18659. link: function(scope, element, attr, ctrls) {
  18660. // notify others, especially parent forms
  18661. var modelCtrl = ctrls[0],
  18662. formCtrl = ctrls[1] || nullFormCtrl;
  18663. formCtrl.$addControl(modelCtrl);
  18664. element.bind('$destroy', function() {
  18665. formCtrl.$removeControl(modelCtrl);
  18666. });
  18667. }
  18668. };
  18669. };
  18670. /**
  18671. * @ngdoc directive
  18672. * @name ng.directive:ngChange
  18673. * @restrict E
  18674. *
  18675. * @description
  18676. * Evaluate given expression when user changes the input.
  18677. * The expression is not evaluated when the value change is coming from the model.
  18678. *
  18679. * Note, this directive requires `ngModel` to be present.
  18680. *
  18681. * @element input
  18682. *
  18683. * @example
  18684. * <doc:example>
  18685. * <doc:source>
  18686. * <script>
  18687. * function Controller($scope) {
  18688. * $scope.counter = 0;
  18689. * $scope.change = function() {
  18690. * $scope.counter++;
  18691. * };
  18692. * }
  18693. * </script>
  18694. * <div ng-controller="Controller">
  18695. * <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
  18696. * <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
  18697. * <label for="ng-change-example2">Confirmed</label><br />
  18698. * debug = {{confirmed}}<br />
  18699. * counter = {{counter}}
  18700. * </div>
  18701. * </doc:source>
  18702. * <doc:scenario>
  18703. * it('should evaluate the expression if changing from view', function() {
  18704. * expect(binding('counter')).toEqual('0');
  18705. * element('#ng-change-example1').click();
  18706. * expect(binding('counter')).toEqual('1');
  18707. * expect(binding('confirmed')).toEqual('true');
  18708. * });
  18709. *
  18710. * it('should not evaluate the expression if changing from model', function() {
  18711. * element('#ng-change-example2').click();
  18712. * expect(binding('counter')).toEqual('0');
  18713. * expect(binding('confirmed')).toEqual('true');
  18714. * });
  18715. * </doc:scenario>
  18716. * </doc:example>
  18717. */
  18718. var ngChangeDirective = valueFn({
  18719. require: 'ngModel',
  18720. link: function(scope, element, attr, ctrl) {
  18721. ctrl.$viewChangeListeners.push(function() {
  18722. scope.$eval(attr.ngChange);
  18723. });
  18724. }
  18725. });
  18726. var requiredDirective = function() {
  18727. return {
  18728. require: '?ngModel',
  18729. link: function(scope, elm, attr, ctrl) {
  18730. if (!ctrl) return;
  18731. attr.required = true; // force truthy in case we are on non input element
  18732. var validator = function(value) {
  18733. if (attr.required && (isEmpty(value) || value === false)) {
  18734. ctrl.$setValidity('required', false);
  18735. return;
  18736. } else {
  18737. ctrl.$setValidity('required', true);
  18738. return value;
  18739. }
  18740. };
  18741. ctrl.$formatters.push(validator);
  18742. ctrl.$parsers.unshift(validator);
  18743. attr.$observe('required', function() {
  18744. validator(ctrl.$viewValue);
  18745. });
  18746. }
  18747. };
  18748. };
  18749. /**
  18750. * @ngdoc directive
  18751. * @name ng.directive:ngList
  18752. *
  18753. * @description
  18754. * Text input that converts between comma-separated string into an array of strings.
  18755. *
  18756. * @element input
  18757. * @param {string=} ngList optional delimiter that should be used to split the value. If
  18758. * specified in form `/something/` then the value will be converted into a regular expression.
  18759. *
  18760. * @example
  18761. <doc:example>
  18762. <doc:source>
  18763. <script>
  18764. function Ctrl($scope) {
  18765. $scope.names = ['igor', 'misko', 'vojta'];
  18766. }
  18767. </script>
  18768. <form name="myForm" ng-controller="Ctrl">
  18769. List: <input name="namesInput" ng-model="names" ng-list required>
  18770. <span class="error" ng-show="myForm.list.$error.required">
  18771. Required!</span>
  18772. <tt>names = {{names}}</tt><br/>
  18773. <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
  18774. <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
  18775. <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
  18776. <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
  18777. </form>
  18778. </doc:source>
  18779. <doc:scenario>
  18780. it('should initialize to model', function() {
  18781. expect(binding('names')).toEqual('["igor","misko","vojta"]');
  18782. expect(binding('myForm.namesInput.$valid')).toEqual('true');
  18783. });
  18784. it('should be invalid if empty', function() {
  18785. input('names').enter('');
  18786. expect(binding('names')).toEqual('[]');
  18787. expect(binding('myForm.namesInput.$valid')).toEqual('false');
  18788. });
  18789. </doc:scenario>
  18790. </doc:example>
  18791. */
  18792. var ngListDirective = function() {
  18793. return {
  18794. require: 'ngModel',
  18795. link: function(scope, element, attr, ctrl) {
  18796. var match = /\/(.*)\//.exec(attr.ngList),
  18797. separator = match && new RegExp(match[1]) || attr.ngList || ',';
  18798. var parse = function(viewValue) {
  18799. var list = [];
  18800. if (viewValue) {
  18801. forEach(viewValue.split(separator), function(value) {
  18802. if (value) list.push(trim(value));
  18803. });
  18804. }
  18805. return list;
  18806. };
  18807. ctrl.$parsers.push(parse);
  18808. ctrl.$formatters.push(function(value) {
  18809. if (isArray(value)) {
  18810. return value.join(', ');
  18811. }
  18812. return undefined;
  18813. });
  18814. }
  18815. };
  18816. };
  18817. var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
  18818. var ngValueDirective = function() {
  18819. return {
  18820. priority: 100,
  18821. compile: function(tpl, tplAttr) {
  18822. if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
  18823. return function(scope, elm, attr) {
  18824. attr.$set('value', scope.$eval(attr.ngValue));
  18825. };
  18826. } else {
  18827. return function(scope, elm, attr) {
  18828. scope.$watch(attr.ngValue, function valueWatchAction(value) {
  18829. attr.$set('value', value, false);
  18830. });
  18831. };
  18832. }
  18833. }
  18834. };
  18835. };
  18836. /**
  18837. * @ngdoc directive
  18838. * @name ng.directive:ngBind
  18839. *
  18840. * @description
  18841. * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
  18842. * with the value of a given expression, and to update the text content when the value of that
  18843. * expression changes.
  18844. *
  18845. * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
  18846. * `{{ expression }}` which is similar but less verbose.
  18847. *
  18848. * Once scenario in which the use of `ngBind` is prefered over `{{ expression }}` binding is when
  18849. * it's desirable to put bindings into template that is momentarily displayed by the browser in its
  18850. * raw state before Angular compiles it. Since `ngBind` is an element attribute, it makes the
  18851. * bindings invisible to the user while the page is loading.
  18852. *
  18853. * An alternative solution to this problem would be using the
  18854. * {@link ng.directive:ngCloak ngCloak} directive.
  18855. *
  18856. *
  18857. * @element ANY
  18858. * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
  18859. *
  18860. * @example
  18861. * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
  18862. <doc:example>
  18863. <doc:source>
  18864. <script>
  18865. function Ctrl($scope) {
  18866. $scope.name = 'Whirled';
  18867. }
  18868. </script>
  18869. <div ng-controller="Ctrl">
  18870. Enter name: <input type="text" ng-model="name"><br>
  18871. Hello <span ng-bind="name"></span>!
  18872. </div>
  18873. </doc:source>
  18874. <doc:scenario>
  18875. it('should check ng-bind', function() {
  18876. expect(using('.doc-example-live').binding('name')).toBe('Whirled');
  18877. using('.doc-example-live').input('name').enter('world');
  18878. expect(using('.doc-example-live').binding('name')).toBe('world');
  18879. });
  18880. </doc:scenario>
  18881. </doc:example>
  18882. */
  18883. var ngBindDirective = ngDirective(function(scope, element, attr) {
  18884. element.addClass('ng-binding').data('$binding', attr.ngBind);
  18885. scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
  18886. element.text(value == undefined ? '' : value);
  18887. });
  18888. });
  18889. /**
  18890. * @ngdoc directive
  18891. * @name ng.directive:ngBindTemplate
  18892. *
  18893. * @description
  18894. * The `ngBindTemplate` directive specifies that the element
  18895. * text should be replaced with the template in ngBindTemplate.
  18896. * Unlike ngBind the ngBindTemplate can contain multiple `{{` `}}`
  18897. * expressions. (This is required since some HTML elements
  18898. * can not have SPAN elements such as TITLE, or OPTION to name a few.)
  18899. *
  18900. * @element ANY
  18901. * @param {string} ngBindTemplate template of form
  18902. * <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
  18903. *
  18904. * @example
  18905. * Try it here: enter text in text box and watch the greeting change.
  18906. <doc:example>
  18907. <doc:source>
  18908. <script>
  18909. function Ctrl($scope) {
  18910. $scope.salutation = 'Hello';
  18911. $scope.name = 'World';
  18912. }
  18913. </script>
  18914. <div ng-controller="Ctrl">
  18915. Salutation: <input type="text" ng-model="salutation"><br>
  18916. Name: <input type="text" ng-model="name"><br>
  18917. <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
  18918. </div>
  18919. </doc:source>
  18920. <doc:scenario>
  18921. it('should check ng-bind', function() {
  18922. expect(using('.doc-example-live').binding('salutation')).
  18923. toBe('Hello');
  18924. expect(using('.doc-example-live').binding('name')).
  18925. toBe('World');
  18926. using('.doc-example-live').input('salutation').enter('Greetings');
  18927. using('.doc-example-live').input('name').enter('user');
  18928. expect(using('.doc-example-live').binding('salutation')).
  18929. toBe('Greetings');
  18930. expect(using('.doc-example-live').binding('name')).
  18931. toBe('user');
  18932. });
  18933. </doc:scenario>
  18934. </doc:example>
  18935. */
  18936. var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
  18937. return function(scope, element, attr) {
  18938. // TODO: move this to scenario runner
  18939. var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
  18940. element.addClass('ng-binding').data('$binding', interpolateFn);
  18941. attr.$observe('ngBindTemplate', function(value) {
  18942. element.text(value);
  18943. });
  18944. }
  18945. }];
  18946. /**
  18947. * @ngdoc directive
  18948. * @name ng.directive:ngBindHtmlUnsafe
  18949. *
  18950. * @description
  18951. * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
  18952. * element. *The innerHTML-ed content will not be sanitized!* You should use this directive only if
  18953. * {@link ngSanitize.directive:ngBindHtml ngBindHtml} directive is too
  18954. * restrictive and when you absolutely trust the source of the content you are binding to.
  18955. *
  18956. * See {@link ngSanitize.$sanitize $sanitize} docs for examples.
  18957. *
  18958. * @element ANY
  18959. * @param {expression} ngBindHtmlUnsafe {@link guide/expression Expression} to evaluate.
  18960. */
  18961. var ngBindHtmlUnsafeDirective = [function() {
  18962. return function(scope, element, attr) {
  18963. element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
  18964. scope.$watch(attr.ngBindHtmlUnsafe, function ngBindHtmlUnsafeWatchAction(value) {
  18965. element.html(value || '');
  18966. });
  18967. };
  18968. }];
  18969. function classDirective(name, selector) {
  18970. name = 'ngClass' + name;
  18971. return ngDirective(function(scope, element, attr) {
  18972. var oldVal = undefined;
  18973. scope.$watch(attr[name], ngClassWatchAction, true);
  18974. attr.$observe('class', function(value) {
  18975. var ngClass = scope.$eval(attr[name]);
  18976. ngClassWatchAction(ngClass, ngClass);
  18977. });
  18978. if (name !== 'ngClass') {
  18979. scope.$watch('$index', function($index, old$index) {
  18980. var mod = $index % 2;
  18981. if (mod !== old$index % 2) {
  18982. if (mod == selector) {
  18983. addClass(scope.$eval(attr[name]));
  18984. } else {
  18985. removeClass(scope.$eval(attr[name]));
  18986. }
  18987. }
  18988. });
  18989. }
  18990. function ngClassWatchAction(newVal) {
  18991. if (selector === true || scope.$index % 2 === selector) {
  18992. if (oldVal && (newVal !== oldVal)) {
  18993. removeClass(oldVal);
  18994. }
  18995. addClass(newVal);
  18996. }
  18997. oldVal = newVal;
  18998. }
  18999. function removeClass(classVal) {
  19000. if (isObject(classVal) && !isArray(classVal)) {
  19001. classVal = map(classVal, function(v, k) { if (v) return k });
  19002. }
  19003. element.removeClass(isArray(classVal) ? classVal.join(' ') : classVal);
  19004. }
  19005. function addClass(classVal) {
  19006. if (isObject(classVal) && !isArray(classVal)) {
  19007. classVal = map(classVal, function(v, k) { if (v) return k });
  19008. }
  19009. if (classVal) {
  19010. element.addClass(isArray(classVal) ? classVal.join(' ') : classVal);
  19011. }
  19012. }
  19013. });
  19014. }
  19015. /**
  19016. * @ngdoc directive
  19017. * @name ng.directive:ngClass
  19018. *
  19019. * @description
  19020. * The `ngClass` allows you to set CSS class on HTML element dynamically by databinding an
  19021. * expression that represents all classes to be added.
  19022. *
  19023. * The directive won't add duplicate classes if a particular class was already set.
  19024. *
  19025. * When the expression changes, the previously added classes are removed and only then the
  19026. * new classes are added.
  19027. *
  19028. * @element ANY
  19029. * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
  19030. * of the evaluation can be a string representing space delimited class
  19031. * names, an array, or a map of class names to boolean values.
  19032. *
  19033. * @example
  19034. <example>
  19035. <file name="index.html">
  19036. <input type="button" value="set" ng-click="myVar='my-class'">
  19037. <input type="button" value="clear" ng-click="myVar=''">
  19038. <br>
  19039. <span ng-class="myVar">Sample Text</span>
  19040. </file>
  19041. <file name="style.css">
  19042. .my-class {
  19043. color: red;
  19044. }
  19045. </file>
  19046. <file name="scenario.js">
  19047. it('should check ng-class', function() {
  19048. expect(element('.doc-example-live span').prop('className')).not().
  19049. toMatch(/my-class/);
  19050. using('.doc-example-live').element(':button:first').click();
  19051. expect(element('.doc-example-live span').prop('className')).
  19052. toMatch(/my-class/);
  19053. using('.doc-example-live').element(':button:last').click();
  19054. expect(element('.doc-example-live span').prop('className')).not().
  19055. toMatch(/my-class/);
  19056. });
  19057. </file>
  19058. </example>
  19059. */
  19060. var ngClassDirective = classDirective('', true);
  19061. /**
  19062. * @ngdoc directive
  19063. * @name ng.directive:ngClassOdd
  19064. *
  19065. * @description
  19066. * The `ngClassOdd` and `ngClassEven` directives work exactly as
  19067. * {@link ng.directive:ngClass ngClass}, except it works in
  19068. * conjunction with `ngRepeat` and takes affect only on odd (even) rows.
  19069. *
  19070. * This directive can be applied only within a scope of an
  19071. * {@link ng.directive:ngRepeat ngRepeat}.
  19072. *
  19073. * @element ANY
  19074. * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
  19075. * of the evaluation can be a string representing space delimited class names or an array.
  19076. *
  19077. * @example
  19078. <example>
  19079. <file name="index.html">
  19080. <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
  19081. <li ng-repeat="name in names">
  19082. <span ng-class-odd="'odd'" ng-class-even="'even'">
  19083. {{name}}
  19084. </span>
  19085. </li>
  19086. </ol>
  19087. </file>
  19088. <file name="style.css">
  19089. .odd {
  19090. color: red;
  19091. }
  19092. .even {
  19093. color: blue;
  19094. }
  19095. </file>
  19096. <file name="scenario.js">
  19097. it('should check ng-class-odd and ng-class-even', function() {
  19098. expect(element('.doc-example-live li:first span').prop('className')).
  19099. toMatch(/odd/);
  19100. expect(element('.doc-example-live li:last span').prop('className')).
  19101. toMatch(/even/);
  19102. });
  19103. </file>
  19104. </example>
  19105. */
  19106. var ngClassOddDirective = classDirective('Odd', 0);
  19107. /**
  19108. * @ngdoc directive
  19109. * @name ng.directive:ngClassEven
  19110. *
  19111. * @description
  19112. * The `ngClassOdd` and `ngClassEven` works exactly as
  19113. * {@link ng.directive:ngClass ngClass}, except it works in
  19114. * conjunction with `ngRepeat` and takes affect only on odd (even) rows.
  19115. *
  19116. * This directive can be applied only within a scope of an
  19117. * {@link ng.directive:ngRepeat ngRepeat}.
  19118. *
  19119. * @element ANY
  19120. * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
  19121. * result of the evaluation can be a string representing space delimited class names or an array.
  19122. *
  19123. * @example
  19124. <example>
  19125. <file name="index.html">
  19126. <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
  19127. <li ng-repeat="name in names">
  19128. <span ng-class-odd="'odd'" ng-class-even="'even'">
  19129. {{name}} &nbsp; &nbsp; &nbsp;
  19130. </span>
  19131. </li>
  19132. </ol>
  19133. </file>
  19134. <file name="style.css">
  19135. .odd {
  19136. color: red;
  19137. }
  19138. .even {
  19139. color: blue;
  19140. }
  19141. </file>
  19142. <file name="scenario.js">
  19143. it('should check ng-class-odd and ng-class-even', function() {
  19144. expect(element('.doc-example-live li:first span').prop('className')).
  19145. toMatch(/odd/);
  19146. expect(element('.doc-example-live li:last span').prop('className')).
  19147. toMatch(/even/);
  19148. });
  19149. </file>
  19150. </example>
  19151. */
  19152. var ngClassEvenDirective = classDirective('Even', 1);
  19153. /**
  19154. * @ngdoc directive
  19155. * @name ng.directive:ngCloak
  19156. *
  19157. * @description
  19158. * The `ngCloak` directive is used to prevent the Angular html template from being briefly
  19159. * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
  19160. * directive to avoid the undesirable flicker effect caused by the html template display.
  19161. *
  19162. * The directive can be applied to the `<body>` element, but typically a fine-grained application is
  19163. * prefered in order to benefit from progressive rendering of the browser view.
  19164. *
  19165. * `ngCloak` works in cooperation with a css rule that is embedded within `angular.js` and
  19166. * `angular.min.js` files. Following is the css rule:
  19167. *
  19168. * <pre>
  19169. * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  19170. * display: none;
  19171. * }
  19172. * </pre>
  19173. *
  19174. * When this css rule is loaded by the browser, all html elements (including their children) that
  19175. * are tagged with the `ng-cloak` directive are hidden. When Angular comes across this directive
  19176. * during the compilation of the template it deletes the `ngCloak` element attribute, which
  19177. * makes the compiled element visible.
  19178. *
  19179. * For the best result, `angular.js` script must be loaded in the head section of the html file;
  19180. * alternatively, the css rule (above) must be included in the external stylesheet of the
  19181. * application.
  19182. *
  19183. * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
  19184. * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
  19185. * class `ngCloak` in addition to `ngCloak` directive as shown in the example below.
  19186. *
  19187. * @element ANY
  19188. *
  19189. * @example
  19190. <doc:example>
  19191. <doc:source>
  19192. <div id="template1" ng-cloak>{{ 'hello' }}</div>
  19193. <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
  19194. </doc:source>
  19195. <doc:scenario>
  19196. it('should remove the template directive and css class', function() {
  19197. expect(element('.doc-example-live #template1').attr('ng-cloak')).
  19198. not().toBeDefined();
  19199. expect(element('.doc-example-live #template2').attr('ng-cloak')).
  19200. not().toBeDefined();
  19201. });
  19202. </doc:scenario>
  19203. </doc:example>
  19204. *
  19205. */
  19206. var ngCloakDirective = ngDirective({
  19207. compile: function(element, attr) {
  19208. attr.$set('ngCloak', undefined);
  19209. element.removeClass('ng-cloak');
  19210. }
  19211. });
  19212. /**
  19213. * @ngdoc directive
  19214. * @name ng.directive:ngController
  19215. *
  19216. * @description
  19217. * The `ngController` directive assigns behavior to a scope. This is a key aspect of how angular
  19218. * supports the principles behind the Model-View-Controller design pattern.
  19219. *
  19220. * MVC components in angular:
  19221. *
  19222. * * Model — The Model is data in scope properties; scopes are attached to the DOM.
  19223. * * View — The template (HTML with data bindings) is rendered into the View.
  19224. * * Controller — The `ngController` directive specifies a Controller class; the class has
  19225. * methods that typically express the business logic behind the application.
  19226. *
  19227. * Note that an alternative way to define controllers is via the `{@link ng.$route}`
  19228. * service.
  19229. *
  19230. * @element ANY
  19231. * @scope
  19232. * @param {expression} ngController Name of a globally accessible constructor function or an
  19233. * {@link guide/expression expression} that on the current scope evaluates to a
  19234. * constructor function.
  19235. *
  19236. * @example
  19237. * Here is a simple form for editing user contact information. Adding, removing, clearing, and
  19238. * greeting are methods declared on the controller (see source tab). These methods can
  19239. * easily be called from the angular markup. Notice that the scope becomes the `this` for the
  19240. * controller's instance. This allows for easy access to the view data from the controller. Also
  19241. * notice that any changes to the data are automatically reflected in the View without the need
  19242. * for a manual update.
  19243. <doc:example>
  19244. <doc:source>
  19245. <script>
  19246. function SettingsController($scope) {
  19247. $scope.name = "John Smith";
  19248. $scope.contacts = [
  19249. {type:'phone', value:'408 555 1212'},
  19250. {type:'email', value:'john.smith@example.org'} ];
  19251. $scope.greet = function() {
  19252. alert(this.name);
  19253. };
  19254. $scope.addContact = function() {
  19255. this.contacts.push({type:'email', value:'yourname@example.org'});
  19256. };
  19257. $scope.removeContact = function(contactToRemove) {
  19258. var index = this.contacts.indexOf(contactToRemove);
  19259. this.contacts.splice(index, 1);
  19260. };
  19261. $scope.clearContact = function(contact) {
  19262. contact.type = 'phone';
  19263. contact.value = '';
  19264. };
  19265. }
  19266. </script>
  19267. <div ng-controller="SettingsController">
  19268. Name: <input type="text" ng-model="name"/>
  19269. [ <a href="" ng-click="greet()">greet</a> ]<br/>
  19270. Contact:
  19271. <ul>
  19272. <li ng-repeat="contact in contacts">
  19273. <select ng-model="contact.type">
  19274. <option>phone</option>
  19275. <option>email</option>
  19276. </select>
  19277. <input type="text" ng-model="contact.value"/>
  19278. [ <a href="" ng-click="clearContact(contact)">clear</a>
  19279. | <a href="" ng-click="removeContact(contact)">X</a> ]
  19280. </li>
  19281. <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
  19282. </ul>
  19283. </div>
  19284. </doc:source>
  19285. <doc:scenario>
  19286. it('should check controller', function() {
  19287. expect(element('.doc-example-live div>:input').val()).toBe('John Smith');
  19288. expect(element('.doc-example-live li:nth-child(1) input').val())
  19289. .toBe('408 555 1212');
  19290. expect(element('.doc-example-live li:nth-child(2) input').val())
  19291. .toBe('john.smith@example.org');
  19292. element('.doc-example-live li:first a:contains("clear")').click();
  19293. expect(element('.doc-example-live li:first input').val()).toBe('');
  19294. element('.doc-example-live li:last a:contains("add")').click();
  19295. expect(element('.doc-example-live li:nth-child(3) input').val())
  19296. .toBe('yourname@example.org');
  19297. });
  19298. </doc:scenario>
  19299. </doc:example>
  19300. */
  19301. var ngControllerDirective = [function() {
  19302. return {
  19303. scope: true,
  19304. controller: '@'
  19305. };
  19306. }];
  19307. /**
  19308. * @ngdoc directive
  19309. * @name ng.directive:ngCsp
  19310. * @priority 1000
  19311. *
  19312. * @description
  19313. * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
  19314. * This directive should be used on the root element of the application (typically the `<html>`
  19315. * element or other element with the {@link ng.directive:ngApp ngApp}
  19316. * directive).
  19317. *
  19318. * If enabled the performance of template expression evaluator will suffer slightly, so don't enable
  19319. * this mode unless you need it.
  19320. *
  19321. * @element html
  19322. */
  19323. var ngCspDirective = ['$sniffer', function($sniffer) {
  19324. return {
  19325. priority: 1000,
  19326. compile: function() {
  19327. $sniffer.csp = true;
  19328. }
  19329. };
  19330. }];
  19331. /**
  19332. * @ngdoc directive
  19333. * @name ng.directive:ngClick
  19334. *
  19335. * @description
  19336. * The ngClick allows you to specify custom behavior when
  19337. * element is clicked.
  19338. *
  19339. * @element ANY
  19340. * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
  19341. * click. (Event object is available as `$event`)
  19342. *
  19343. * @example
  19344. <doc:example>
  19345. <doc:source>
  19346. <button ng-click="count = count + 1" ng-init="count=0">
  19347. Increment
  19348. </button>
  19349. count: {{count}}
  19350. </doc:source>
  19351. <doc:scenario>
  19352. it('should check ng-click', function() {
  19353. expect(binding('count')).toBe('0');
  19354. element('.doc-example-live :button').click();
  19355. expect(binding('count')).toBe('1');
  19356. });
  19357. </doc:scenario>
  19358. </doc:example>
  19359. */
  19360. /*
  19361. * A directive that allows creation of custom onclick handlers that are defined as angular
  19362. * expressions and are compiled and executed within the current scope.
  19363. *
  19364. * Events that are handled via these handler are always configured not to propagate further.
  19365. */
  19366. var ngEventDirectives = {};
  19367. forEach(
  19368. 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave'.split(' '),
  19369. function(name) {
  19370. var directiveName = directiveNormalize('ng-' + name);
  19371. ngEventDirectives[directiveName] = ['$parse', function($parse) {
  19372. return function(scope, element, attr) {
  19373. var fn = $parse(attr[directiveName]);
  19374. element.bind(lowercase(name), function(event) {
  19375. scope.$apply(function() {
  19376. fn(scope, {$event:event});
  19377. });
  19378. });
  19379. };
  19380. }];
  19381. }
  19382. );
  19383. /**
  19384. * @ngdoc directive
  19385. * @name ng.directive:ngDblclick
  19386. *
  19387. * @description
  19388. * The `ngDblclick` directive allows you to specify custom behavior on dblclick event.
  19389. *
  19390. * @element ANY
  19391. * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
  19392. * dblclick. (Event object is available as `$event`)
  19393. *
  19394. * @example
  19395. * See {@link ng.directive:ngClick ngClick}
  19396. */
  19397. /**
  19398. * @ngdoc directive
  19399. * @name ng.directive:ngMousedown
  19400. *
  19401. * @description
  19402. * The ngMousedown directive allows you to specify custom behavior on mousedown event.
  19403. *
  19404. * @element ANY
  19405. * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
  19406. * mousedown. (Event object is available as `$event`)
  19407. *
  19408. * @example
  19409. * See {@link ng.directive:ngClick ngClick}
  19410. */
  19411. /**
  19412. * @ngdoc directive
  19413. * @name ng.directive:ngMouseup
  19414. *
  19415. * @description
  19416. * Specify custom behavior on mouseup event.
  19417. *
  19418. * @element ANY
  19419. * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
  19420. * mouseup. (Event object is available as `$event`)
  19421. *
  19422. * @example
  19423. * See {@link ng.directive:ngClick ngClick}
  19424. */
  19425. /**
  19426. * @ngdoc directive
  19427. * @name ng.directive:ngMouseover
  19428. *
  19429. * @description
  19430. * Specify custom behavior on mouseover event.
  19431. *
  19432. * @element ANY
  19433. * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
  19434. * mouseover. (Event object is available as `$event`)
  19435. *
  19436. * @example
  19437. * See {@link ng.directive:ngClick ngClick}
  19438. */
  19439. /**
  19440. * @ngdoc directive
  19441. * @name ng.directive:ngMouseenter
  19442. *
  19443. * @description
  19444. * Specify custom behavior on mouseenter event.
  19445. *
  19446. * @element ANY
  19447. * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
  19448. * mouseenter. (Event object is available as `$event`)
  19449. *
  19450. * @example
  19451. * See {@link ng.directive:ngClick ngClick}
  19452. */
  19453. /**
  19454. * @ngdoc directive
  19455. * @name ng.directive:ngMouseleave
  19456. *
  19457. * @description
  19458. * Specify custom behavior on mouseleave event.
  19459. *
  19460. * @element ANY
  19461. * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
  19462. * mouseleave. (Event object is available as `$event`)
  19463. *
  19464. * @example
  19465. * See {@link ng.directive:ngClick ngClick}
  19466. */
  19467. /**
  19468. * @ngdoc directive
  19469. * @name ng.directive:ngMousemove
  19470. *
  19471. * @description
  19472. * Specify custom behavior on mousemove event.
  19473. *
  19474. * @element ANY
  19475. * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
  19476. * mousemove. (Event object is available as `$event`)
  19477. *
  19478. * @example
  19479. * See {@link ng.directive:ngClick ngClick}
  19480. */
  19481. /**
  19482. * @ngdoc directive
  19483. * @name ng.directive:ngSubmit
  19484. *
  19485. * @description
  19486. * Enables binding angular expressions to onsubmit events.
  19487. *
  19488. * Additionally it prevents the default action (which for form means sending the request to the
  19489. * server and reloading the current page).
  19490. *
  19491. * @element form
  19492. * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
  19493. *
  19494. * @example
  19495. <doc:example>
  19496. <doc:source>
  19497. <script>
  19498. function Ctrl($scope) {
  19499. $scope.list = [];
  19500. $scope.text = 'hello';
  19501. $scope.submit = function() {
  19502. if (this.text) {
  19503. this.list.push(this.text);
  19504. this.text = '';
  19505. }
  19506. };
  19507. }
  19508. </script>
  19509. <form ng-submit="submit()" ng-controller="Ctrl">
  19510. Enter text and hit enter:
  19511. <input type="text" ng-model="text" name="text" />
  19512. <input type="submit" id="submit" value="Submit" />
  19513. <pre>list={{list}}</pre>
  19514. </form>
  19515. </doc:source>
  19516. <doc:scenario>
  19517. it('should check ng-submit', function() {
  19518. expect(binding('list')).toBe('[]');
  19519. element('.doc-example-live #submit').click();
  19520. expect(binding('list')).toBe('["hello"]');
  19521. expect(input('text').val()).toBe('');
  19522. });
  19523. it('should ignore empty strings', function() {
  19524. expect(binding('list')).toBe('[]');
  19525. element('.doc-example-live #submit').click();
  19526. element('.doc-example-live #submit').click();
  19527. expect(binding('list')).toBe('["hello"]');
  19528. });
  19529. </doc:scenario>
  19530. </doc:example>
  19531. */
  19532. var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
  19533. element.bind('submit', function() {
  19534. scope.$apply(attrs.ngSubmit);
  19535. });
  19536. });
  19537. /**
  19538. * @ngdoc directive
  19539. * @name ng.directive:ngInclude
  19540. * @restrict ECA
  19541. *
  19542. * @description
  19543. * Fetches, compiles and includes an external HTML fragment.
  19544. *
  19545. * Keep in mind that Same Origin Policy applies to included resources
  19546. * (e.g. ngInclude won't work for cross-domain requests on all browsers and for
  19547. * file:// access on some browsers).
  19548. *
  19549. * @scope
  19550. *
  19551. * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
  19552. * make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`.
  19553. * @param {string=} onload Expression to evaluate when a new partial is loaded.
  19554. *
  19555. * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
  19556. * $anchorScroll} to scroll the viewport after the content is loaded.
  19557. *
  19558. * - If the attribute is not set, disable scrolling.
  19559. * - If the attribute is set without value, enable scrolling.
  19560. * - Otherwise enable scrolling only if the expression evaluates to truthy value.
  19561. *
  19562. * @example
  19563. <example>
  19564. <file name="index.html">
  19565. <div ng-controller="Ctrl">
  19566. <select ng-model="template" ng-options="t.name for t in templates">
  19567. <option value="">(blank)</option>
  19568. </select>
  19569. url of the template: <tt>{{template.url}}</tt>
  19570. <hr/>
  19571. <div ng-include src="template.url"></div>
  19572. </div>
  19573. </file>
  19574. <file name="script.js">
  19575. function Ctrl($scope) {
  19576. $scope.templates =
  19577. [ { name: 'template1.html', url: 'template1.html'}
  19578. , { name: 'template2.html', url: 'template2.html'} ];
  19579. $scope.template = $scope.templates[0];
  19580. }
  19581. </file>
  19582. <file name="template1.html">
  19583. Content of template1.html
  19584. </file>
  19585. <file name="template2.html">
  19586. Content of template2.html
  19587. </file>
  19588. <file name="scenario.js">
  19589. it('should load template1.html', function() {
  19590. expect(element('.doc-example-live [ng-include]').text()).
  19591. toMatch(/Content of template1.html/);
  19592. });
  19593. it('should load template2.html', function() {
  19594. select('template').option('1');
  19595. expect(element('.doc-example-live [ng-include]').text()).
  19596. toMatch(/Content of template2.html/);
  19597. });
  19598. it('should change to blank', function() {
  19599. select('template').option('');
  19600. expect(element('.doc-example-live [ng-include]').text()).toEqual('');
  19601. });
  19602. </file>
  19603. </example>
  19604. */
  19605. /**
  19606. * @ngdoc event
  19607. * @name ng.directive:ngInclude#$includeContentLoaded
  19608. * @eventOf ng.directive:ngInclude
  19609. * @eventType emit on the current ngInclude scope
  19610. * @description
  19611. * Emitted every time the ngInclude content is reloaded.
  19612. */
  19613. var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile',
  19614. function($http, $templateCache, $anchorScroll, $compile) {
  19615. return {
  19616. restrict: 'ECA',
  19617. terminal: true,
  19618. compile: function(element, attr) {
  19619. var srcExp = attr.ngInclude || attr.src,
  19620. onloadExp = attr.onload || '',
  19621. autoScrollExp = attr.autoscroll;
  19622. return function(scope, element) {
  19623. var changeCounter = 0,
  19624. childScope;
  19625. var clearContent = function() {
  19626. if (childScope) {
  19627. childScope.$destroy();
  19628. childScope = null;
  19629. }
  19630. element.html('');
  19631. };
  19632. scope.$watch(srcExp, function ngIncludeWatchAction(src) {
  19633. var thisChangeId = ++changeCounter;
  19634. if (src) {
  19635. $http.get(src, {cache: $templateCache}).success(function(response) {
  19636. if (thisChangeId !== changeCounter) return;
  19637. if (childScope) childScope.$destroy();
  19638. childScope = scope.$new();
  19639. element.html(response);
  19640. $compile(element.contents())(childScope);
  19641. if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
  19642. $anchorScroll();
  19643. }
  19644. childScope.$emit('$includeContentLoaded');
  19645. scope.$eval(onloadExp);
  19646. }).error(function() {
  19647. if (thisChangeId === changeCounter) clearContent();
  19648. });
  19649. } else clearContent();
  19650. });
  19651. };
  19652. }
  19653. };
  19654. }];
  19655. /**
  19656. * @ngdoc directive
  19657. * @name ng.directive:ngInit
  19658. *
  19659. * @description
  19660. * The `ngInit` directive specifies initialization tasks to be executed
  19661. * before the template enters execution mode during bootstrap.
  19662. *
  19663. * @element ANY
  19664. * @param {expression} ngInit {@link guide/expression Expression} to eval.
  19665. *
  19666. * @example
  19667. <doc:example>
  19668. <doc:source>
  19669. <div ng-init="greeting='Hello'; person='World'">
  19670. {{greeting}} {{person}}!
  19671. </div>
  19672. </doc:source>
  19673. <doc:scenario>
  19674. it('should check greeting', function() {
  19675. expect(binding('greeting')).toBe('Hello');
  19676. expect(binding('person')).toBe('World');
  19677. });
  19678. </doc:scenario>
  19679. </doc:example>
  19680. */
  19681. var ngInitDirective = ngDirective({
  19682. compile: function() {
  19683. return {
  19684. pre: function(scope, element, attrs) {
  19685. scope.$eval(attrs.ngInit);
  19686. }
  19687. }
  19688. }
  19689. });
  19690. /**
  19691. * @ngdoc directive
  19692. * @name ng.directive:ngNonBindable
  19693. * @priority 1000
  19694. *
  19695. * @description
  19696. * Sometimes it is necessary to write code which looks like bindings but which should be left alone
  19697. * by angular. Use `ngNonBindable` to make angular ignore a chunk of HTML.
  19698. *
  19699. * @element ANY
  19700. *
  19701. * @example
  19702. * In this example there are two location where a simple binding (`{{}}`) is present, but the one
  19703. * wrapped in `ngNonBindable` is left alone.
  19704. *
  19705. * @example
  19706. <doc:example>
  19707. <doc:source>
  19708. <div>Normal: {{1 + 2}}</div>
  19709. <div ng-non-bindable>Ignored: {{1 + 2}}</div>
  19710. </doc:source>
  19711. <doc:scenario>
  19712. it('should check ng-non-bindable', function() {
  19713. expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
  19714. expect(using('.doc-example-live').element('div:last').text()).
  19715. toMatch(/1 \+ 2/);
  19716. });
  19717. </doc:scenario>
  19718. </doc:example>
  19719. */
  19720. var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
  19721. /**
  19722. * @ngdoc directive
  19723. * @name ng.directive:ngPluralize
  19724. * @restrict EA
  19725. *
  19726. * @description
  19727. * # Overview
  19728. * `ngPluralize` is a directive that displays messages according to en-US localization rules.
  19729. * These rules are bundled with angular.js and the rules can be overridden
  19730. * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
  19731. * by specifying the mappings between
  19732. * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
  19733. * plural categories} and the strings to be displayed.
  19734. *
  19735. * # Plural categories and explicit number rules
  19736. * There are two
  19737. * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
  19738. * plural categories} in Angular's default en-US locale: "one" and "other".
  19739. *
  19740. * While a pural category may match many numbers (for example, in en-US locale, "other" can match
  19741. * any number that is not 1), an explicit number rule can only match one number. For example, the
  19742. * explicit number rule for "3" matches the number 3. You will see the use of plural categories
  19743. * and explicit number rules throughout later parts of this documentation.
  19744. *
  19745. * # Configuring ngPluralize
  19746. * You configure ngPluralize by providing 2 attributes: `count` and `when`.
  19747. * You can also provide an optional attribute, `offset`.
  19748. *
  19749. * The value of the `count` attribute can be either a string or an {@link guide/expression
  19750. * Angular expression}; these are evaluated on the current scope for its bound value.
  19751. *
  19752. * The `when` attribute specifies the mappings between plural categories and the actual
  19753. * string to be displayed. The value of the attribute should be a JSON object so that Angular
  19754. * can interpret it correctly.
  19755. *
  19756. * The following example shows how to configure ngPluralize:
  19757. *
  19758. * <pre>
  19759. * <ng-pluralize count="personCount"
  19760. when="{'0': 'Nobody is viewing.',
  19761. * 'one': '1 person is viewing.',
  19762. * 'other': '{} people are viewing.'}">
  19763. * </ng-pluralize>
  19764. *</pre>
  19765. *
  19766. * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
  19767. * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
  19768. * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
  19769. * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
  19770. * show "a dozen people are viewing".
  19771. *
  19772. * You can use a set of closed braces(`{}`) as a placeholder for the number that you want substituted
  19773. * into pluralized strings. In the previous example, Angular will replace `{}` with
  19774. * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
  19775. * for <span ng-non-bindable>{{numberExpression}}</span>.
  19776. *
  19777. * # Configuring ngPluralize with offset
  19778. * The `offset` attribute allows further customization of pluralized text, which can result in
  19779. * a better user experience. For example, instead of the message "4 people are viewing this document",
  19780. * you might display "John, Kate and 2 others are viewing this document".
  19781. * The offset attribute allows you to offset a number by any desired value.
  19782. * Let's take a look at an example:
  19783. *
  19784. * <pre>
  19785. * <ng-pluralize count="personCount" offset=2
  19786. * when="{'0': 'Nobody is viewing.',
  19787. * '1': '{{person1}} is viewing.',
  19788. * '2': '{{person1}} and {{person2}} are viewing.',
  19789. * 'one': '{{person1}}, {{person2}} and one other person are viewing.',
  19790. * 'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
  19791. * </ng-pluralize>
  19792. * </pre>
  19793. *
  19794. * Notice that we are still using two plural categories(one, other), but we added
  19795. * three explicit number rules 0, 1 and 2.
  19796. * When one person, perhaps John, views the document, "John is viewing" will be shown.
  19797. * When three people view the document, no explicit number rule is found, so
  19798. * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
  19799. * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
  19800. * is shown.
  19801. *
  19802. * Note that when you specify offsets, you must provide explicit number rules for
  19803. * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
  19804. * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
  19805. * plural categories "one" and "other".
  19806. *
  19807. * @param {string|expression} count The variable to be bounded to.
  19808. * @param {string} when The mapping between plural category to its correspoding strings.
  19809. * @param {number=} offset Offset to deduct from the total number.
  19810. *
  19811. * @example
  19812. <doc:example>
  19813. <doc:source>
  19814. <script>
  19815. function Ctrl($scope) {
  19816. $scope.person1 = 'Igor';
  19817. $scope.person2 = 'Misko';
  19818. $scope.personCount = 1;
  19819. }
  19820. </script>
  19821. <div ng-controller="Ctrl">
  19822. Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
  19823. Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
  19824. Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
  19825. <!--- Example with simple pluralization rules for en locale --->
  19826. Without Offset:
  19827. <ng-pluralize count="personCount"
  19828. when="{'0': 'Nobody is viewing.',
  19829. 'one': '1 person is viewing.',
  19830. 'other': '{} people are viewing.'}">
  19831. </ng-pluralize><br>
  19832. <!--- Example with offset --->
  19833. With Offset(2):
  19834. <ng-pluralize count="personCount" offset=2
  19835. when="{'0': 'Nobody is viewing.',
  19836. '1': '{{person1}} is viewing.',
  19837. '2': '{{person1}} and {{person2}} are viewing.',
  19838. 'one': '{{person1}}, {{person2}} and one other person are viewing.',
  19839. 'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
  19840. </ng-pluralize>
  19841. </div>
  19842. </doc:source>
  19843. <doc:scenario>
  19844. it('should show correct pluralized string', function() {
  19845. expect(element('.doc-example-live ng-pluralize:first').text()).
  19846. toBe('1 person is viewing.');
  19847. expect(element('.doc-example-live ng-pluralize:last').text()).
  19848. toBe('Igor is viewing.');
  19849. using('.doc-example-live').input('personCount').enter('0');
  19850. expect(element('.doc-example-live ng-pluralize:first').text()).
  19851. toBe('Nobody is viewing.');
  19852. expect(element('.doc-example-live ng-pluralize:last').text()).
  19853. toBe('Nobody is viewing.');
  19854. using('.doc-example-live').input('personCount').enter('2');
  19855. expect(element('.doc-example-live ng-pluralize:first').text()).
  19856. toBe('2 people are viewing.');
  19857. expect(element('.doc-example-live ng-pluralize:last').text()).
  19858. toBe('Igor and Misko are viewing.');
  19859. using('.doc-example-live').input('personCount').enter('3');
  19860. expect(element('.doc-example-live ng-pluralize:first').text()).
  19861. toBe('3 people are viewing.');
  19862. expect(element('.doc-example-live ng-pluralize:last').text()).
  19863. toBe('Igor, Misko and one other person are viewing.');
  19864. using('.doc-example-live').input('personCount').enter('4');
  19865. expect(element('.doc-example-live ng-pluralize:first').text()).
  19866. toBe('4 people are viewing.');
  19867. expect(element('.doc-example-live ng-pluralize:last').text()).
  19868. toBe('Igor, Misko and 2 other people are viewing.');
  19869. });
  19870. it('should show data-binded names', function() {
  19871. using('.doc-example-live').input('personCount').enter('4');
  19872. expect(element('.doc-example-live ng-pluralize:last').text()).
  19873. toBe('Igor, Misko and 2 other people are viewing.');
  19874. using('.doc-example-live').input('person1').enter('Di');
  19875. using('.doc-example-live').input('person2').enter('Vojta');
  19876. expect(element('.doc-example-live ng-pluralize:last').text()).
  19877. toBe('Di, Vojta and 2 other people are viewing.');
  19878. });
  19879. </doc:scenario>
  19880. </doc:example>
  19881. */
  19882. var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
  19883. var BRACE = /{}/g;
  19884. return {
  19885. restrict: 'EA',
  19886. link: function(scope, element, attr) {
  19887. var numberExp = attr.count,
  19888. whenExp = element.attr(attr.$attr.when), // this is because we have {{}} in attrs
  19889. offset = attr.offset || 0,
  19890. whens = scope.$eval(whenExp),
  19891. whensExpFns = {},
  19892. startSymbol = $interpolate.startSymbol(),
  19893. endSymbol = $interpolate.endSymbol();
  19894. forEach(whens, function(expression, key) {
  19895. whensExpFns[key] =
  19896. $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
  19897. offset + endSymbol));
  19898. });
  19899. scope.$watch(function ngPluralizeWatch() {
  19900. var value = parseFloat(scope.$eval(numberExp));
  19901. if (!isNaN(value)) {
  19902. //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
  19903. //check it against pluralization rules in $locale service
  19904. if (!whens[value]) value = $locale.pluralCat(value - offset);
  19905. return whensExpFns[value](scope, element, true);
  19906. } else {
  19907. return '';
  19908. }
  19909. }, function ngPluralizeWatchAction(newVal) {
  19910. element.text(newVal);
  19911. });
  19912. }
  19913. };
  19914. }];
  19915. /**
  19916. * @ngdoc directive
  19917. * @name ng.directive:ngRepeat
  19918. *
  19919. * @description
  19920. * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
  19921. * instance gets its own scope, where the given loop variable is set to the current collection item,
  19922. * and `$index` is set to the item index or key.
  19923. *
  19924. * Special properties are exposed on the local scope of each template instance, including:
  19925. *
  19926. * * `$index` – `{number}` – iterator offset of the repeated element (0..length-1)
  19927. * * `$first` – `{boolean}` – true if the repeated element is first in the iterator.
  19928. * * `$middle` – `{boolean}` – true if the repeated element is between the first and last in the iterator.
  19929. * * `$last` – `{boolean}` – true if the repeated element is last in the iterator.
  19930. *
  19931. *
  19932. * @element ANY
  19933. * @scope
  19934. * @priority 1000
  19935. * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. Two
  19936. * formats are currently supported:
  19937. *
  19938. * * `variable in expression` – where variable is the user defined loop variable and `expression`
  19939. * is a scope expression giving the collection to enumerate.
  19940. *
  19941. * For example: `track in cd.tracks`.
  19942. *
  19943. * * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
  19944. * and `expression` is the scope expression giving the collection to enumerate.
  19945. *
  19946. * For example: `(name, age) in {'adam':10, 'amalie':12}`.
  19947. *
  19948. * @example
  19949. * This example initializes the scope to a list of names and
  19950. * then uses `ngRepeat` to display every person:
  19951. <doc:example>
  19952. <doc:source>
  19953. <div ng-init="friends = [{name:'John', age:25}, {name:'Mary', age:28}]">
  19954. I have {{friends.length}} friends. They are:
  19955. <ul>
  19956. <li ng-repeat="friend in friends">
  19957. [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
  19958. </li>
  19959. </ul>
  19960. </div>
  19961. </doc:source>
  19962. <doc:scenario>
  19963. it('should check ng-repeat', function() {
  19964. var r = using('.doc-example-live').repeater('ul li');
  19965. expect(r.count()).toBe(2);
  19966. expect(r.row(0)).toEqual(["1","John","25"]);
  19967. expect(r.row(1)).toEqual(["2","Mary","28"]);
  19968. });
  19969. </doc:scenario>
  19970. </doc:example>
  19971. */
  19972. var ngRepeatDirective = ngDirective({
  19973. transclude: 'element',
  19974. priority: 1000,
  19975. terminal: true,
  19976. compile: function(element, attr, linker) {
  19977. return function(scope, iterStartElement, attr){
  19978. var expression = attr.ngRepeat;
  19979. var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
  19980. lhs, rhs, valueIdent, keyIdent;
  19981. if (! match) {
  19982. throw Error("Expected ngRepeat in form of '_item_ in _collection_' but got '" +
  19983. expression + "'.");
  19984. }
  19985. lhs = match[1];
  19986. rhs = match[2];
  19987. match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
  19988. if (!match) {
  19989. throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
  19990. lhs + "'.");
  19991. }
  19992. valueIdent = match[3] || match[1];
  19993. keyIdent = match[2];
  19994. // Store a list of elements from previous run. This is a hash where key is the item from the
  19995. // iterator, and the value is an array of objects with following properties.
  19996. // - scope: bound scope
  19997. // - element: previous element.
  19998. // - index: position
  19999. // We need an array of these objects since the same object can be returned from the iterator.
  20000. // We expect this to be a rare case.
  20001. var lastOrder = new HashQueueMap();
  20002. scope.$watch(function ngRepeatWatch(scope){
  20003. var index, length,
  20004. collection = scope.$eval(rhs),
  20005. cursor = iterStartElement, // current position of the node
  20006. // Same as lastOrder but it has the current state. It will become the
  20007. // lastOrder on the next iteration.
  20008. nextOrder = new HashQueueMap(),
  20009. arrayBound,
  20010. childScope,
  20011. key, value, // key/value of iteration
  20012. array,
  20013. last; // last object information {scope, element, index}
  20014. if (!isArray(collection)) {
  20015. // if object, extract keys, sort them and use to determine order of iteration over obj props
  20016. array = [];
  20017. for(key in collection) {
  20018. if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
  20019. array.push(key);
  20020. }
  20021. }
  20022. array.sort();
  20023. } else {
  20024. array = collection || [];
  20025. }
  20026. arrayBound = array.length-1;
  20027. // we are not using forEach for perf reasons (trying to avoid #call)
  20028. for (index = 0, length = array.length; index < length; index++) {
  20029. key = (collection === array) ? index : array[index];
  20030. value = collection[key];
  20031. last = lastOrder.shift(value);
  20032. if (last) {
  20033. // if we have already seen this object, then we need to reuse the
  20034. // associated scope/element
  20035. childScope = last.scope;
  20036. nextOrder.push(value, last);
  20037. if (index === last.index) {
  20038. // do nothing
  20039. cursor = last.element;
  20040. } else {
  20041. // existing item which got moved
  20042. last.index = index;
  20043. // This may be a noop, if the element is next, but I don't know of a good way to
  20044. // figure this out, since it would require extra DOM access, so let's just hope that
  20045. // the browsers realizes that it is noop, and treats it as such.
  20046. cursor.after(last.element);
  20047. cursor = last.element;
  20048. }
  20049. } else {
  20050. // new item which we don't know about
  20051. childScope = scope.$new();
  20052. }
  20053. childScope[valueIdent] = value;
  20054. if (keyIdent) childScope[keyIdent] = key;
  20055. childScope.$index = index;
  20056. childScope.$first = (index === 0);
  20057. childScope.$last = (index === arrayBound);
  20058. childScope.$middle = !(childScope.$first || childScope.$last);
  20059. if (!last) {
  20060. linker(childScope, function(clone){
  20061. cursor.after(clone);
  20062. last = {
  20063. scope: childScope,
  20064. element: (cursor = clone),
  20065. index: index
  20066. };
  20067. nextOrder.push(value, last);
  20068. });
  20069. }
  20070. }
  20071. //shrink children
  20072. for (key in lastOrder) {
  20073. if (lastOrder.hasOwnProperty(key)) {
  20074. array = lastOrder[key];
  20075. while(array.length) {
  20076. value = array.pop();
  20077. value.element.remove();
  20078. value.scope.$destroy();
  20079. }
  20080. }
  20081. }
  20082. lastOrder = nextOrder;
  20083. });
  20084. };
  20085. }
  20086. });
  20087. /**
  20088. * @ngdoc directive
  20089. * @name ng.directive:ngShow
  20090. *
  20091. * @description
  20092. * The `ngShow` and `ngHide` directives show or hide a portion of the DOM tree (HTML)
  20093. * conditionally.
  20094. *
  20095. * @element ANY
  20096. * @param {expression} ngShow If the {@link guide/expression expression} is truthy
  20097. * then the element is shown or hidden respectively.
  20098. *
  20099. * @example
  20100. <doc:example>
  20101. <doc:source>
  20102. Click me: <input type="checkbox" ng-model="checked"><br/>
  20103. Show: <span ng-show="checked">I show up when your checkbox is checked.</span> <br/>
  20104. Hide: <span ng-hide="checked">I hide when your checkbox is checked.</span>
  20105. </doc:source>
  20106. <doc:scenario>
  20107. it('should check ng-show / ng-hide', function() {
  20108. expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
  20109. expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
  20110. input('checked').check();
  20111. expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
  20112. expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
  20113. });
  20114. </doc:scenario>
  20115. </doc:example>
  20116. */
  20117. //TODO(misko): refactor to remove element from the DOM
  20118. var ngShowDirective = ngDirective(function(scope, element, attr){
  20119. scope.$watch(attr.ngShow, function ngShowWatchAction(value){
  20120. element.css('display', toBoolean(value) ? '' : 'none');
  20121. });
  20122. });
  20123. /**
  20124. * @ngdoc directive
  20125. * @name ng.directive:ngHide
  20126. *
  20127. * @description
  20128. * The `ngHide` and `ngShow` directives hide or show a portion of the DOM tree (HTML)
  20129. * conditionally.
  20130. *
  20131. * @element ANY
  20132. * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
  20133. * the element is shown or hidden respectively.
  20134. *
  20135. * @example
  20136. <doc:example>
  20137. <doc:source>
  20138. Click me: <input type="checkbox" ng-model="checked"><br/>
  20139. Show: <span ng-show="checked">I show up when you checkbox is checked?</span> <br/>
  20140. Hide: <span ng-hide="checked">I hide when you checkbox is checked?</span>
  20141. </doc:source>
  20142. <doc:scenario>
  20143. it('should check ng-show / ng-hide', function() {
  20144. expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
  20145. expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
  20146. input('checked').check();
  20147. expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
  20148. expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
  20149. });
  20150. </doc:scenario>
  20151. </doc:example>
  20152. */
  20153. //TODO(misko): refactor to remove element from the DOM
  20154. var ngHideDirective = ngDirective(function(scope, element, attr){
  20155. scope.$watch(attr.ngHide, function ngHideWatchAction(value){
  20156. element.css('display', toBoolean(value) ? 'none' : '');
  20157. });
  20158. });
  20159. /**
  20160. * @ngdoc directive
  20161. * @name ng.directive:ngStyle
  20162. *
  20163. * @description
  20164. * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
  20165. *
  20166. * @element ANY
  20167. * @param {expression} ngStyle {@link guide/expression Expression} which evals to an
  20168. * object whose keys are CSS style names and values are corresponding values for those CSS
  20169. * keys.
  20170. *
  20171. * @example
  20172. <example>
  20173. <file name="index.html">
  20174. <input type="button" value="set" ng-click="myStyle={color:'red'}">
  20175. <input type="button" value="clear" ng-click="myStyle={}">
  20176. <br/>
  20177. <span ng-style="myStyle">Sample Text</span>
  20178. <pre>myStyle={{myStyle}}</pre>
  20179. </file>
  20180. <file name="style.css">
  20181. span {
  20182. color: black;
  20183. }
  20184. </file>
  20185. <file name="scenario.js">
  20186. it('should check ng-style', function() {
  20187. expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
  20188. element('.doc-example-live :button[value=set]').click();
  20189. expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)');
  20190. element('.doc-example-live :button[value=clear]').click();
  20191. expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
  20192. });
  20193. </file>
  20194. </example>
  20195. */
  20196. var ngStyleDirective = ngDirective(function(scope, element, attr) {
  20197. scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
  20198. if (oldStyles && (newStyles !== oldStyles)) {
  20199. forEach(oldStyles, function(val, style) { element.css(style, '');});
  20200. }
  20201. if (newStyles) element.css(newStyles);
  20202. }, true);
  20203. });
  20204. /**
  20205. * @ngdoc directive
  20206. * @name ng.directive:ngSwitch
  20207. * @restrict EA
  20208. *
  20209. * @description
  20210. * Conditionally change the DOM structure.
  20211. *
  20212. * @usage
  20213. * <ANY ng-switch="expression">
  20214. * <ANY ng-switch-when="matchValue1">...</ANY>
  20215. * <ANY ng-switch-when="matchValue2">...</ANY>
  20216. * ...
  20217. * <ANY ng-switch-default>...</ANY>
  20218. * </ANY>
  20219. *
  20220. * @scope
  20221. * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
  20222. * @paramDescription
  20223. * On child elments add:
  20224. *
  20225. * * `ngSwitchWhen`: the case statement to match against. If match then this
  20226. * case will be displayed.
  20227. * * `ngSwitchDefault`: the default case when no other casses match.
  20228. *
  20229. * @example
  20230. <doc:example>
  20231. <doc:source>
  20232. <script>
  20233. function Ctrl($scope) {
  20234. $scope.items = ['settings', 'home', 'other'];
  20235. $scope.selection = $scope.items[0];
  20236. }
  20237. </script>
  20238. <div ng-controller="Ctrl">
  20239. <select ng-model="selection" ng-options="item for item in items">
  20240. </select>
  20241. <tt>selection={{selection}}</tt>
  20242. <hr/>
  20243. <div ng-switch on="selection" >
  20244. <div ng-switch-when="settings">Settings Div</div>
  20245. <span ng-switch-when="home">Home Span</span>
  20246. <span ng-switch-default>default</span>
  20247. </div>
  20248. </div>
  20249. </doc:source>
  20250. <doc:scenario>
  20251. it('should start in settings', function() {
  20252. expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
  20253. });
  20254. it('should change to home', function() {
  20255. select('selection').option('home');
  20256. expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/);
  20257. });
  20258. it('should select deafault', function() {
  20259. select('selection').option('other');
  20260. expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/);
  20261. });
  20262. </doc:scenario>
  20263. </doc:example>
  20264. */
  20265. var NG_SWITCH = 'ng-switch';
  20266. var ngSwitchDirective = valueFn({
  20267. restrict: 'EA',
  20268. require: 'ngSwitch',
  20269. // asks for $scope to fool the BC controller module
  20270. controller: ['$scope', function ngSwitchController() {
  20271. this.cases = {};
  20272. }],
  20273. link: function(scope, element, attr, ctrl) {
  20274. var watchExpr = attr.ngSwitch || attr.on,
  20275. selectedTransclude,
  20276. selectedElement,
  20277. selectedScope;
  20278. scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
  20279. if (selectedElement) {
  20280. selectedScope.$destroy();
  20281. selectedElement.remove();
  20282. selectedElement = selectedScope = null;
  20283. }
  20284. if ((selectedTransclude = ctrl.cases['!' + value] || ctrl.cases['?'])) {
  20285. scope.$eval(attr.change);
  20286. selectedScope = scope.$new();
  20287. selectedTransclude(selectedScope, function(caseElement) {
  20288. selectedElement = caseElement;
  20289. element.append(caseElement);
  20290. });
  20291. }
  20292. });
  20293. }
  20294. });
  20295. var ngSwitchWhenDirective = ngDirective({
  20296. transclude: 'element',
  20297. priority: 500,
  20298. require: '^ngSwitch',
  20299. compile: function(element, attrs, transclude) {
  20300. return function(scope, element, attr, ctrl) {
  20301. ctrl.cases['!' + attrs.ngSwitchWhen] = transclude;
  20302. };
  20303. }
  20304. });
  20305. var ngSwitchDefaultDirective = ngDirective({
  20306. transclude: 'element',
  20307. priority: 500,
  20308. require: '^ngSwitch',
  20309. compile: function(element, attrs, transclude) {
  20310. return function(scope, element, attr, ctrl) {
  20311. ctrl.cases['?'] = transclude;
  20312. };
  20313. }
  20314. });
  20315. /**
  20316. * @ngdoc directive
  20317. * @name ng.directive:ngTransclude
  20318. *
  20319. * @description
  20320. * Insert the transcluded DOM here.
  20321. *
  20322. * @element ANY
  20323. *
  20324. * @example
  20325. <doc:example module="transclude">
  20326. <doc:source>
  20327. <script>
  20328. function Ctrl($scope) {
  20329. $scope.title = 'Lorem Ipsum';
  20330. $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
  20331. }
  20332. angular.module('transclude', [])
  20333. .directive('pane', function(){
  20334. return {
  20335. restrict: 'E',
  20336. transclude: true,
  20337. scope: 'isolate',
  20338. locals: { title:'bind' },
  20339. template: '<div style="border: 1px solid black;">' +
  20340. '<div style="background-color: gray">{{title}}</div>' +
  20341. '<div ng-transclude></div>' +
  20342. '</div>'
  20343. };
  20344. });
  20345. </script>
  20346. <div ng-controller="Ctrl">
  20347. <input ng-model="title"><br>
  20348. <textarea ng-model="text"></textarea> <br/>
  20349. <pane title="{{title}}">{{text}}</pane>
  20350. </div>
  20351. </doc:source>
  20352. <doc:scenario>
  20353. it('should have transcluded', function() {
  20354. input('title').enter('TITLE');
  20355. input('text').enter('TEXT');
  20356. expect(binding('title')).toEqual('TITLE');
  20357. expect(binding('text')).toEqual('TEXT');
  20358. });
  20359. </doc:scenario>
  20360. </doc:example>
  20361. *
  20362. */
  20363. var ngTranscludeDirective = ngDirective({
  20364. controller: ['$transclude', '$element', function($transclude, $element) {
  20365. $transclude(function(clone) {
  20366. $element.append(clone);
  20367. });
  20368. }]
  20369. });
  20370. /**
  20371. * @ngdoc directive
  20372. * @name ng.directive:ngView
  20373. * @restrict ECA
  20374. *
  20375. * @description
  20376. * # Overview
  20377. * `ngView` is a directive that complements the {@link ng.$route $route} service by
  20378. * including the rendered template of the current route into the main layout (`index.html`) file.
  20379. * Every time the current route changes, the included view changes with it according to the
  20380. * configuration of the `$route` service.
  20381. *
  20382. * @scope
  20383. * @example
  20384. <example module="ngView">
  20385. <file name="index.html">
  20386. <div ng-controller="MainCntl">
  20387. Choose:
  20388. <a href="Book/Moby">Moby</a> |
  20389. <a href="Book/Moby/ch/1">Moby: Ch1</a> |
  20390. <a href="Book/Gatsby">Gatsby</a> |
  20391. <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
  20392. <a href="Book/Scarlet">Scarlet Letter</a><br/>
  20393. <div ng-view></div>
  20394. <hr />
  20395. <pre>$location.path() = {{$location.path()}}</pre>
  20396. <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
  20397. <pre>$route.current.params = {{$route.current.params}}</pre>
  20398. <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
  20399. <pre>$routeParams = {{$routeParams}}</pre>
  20400. </div>
  20401. </file>
  20402. <file name="book.html">
  20403. controller: {{name}}<br />
  20404. Book Id: {{params.bookId}}<br />
  20405. </file>
  20406. <file name="chapter.html">
  20407. controller: {{name}}<br />
  20408. Book Id: {{params.bookId}}<br />
  20409. Chapter Id: {{params.chapterId}}
  20410. </file>
  20411. <file name="script.js">
  20412. angular.module('ngView', [], function($routeProvider, $locationProvider) {
  20413. $routeProvider.when('/Book/:bookId', {
  20414. templateUrl: 'book.html',
  20415. controller: BookCntl
  20416. });
  20417. $routeProvider.when('/Book/:bookId/ch/:chapterId', {
  20418. templateUrl: 'chapter.html',
  20419. controller: ChapterCntl
  20420. });
  20421. // configure html5 to get links working on jsfiddle
  20422. $locationProvider.html5Mode(true);
  20423. });
  20424. function MainCntl($scope, $route, $routeParams, $location) {
  20425. $scope.$route = $route;
  20426. $scope.$location = $location;
  20427. $scope.$routeParams = $routeParams;
  20428. }
  20429. function BookCntl($scope, $routeParams) {
  20430. $scope.name = "BookCntl";
  20431. $scope.params = $routeParams;
  20432. }
  20433. function ChapterCntl($scope, $routeParams) {
  20434. $scope.name = "ChapterCntl";
  20435. $scope.params = $routeParams;
  20436. }
  20437. </file>
  20438. <file name="scenario.js">
  20439. it('should load and compile correct template', function() {
  20440. element('a:contains("Moby: Ch1")').click();
  20441. var content = element('.doc-example-live [ng-view]').text();
  20442. expect(content).toMatch(/controller\: ChapterCntl/);
  20443. expect(content).toMatch(/Book Id\: Moby/);
  20444. expect(content).toMatch(/Chapter Id\: 1/);
  20445. element('a:contains("Scarlet")').click();
  20446. content = element('.doc-example-live [ng-view]').text();
  20447. expect(content).toMatch(/controller\: BookCntl/);
  20448. expect(content).toMatch(/Book Id\: Scarlet/);
  20449. });
  20450. </file>
  20451. </example>
  20452. */
  20453. /**
  20454. * @ngdoc event
  20455. * @name ng.directive:ngView#$viewContentLoaded
  20456. * @eventOf ng.directive:ngView
  20457. * @eventType emit on the current ngView scope
  20458. * @description
  20459. * Emitted every time the ngView content is reloaded.
  20460. */
  20461. var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$compile',
  20462. '$controller',
  20463. function($http, $templateCache, $route, $anchorScroll, $compile,
  20464. $controller) {
  20465. return {
  20466. restrict: 'ECA',
  20467. terminal: true,
  20468. link: function(scope, element, attr) {
  20469. var lastScope,
  20470. onloadExp = attr.onload || '';
  20471. scope.$on('$routeChangeSuccess', update);
  20472. update();
  20473. function destroyLastScope() {
  20474. if (lastScope) {
  20475. lastScope.$destroy();
  20476. lastScope = null;
  20477. }
  20478. }
  20479. function clearContent() {
  20480. element.html('');
  20481. destroyLastScope();
  20482. }
  20483. function update() {
  20484. var locals = $route.current && $route.current.locals,
  20485. template = locals && locals.$template;
  20486. if (template) {
  20487. element.html(template);
  20488. destroyLastScope();
  20489. var link = $compile(element.contents()),
  20490. current = $route.current,
  20491. controller;
  20492. lastScope = current.scope = scope.$new();
  20493. if (current.controller) {
  20494. locals.$scope = lastScope;
  20495. controller = $controller(current.controller, locals);
  20496. element.children().data('$ngControllerController', controller);
  20497. }
  20498. link(lastScope);
  20499. lastScope.$emit('$viewContentLoaded');
  20500. lastScope.$eval(onloadExp);
  20501. // $anchorScroll might listen on event...
  20502. $anchorScroll();
  20503. } else {
  20504. clearContent();
  20505. }
  20506. }
  20507. }
  20508. };
  20509. }];
  20510. /**
  20511. * @ngdoc directive
  20512. * @name ng.directive:script
  20513. *
  20514. * @description
  20515. * Load content of a script tag, with type `text/ng-template`, into `$templateCache`, so that the
  20516. * template can be used by `ngInclude`, `ngView` or directive templates.
  20517. *
  20518. * @restrict E
  20519. * @param {'text/ng-template'} type must be set to `'text/ng-template'`
  20520. *
  20521. * @example
  20522. <doc:example>
  20523. <doc:source>
  20524. <script type="text/ng-template" id="/tpl.html">
  20525. Content of the template.
  20526. </script>
  20527. <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
  20528. <div id="tpl-content" ng-include src="currentTpl"></div>
  20529. </doc:source>
  20530. <doc:scenario>
  20531. it('should load template defined inside script tag', function() {
  20532. element('#tpl-link').click();
  20533. expect(element('#tpl-content').text()).toMatch(/Content of the template/);
  20534. });
  20535. </doc:scenario>
  20536. </doc:example>
  20537. */
  20538. var scriptDirective = ['$templateCache', function($templateCache) {
  20539. return {
  20540. restrict: 'E',
  20541. terminal: true,
  20542. compile: function(element, attr) {
  20543. if (attr.type == 'text/ng-template') {
  20544. var templateUrl = attr.id,
  20545. // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
  20546. text = element[0].text;
  20547. $templateCache.put(templateUrl, text);
  20548. }
  20549. }
  20550. };
  20551. }];
  20552. /**
  20553. * @ngdoc directive
  20554. * @name ng.directive:select
  20555. * @restrict E
  20556. *
  20557. * @description
  20558. * HTML `SELECT` element with angular data-binding.
  20559. *
  20560. * # `ngOptions`
  20561. *
  20562. * Optionally `ngOptions` attribute can be used to dynamically generate a list of `<option>`
  20563. * elements for a `<select>` element using an array or an object obtained by evaluating the
  20564. * `ngOptions` expression.
  20565. *˝˝
  20566. * When an item in the select menu is select, the value of array element or object property
  20567. * represented by the selected option will be bound to the model identified by the `ngModel`
  20568. * directive of the parent select element.
  20569. *
  20570. * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
  20571. * be nested into the `<select>` element. This element will then represent `null` or "not selected"
  20572. * option. See example below for demonstration.
  20573. *
  20574. * Note: `ngOptions` provides iterator facility for `<option>` element which should be used instead
  20575. * of {@link ng.directive:ngRepeat ngRepeat} when you want the
  20576. * `select` model to be bound to a non-string value. This is because an option element can currently
  20577. * be bound to string values only.
  20578. *
  20579. * @param {string} name assignable expression to data-bind to.
  20580. * @param {string=} required The control is considered valid only if value is entered.
  20581. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
  20582. * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
  20583. * `required` when you want to data-bind to the `required` attribute.
  20584. * @param {comprehension_expression=} ngOptions in one of the following forms:
  20585. *
  20586. * * for array data sources:
  20587. * * `label` **`for`** `value` **`in`** `array`
  20588. * * `select` **`as`** `label` **`for`** `value` **`in`** `array`
  20589. * * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
  20590. * * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array`
  20591. * * for object data sources:
  20592. * * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
  20593. * * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
  20594. * * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
  20595. * * `select` **`as`** `label` **`group by`** `group`
  20596. * **`for` `(`**`key`**`,`** `value`**`) in`** `object`
  20597. *
  20598. * Where:
  20599. *
  20600. * * `array` / `object`: an expression which evaluates to an array / object to iterate over.
  20601. * * `value`: local variable which will refer to each item in the `array` or each property value
  20602. * of `object` during iteration.
  20603. * * `key`: local variable which will refer to a property name in `object` during iteration.
  20604. * * `label`: The result of this expression will be the label for `<option>` element. The
  20605. * `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
  20606. * * `select`: The result of this expression will be bound to the model of the parent `<select>`
  20607. * element. If not specified, `select` expression will default to `value`.
  20608. * * `group`: The result of this expression will be used to group options using the `<optgroup>`
  20609. * DOM element.
  20610. *
  20611. * @example
  20612. <doc:example>
  20613. <doc:source>
  20614. <script>
  20615. function MyCntrl($scope) {
  20616. $scope.colors = [
  20617. {name:'black', shade:'dark'},
  20618. {name:'white', shade:'light'},
  20619. {name:'red', shade:'dark'},
  20620. {name:'blue', shade:'dark'},
  20621. {name:'yellow', shade:'light'}
  20622. ];
  20623. $scope.color = $scope.colors[2]; // red
  20624. }
  20625. </script>
  20626. <div ng-controller="MyCntrl">
  20627. <ul>
  20628. <li ng-repeat="color in colors">
  20629. Name: <input ng-model="color.name">
  20630. [<a href ng-click="colors.splice($index, 1)">X</a>]
  20631. </li>
  20632. <li>
  20633. [<a href ng-click="colors.push({})">add</a>]
  20634. </li>
  20635. </ul>
  20636. <hr/>
  20637. Color (null not allowed):
  20638. <select ng-model="color" ng-options="c.name for c in colors"></select><br>
  20639. Color (null allowed):
  20640. <span class="nullable">
  20641. <select ng-model="color" ng-options="c.name for c in colors">
  20642. <option value="">-- chose color --</option>
  20643. </select>
  20644. </span><br/>
  20645. Color grouped by shade:
  20646. <select ng-model="color" ng-options="c.name group by c.shade for c in colors">
  20647. </select><br/>
  20648. Select <a href ng-click="color={name:'not in list'}">bogus</a>.<br>
  20649. <hr/>
  20650. Currently selected: {{ {selected_color:color} }}
  20651. <div style="border:solid 1px black; height:20px"
  20652. ng-style="{'background-color':color.name}">
  20653. </div>
  20654. </div>
  20655. </doc:source>
  20656. <doc:scenario>
  20657. it('should check ng-options', function() {
  20658. expect(binding('{selected_color:color}')).toMatch('red');
  20659. select('color').option('0');
  20660. expect(binding('{selected_color:color}')).toMatch('black');
  20661. using('.nullable').select('color').option('');
  20662. expect(binding('{selected_color:color}')).toMatch('null');
  20663. });
  20664. </doc:scenario>
  20665. </doc:example>
  20666. */
  20667. var ngOptionsDirective = valueFn({ terminal: true });
  20668. var selectDirective = ['$compile', '$parse', function($compile, $parse) {
  20669. //0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000077770
  20670. var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/,
  20671. nullModelCtrl = {$setViewValue: noop};
  20672. return {
  20673. restrict: 'E',
  20674. require: ['select', '?ngModel'],
  20675. controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
  20676. var self = this,
  20677. optionsMap = {},
  20678. ngModelCtrl = nullModelCtrl,
  20679. nullOption,
  20680. unknownOption;
  20681. self.databound = $attrs.ngModel;
  20682. self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
  20683. ngModelCtrl = ngModelCtrl_;
  20684. nullOption = nullOption_;
  20685. unknownOption = unknownOption_;
  20686. }
  20687. self.addOption = function(value) {
  20688. optionsMap[value] = true;
  20689. if (ngModelCtrl.$viewValue == value) {
  20690. $element.val(value);
  20691. if (unknownOption.parent()) unknownOption.remove();
  20692. }
  20693. };
  20694. self.removeOption = function(value) {
  20695. if (this.hasOption(value)) {
  20696. delete optionsMap[value];
  20697. if (ngModelCtrl.$viewValue == value) {
  20698. this.renderUnknownOption(value);
  20699. }
  20700. }
  20701. };
  20702. self.renderUnknownOption = function(val) {
  20703. var unknownVal = '? ' + hashKey(val) + ' ?';
  20704. unknownOption.val(unknownVal);
  20705. $element.prepend(unknownOption);
  20706. $element.val(unknownVal);
  20707. unknownOption.prop('selected', true); // needed for IE
  20708. }
  20709. self.hasOption = function(value) {
  20710. return optionsMap.hasOwnProperty(value);
  20711. }
  20712. $scope.$on('$destroy', function() {
  20713. // disable unknown option so that we don't do work when the whole select is being destroyed
  20714. self.renderUnknownOption = noop;
  20715. });
  20716. }],
  20717. link: function(scope, element, attr, ctrls) {
  20718. // if ngModel is not defined, we don't need to do anything
  20719. if (!ctrls[1]) return;
  20720. var selectCtrl = ctrls[0],
  20721. ngModelCtrl = ctrls[1],
  20722. multiple = attr.multiple,
  20723. optionsExp = attr.ngOptions,
  20724. nullOption = false, // if false, user will not be able to select it (used by ngOptions)
  20725. emptyOption,
  20726. // we can't just jqLite('<option>') since jqLite is not smart enough
  20727. // to create it in <select> and IE barfs otherwise.
  20728. optionTemplate = jqLite(document.createElement('option')),
  20729. optGroupTemplate =jqLite(document.createElement('optgroup')),
  20730. unknownOption = optionTemplate.clone();
  20731. // find "null" option
  20732. for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
  20733. if (children[i].value == '') {
  20734. emptyOption = nullOption = children.eq(i);
  20735. break;
  20736. }
  20737. }
  20738. selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
  20739. // required validator
  20740. if (multiple && (attr.required || attr.ngRequired)) {
  20741. var requiredValidator = function(value) {
  20742. ngModelCtrl.$setValidity('required', !attr.required || (value && value.length));
  20743. return value;
  20744. };
  20745. ngModelCtrl.$parsers.push(requiredValidator);
  20746. ngModelCtrl.$formatters.unshift(requiredValidator);
  20747. attr.$observe('required', function() {
  20748. requiredValidator(ngModelCtrl.$viewValue);
  20749. });
  20750. }
  20751. if (optionsExp) Options(scope, element, ngModelCtrl);
  20752. else if (multiple) Multiple(scope, element, ngModelCtrl);
  20753. else Single(scope, element, ngModelCtrl, selectCtrl);
  20754. ////////////////////////////
  20755. function Single(scope, selectElement, ngModelCtrl, selectCtrl) {
  20756. ngModelCtrl.$render = function() {
  20757. var viewValue = ngModelCtrl.$viewValue;
  20758. if (selectCtrl.hasOption(viewValue)) {
  20759. if (unknownOption.parent()) unknownOption.remove();
  20760. selectElement.val(viewValue);
  20761. if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
  20762. } else {
  20763. if (isUndefined(viewValue) && emptyOption) {
  20764. selectElement.val('');
  20765. } else {
  20766. selectCtrl.renderUnknownOption(viewValue);
  20767. }
  20768. }
  20769. };
  20770. selectElement.bind('change', function() {
  20771. scope.$apply(function() {
  20772. if (unknownOption.parent()) unknownOption.remove();
  20773. ngModelCtrl.$setViewValue(selectElement.val());
  20774. });
  20775. });
  20776. }
  20777. function Multiple(scope, selectElement, ctrl) {
  20778. var lastView;
  20779. ctrl.$render = function() {
  20780. var items = new HashMap(ctrl.$viewValue);
  20781. forEach(selectElement.find('option'), function(option) {
  20782. option.selected = isDefined(items.get(option.value));
  20783. });
  20784. };
  20785. // we have to do it on each watch since ngModel watches reference, but
  20786. // we need to work of an array, so we need to see if anything was inserted/removed
  20787. scope.$watch(function selectMultipleWatch() {
  20788. if (!equals(lastView, ctrl.$viewValue)) {
  20789. lastView = copy(ctrl.$viewValue);
  20790. ctrl.$render();
  20791. }
  20792. });
  20793. selectElement.bind('change', function() {
  20794. scope.$apply(function() {
  20795. var array = [];
  20796. forEach(selectElement.find('option'), function(option) {
  20797. if (option.selected) {
  20798. array.push(option.value);
  20799. }
  20800. });
  20801. ctrl.$setViewValue(array);
  20802. });
  20803. });
  20804. }
  20805. function Options(scope, selectElement, ctrl) {
  20806. var match;
  20807. if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
  20808. throw Error(
  20809. "Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
  20810. " but got '" + optionsExp + "'.");
  20811. }
  20812. var displayFn = $parse(match[2] || match[1]),
  20813. valueName = match[4] || match[6],
  20814. keyName = match[5],
  20815. groupByFn = $parse(match[3] || ''),
  20816. valueFn = $parse(match[2] ? match[1] : valueName),
  20817. valuesFn = $parse(match[7]),
  20818. // This is an array of array of existing option groups in DOM. We try to reuse these if possible
  20819. // optionGroupsCache[0] is the options with no option group
  20820. // optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
  20821. optionGroupsCache = [[{element: selectElement, label:''}]];
  20822. if (nullOption) {
  20823. // compile the element since there might be bindings in it
  20824. $compile(nullOption)(scope);
  20825. // remove the class, which is added automatically because we recompile the element and it
  20826. // becomes the compilation root
  20827. nullOption.removeClass('ng-scope');
  20828. // we need to remove it before calling selectElement.html('') because otherwise IE will
  20829. // remove the label from the element. wtf?
  20830. nullOption.remove();
  20831. }
  20832. // clear contents, we'll add what's needed based on the model
  20833. selectElement.html('');
  20834. selectElement.bind('change', function() {
  20835. scope.$apply(function() {
  20836. var optionGroup,
  20837. collection = valuesFn(scope) || [],
  20838. locals = {},
  20839. key, value, optionElement, index, groupIndex, length, groupLength;
  20840. if (multiple) {
  20841. value = [];
  20842. for (groupIndex = 0, groupLength = optionGroupsCache.length;
  20843. groupIndex < groupLength;
  20844. groupIndex++) {
  20845. // list of options for that group. (first item has the parent)
  20846. optionGroup = optionGroupsCache[groupIndex];
  20847. for(index = 1, length = optionGroup.length; index < length; index++) {
  20848. if ((optionElement = optionGroup[index].element)[0].selected) {
  20849. key = optionElement.val();
  20850. if (keyName) locals[keyName] = key;
  20851. locals[valueName] = collection[key];
  20852. value.push(valueFn(scope, locals));
  20853. }
  20854. }
  20855. }
  20856. } else {
  20857. key = selectElement.val();
  20858. if (key == '?') {
  20859. value = undefined;
  20860. } else if (key == ''){
  20861. value = null;
  20862. } else {
  20863. locals[valueName] = collection[key];
  20864. if (keyName) locals[keyName] = key;
  20865. value = valueFn(scope, locals);
  20866. }
  20867. }
  20868. ctrl.$setViewValue(value);
  20869. });
  20870. });
  20871. ctrl.$render = render;
  20872. // TODO(vojta): can't we optimize this ?
  20873. scope.$watch(render);
  20874. function render() {
  20875. var optionGroups = {'':[]}, // Temporary location for the option groups before we render them
  20876. optionGroupNames = [''],
  20877. optionGroupName,
  20878. optionGroup,
  20879. option,
  20880. existingParent, existingOptions, existingOption,
  20881. modelValue = ctrl.$modelValue,
  20882. values = valuesFn(scope) || [],
  20883. keys = keyName ? sortedKeys(values) : values,
  20884. groupLength, length,
  20885. groupIndex, index,
  20886. locals = {},
  20887. selected,
  20888. selectedSet = false, // nothing is selected yet
  20889. lastElement,
  20890. element,
  20891. label;
  20892. if (multiple) {
  20893. selectedSet = new HashMap(modelValue);
  20894. } else if (modelValue === null || nullOption) {
  20895. // if we are not multiselect, and we are null then we have to add the nullOption
  20896. optionGroups[''].push({selected:modelValue === null, id:'', label:''});
  20897. selectedSet = true;
  20898. }
  20899. // We now build up the list of options we need (we merge later)
  20900. for (index = 0; length = keys.length, index < length; index++) {
  20901. locals[valueName] = values[keyName ? locals[keyName]=keys[index]:index];
  20902. optionGroupName = groupByFn(scope, locals) || '';
  20903. if (!(optionGroup = optionGroups[optionGroupName])) {
  20904. optionGroup = optionGroups[optionGroupName] = [];
  20905. optionGroupNames.push(optionGroupName);
  20906. }
  20907. if (multiple) {
  20908. selected = selectedSet.remove(valueFn(scope, locals)) != undefined;
  20909. } else {
  20910. selected = modelValue === valueFn(scope, locals);
  20911. selectedSet = selectedSet || selected; // see if at least one item is selected
  20912. }
  20913. label = displayFn(scope, locals); // what will be seen by the user
  20914. label = label === undefined ? '' : label; // doing displayFn(scope, locals) || '' overwrites zero values
  20915. optionGroup.push({
  20916. id: keyName ? keys[index] : index, // either the index into array or key from object
  20917. label: label,
  20918. selected: selected // determine if we should be selected
  20919. });
  20920. }
  20921. if (!multiple && !selectedSet) {
  20922. // nothing was selected, we have to insert the undefined item
  20923. optionGroups[''].unshift({id:'?', label:'', selected:true});
  20924. }
  20925. // Now we need to update the list of DOM nodes to match the optionGroups we computed above
  20926. for (groupIndex = 0, groupLength = optionGroupNames.length;
  20927. groupIndex < groupLength;
  20928. groupIndex++) {
  20929. // current option group name or '' if no group
  20930. optionGroupName = optionGroupNames[groupIndex];
  20931. // list of options for that group. (first item has the parent)
  20932. optionGroup = optionGroups[optionGroupName];
  20933. if (optionGroupsCache.length <= groupIndex) {
  20934. // we need to grow the optionGroups
  20935. existingParent = {
  20936. element: optGroupTemplate.clone().attr('label', optionGroupName),
  20937. label: optionGroup.label
  20938. };
  20939. existingOptions = [existingParent];
  20940. optionGroupsCache.push(existingOptions);
  20941. selectElement.append(existingParent.element);
  20942. } else {
  20943. existingOptions = optionGroupsCache[groupIndex];
  20944. existingParent = existingOptions[0]; // either SELECT (no group) or OPTGROUP element
  20945. // update the OPTGROUP label if not the same.
  20946. if (existingParent.label != optionGroupName) {
  20947. existingParent.element.attr('label', existingParent.label = optionGroupName);
  20948. }
  20949. }
  20950. lastElement = null; // start at the beginning
  20951. for(index = 0, length = optionGroup.length; index < length; index++) {
  20952. option = optionGroup[index];
  20953. if ((existingOption = existingOptions[index+1])) {
  20954. // reuse elements
  20955. lastElement = existingOption.element;
  20956. if (existingOption.label !== option.label) {
  20957. lastElement.text(existingOption.label = option.label);
  20958. }
  20959. if (existingOption.id !== option.id) {
  20960. lastElement.val(existingOption.id = option.id);
  20961. }
  20962. if (existingOption.element.selected !== option.selected) {
  20963. lastElement.prop('selected', (existingOption.selected = option.selected));
  20964. }
  20965. } else {
  20966. // grow elements
  20967. // if it's a null option
  20968. if (option.id === '' && nullOption) {
  20969. // put back the pre-compiled element
  20970. element = nullOption;
  20971. } else {
  20972. // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
  20973. // in this version of jQuery on some browser the .text() returns a string
  20974. // rather then the element.
  20975. (element = optionTemplate.clone())
  20976. .val(option.id)
  20977. .attr('selected', option.selected)
  20978. .text(option.label);
  20979. }
  20980. existingOptions.push(existingOption = {
  20981. element: element,
  20982. label: option.label,
  20983. id: option.id,
  20984. selected: option.selected
  20985. });
  20986. if (lastElement) {
  20987. lastElement.after(element);
  20988. } else {
  20989. existingParent.element.append(element);
  20990. }
  20991. lastElement = element;
  20992. }
  20993. }
  20994. // remove any excessive OPTIONs in a group
  20995. index++; // increment since the existingOptions[0] is parent element not OPTION
  20996. while(existingOptions.length > index) {
  20997. existingOptions.pop().element.remove();
  20998. }
  20999. }
  21000. // remove any excessive OPTGROUPs from select
  21001. while(optionGroupsCache.length > groupIndex) {
  21002. optionGroupsCache.pop()[0].element.remove();
  21003. }
  21004. }
  21005. }
  21006. }
  21007. }
  21008. }];
  21009. var optionDirective = ['$interpolate', function($interpolate) {
  21010. var nullSelectCtrl = {
  21011. addOption: noop,
  21012. removeOption: noop
  21013. };
  21014. return {
  21015. restrict: 'E',
  21016. priority: 100,
  21017. compile: function(element, attr) {
  21018. if (isUndefined(attr.value)) {
  21019. var interpolateFn = $interpolate(element.text(), true);
  21020. if (!interpolateFn) {
  21021. attr.$set('value', element.text());
  21022. }
  21023. }
  21024. return function (scope, element, attr) {
  21025. var selectCtrlName = '$selectController',
  21026. parent = element.parent(),
  21027. selectCtrl = parent.data(selectCtrlName) ||
  21028. parent.parent().data(selectCtrlName); // in case we are in optgroup
  21029. if (selectCtrl && selectCtrl.databound) {
  21030. // For some reason Opera defaults to true and if not overridden this messes up the repeater.
  21031. // We don't want the view to drive the initialization of the model anyway.
  21032. element.prop('selected', false);
  21033. } else {
  21034. selectCtrl = nullSelectCtrl;
  21035. }
  21036. if (interpolateFn) {
  21037. scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
  21038. attr.$set('value', newVal);
  21039. if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
  21040. selectCtrl.addOption(newVal);
  21041. });
  21042. } else {
  21043. selectCtrl.addOption(attr.value);
  21044. }
  21045. element.bind('$destroy', function() {
  21046. selectCtrl.removeOption(attr.value);
  21047. });
  21048. };
  21049. }
  21050. }
  21051. }];
  21052. var styleDirective = valueFn({
  21053. restrict: 'E',
  21054. terminal: true
  21055. });
  21056. /**
  21057. * Setup file for the Scenario.
  21058. * Must be first in the compilation/bootstrap list.
  21059. */
  21060. // Public namespace
  21061. angular.scenario = angular.scenario || {};
  21062. /**
  21063. * Defines a new output format.
  21064. *
  21065. * @param {string} name the name of the new output format
  21066. * @param {function()} fn function(context, runner) that generates the output
  21067. */
  21068. angular.scenario.output = angular.scenario.output || function(name, fn) {
  21069. angular.scenario.output[name] = fn;
  21070. };
  21071. /**
  21072. * Defines a new DSL statement. If your factory function returns a Future
  21073. * it's returned, otherwise the result is assumed to be a map of functions
  21074. * for chaining. Chained functions are subject to the same rules.
  21075. *
  21076. * Note: All functions on the chain are bound to the chain scope so values
  21077. * set on "this" in your statement function are available in the chained
  21078. * functions.
  21079. *
  21080. * @param {string} name The name of the statement
  21081. * @param {function()} fn Factory function(), return a function for
  21082. * the statement.
  21083. */
  21084. angular.scenario.dsl = angular.scenario.dsl || function(name, fn) {
  21085. angular.scenario.dsl[name] = function() {
  21086. function executeStatement(statement, args) {
  21087. var result = statement.apply(this, args);
  21088. if (angular.isFunction(result) || result instanceof angular.scenario.Future)
  21089. return result;
  21090. var self = this;
  21091. var chain = angular.extend({}, result);
  21092. angular.forEach(chain, function(value, name) {
  21093. if (angular.isFunction(value)) {
  21094. chain[name] = function() {
  21095. return executeStatement.call(self, value, arguments);
  21096. };
  21097. } else {
  21098. chain[name] = value;
  21099. }
  21100. });
  21101. return chain;
  21102. }
  21103. var statement = fn.apply(this, arguments);
  21104. return function() {
  21105. return executeStatement.call(this, statement, arguments);
  21106. };
  21107. };
  21108. };
  21109. /**
  21110. * Defines a new matcher for use with the expects() statement. The value
  21111. * this.actual (like in Jasmine) is available in your matcher to compare
  21112. * against. Your function should return a boolean. The future is automatically
  21113. * created for you.
  21114. *
  21115. * @param {string} name The name of the matcher
  21116. * @param {function()} fn The matching function(expected).
  21117. */
  21118. angular.scenario.matcher = angular.scenario.matcher || function(name, fn) {
  21119. angular.scenario.matcher[name] = function(expected) {
  21120. var prefix = 'expect ' + this.future.name + ' ';
  21121. if (this.inverse) {
  21122. prefix += 'not ';
  21123. }
  21124. var self = this;
  21125. this.addFuture(prefix + name + ' ' + angular.toJson(expected),
  21126. function(done) {
  21127. var error;
  21128. self.actual = self.future.value;
  21129. if ((self.inverse && fn.call(self, expected)) ||
  21130. (!self.inverse && !fn.call(self, expected))) {
  21131. error = 'expected ' + angular.toJson(expected) +
  21132. ' but was ' + angular.toJson(self.actual);
  21133. }
  21134. done(error);
  21135. });
  21136. };
  21137. };
  21138. /**
  21139. * Initialize the scenario runner and run !
  21140. *
  21141. * Access global window and document object
  21142. * Access $runner through closure
  21143. *
  21144. * @param {Object=} config Config options
  21145. */
  21146. angular.scenario.setUpAndRun = function(config) {
  21147. var href = window.location.href;
  21148. var body = _jQuery(document.body);
  21149. var output = [];
  21150. var objModel = new angular.scenario.ObjectModel($runner);
  21151. if (config && config.scenario_output) {
  21152. output = config.scenario_output.split(',');
  21153. }
  21154. angular.forEach(angular.scenario.output, function(fn, name) {
  21155. if (!output.length || indexOf(output,name) != -1) {
  21156. var context = body.append('<div></div>').find('div:last');
  21157. context.attr('id', name);
  21158. fn.call({}, context, $runner, objModel);
  21159. }
  21160. });
  21161. if (!/^http/.test(href) && !/^https/.test(href)) {
  21162. body.append('<p id="system-error"></p>');
  21163. body.find('#system-error').text(
  21164. 'Scenario runner must be run using http or https. The protocol ' +
  21165. href.split(':')[0] + ':// is not supported.'
  21166. );
  21167. return;
  21168. }
  21169. var appFrame = body.append('<div id="application"></div>').find('#application');
  21170. var application = new angular.scenario.Application(appFrame);
  21171. $runner.on('RunnerEnd', function() {
  21172. appFrame.css('display', 'none');
  21173. appFrame.find('iframe').attr('src', 'about:blank');
  21174. });
  21175. $runner.on('RunnerError', function(error) {
  21176. if (window.console) {
  21177. console.log(formatException(error));
  21178. } else {
  21179. // Do something for IE
  21180. alert(error);
  21181. }
  21182. });
  21183. $runner.run(application);
  21184. };
  21185. /**
  21186. * Iterates through list with iterator function that must call the
  21187. * continueFunction to continute iterating.
  21188. *
  21189. * @param {Array} list list to iterate over
  21190. * @param {function()} iterator Callback function(value, continueFunction)
  21191. * @param {function()} done Callback function(error, result) called when
  21192. * iteration finishes or an error occurs.
  21193. */
  21194. function asyncForEach(list, iterator, done) {
  21195. var i = 0;
  21196. function loop(error, index) {
  21197. if (index && index > i) {
  21198. i = index;
  21199. }
  21200. if (error || i >= list.length) {
  21201. done(error);
  21202. } else {
  21203. try {
  21204. iterator(list[i++], loop);
  21205. } catch (e) {
  21206. done(e);
  21207. }
  21208. }
  21209. }
  21210. loop();
  21211. }
  21212. /**
  21213. * Formats an exception into a string with the stack trace, but limits
  21214. * to a specific line length.
  21215. *
  21216. * @param {Object} error The exception to format, can be anything throwable
  21217. * @param {Number=} [maxStackLines=5] max lines of the stack trace to include
  21218. * default is 5.
  21219. */
  21220. function formatException(error, maxStackLines) {
  21221. maxStackLines = maxStackLines || 5;
  21222. var message = error.toString();
  21223. if (error.stack) {
  21224. var stack = error.stack.split('\n');
  21225. if (stack[0].indexOf(message) === -1) {
  21226. maxStackLines++;
  21227. stack.unshift(error.message);
  21228. }
  21229. message = stack.slice(0, maxStackLines).join('\n');
  21230. }
  21231. return message;
  21232. }
  21233. /**
  21234. * Returns a function that gets the file name and line number from a
  21235. * location in the stack if available based on the call site.
  21236. *
  21237. * Note: this returns another function because accessing .stack is very
  21238. * expensive in Chrome.
  21239. *
  21240. * @param {Number} offset Number of stack lines to skip
  21241. */
  21242. function callerFile(offset) {
  21243. var error = new Error();
  21244. return function() {
  21245. var line = (error.stack || '').split('\n')[offset];
  21246. // Clean up the stack trace line
  21247. if (line) {
  21248. if (line.indexOf('@') !== -1) {
  21249. // Firefox
  21250. line = line.substring(line.indexOf('@')+1);
  21251. } else {
  21252. // Chrome
  21253. line = line.substring(line.indexOf('(')+1).replace(')', '');
  21254. }
  21255. }
  21256. return line || '';
  21257. };
  21258. }
  21259. /**
  21260. * Triggers a browser event. Attempts to choose the right event if one is
  21261. * not specified.
  21262. *
  21263. * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
  21264. * @param {string} type Optional event type.
  21265. * @param {Array.<string>=} keys Optional list of pressed keys
  21266. * (valid values: 'alt', 'meta', 'shift', 'ctrl')
  21267. */
  21268. function browserTrigger(element, type, keys) {
  21269. if (element && !element.nodeName) element = element[0];
  21270. if (!element) return;
  21271. if (!type) {
  21272. type = {
  21273. 'text': 'change',
  21274. 'textarea': 'change',
  21275. 'hidden': 'change',
  21276. 'password': 'change',
  21277. 'button': 'click',
  21278. 'submit': 'click',
  21279. 'reset': 'click',
  21280. 'image': 'click',
  21281. 'checkbox': 'click',
  21282. 'radio': 'click',
  21283. 'select-one': 'change',
  21284. 'select-multiple': 'change'
  21285. }[lowercase(element.type)] || 'click';
  21286. }
  21287. if (lowercase(nodeName_(element)) == 'option') {
  21288. element.parentNode.value = element.value;
  21289. element = element.parentNode;
  21290. type = 'change';
  21291. }
  21292. keys = keys || [];
  21293. function pressed(key) {
  21294. return indexOf(keys, key) !== -1;
  21295. }
  21296. if (msie < 9) {
  21297. switch(element.type) {
  21298. case 'radio':
  21299. case 'checkbox':
  21300. element.checked = !element.checked;
  21301. break;
  21302. }
  21303. // WTF!!! Error: Unspecified error.
  21304. // Don't know why, but some elements when detached seem to be in inconsistent state and
  21305. // calling .fireEvent() on them will result in very unhelpful error (Error: Unspecified error)
  21306. // forcing the browser to compute the element position (by reading its CSS)
  21307. // puts the element in consistent state.
  21308. element.style.posLeft;
  21309. // TODO(vojta): create event objects with pressed keys to get it working on IE<9
  21310. var ret = element.fireEvent('on' + type);
  21311. if (lowercase(element.type) == 'submit') {
  21312. while(element) {
  21313. if (lowercase(element.nodeName) == 'form') {
  21314. element.fireEvent('onsubmit');
  21315. break;
  21316. }
  21317. element = element.parentNode;
  21318. }
  21319. }
  21320. return ret;
  21321. } else {
  21322. var evnt = document.createEvent('MouseEvents'),
  21323. originalPreventDefault = evnt.preventDefault,
  21324. iframe = _jQuery('#application iframe')[0],
  21325. appWindow = iframe ? iframe.contentWindow : window,
  21326. fakeProcessDefault = true,
  21327. finalProcessDefault,
  21328. angular = appWindow.angular || {};
  21329. // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
  21330. angular['ff-684208-preventDefault'] = false;
  21331. evnt.preventDefault = function() {
  21332. fakeProcessDefault = false;
  21333. return originalPreventDefault.apply(evnt, arguments);
  21334. };
  21335. evnt.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, pressed('ctrl'), pressed('alt'),
  21336. pressed('shift'), pressed('meta'), 0, element);
  21337. element.dispatchEvent(evnt);
  21338. finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
  21339. delete angular['ff-684208-preventDefault'];
  21340. return finalProcessDefault;
  21341. }
  21342. }
  21343. /**
  21344. * Don't use the jQuery trigger method since it works incorrectly.
  21345. *
  21346. * jQuery notifies listeners and then changes the state of a checkbox and
  21347. * does not create a real browser event. A real click changes the state of
  21348. * the checkbox and then notifies listeners.
  21349. *
  21350. * To work around this we instead use our own handler that fires a real event.
  21351. */
  21352. (function(fn){
  21353. var parentTrigger = fn.trigger;
  21354. fn.trigger = function(type) {
  21355. if (/(click|change|keydown|blur|input)/.test(type)) {
  21356. var processDefaults = [];
  21357. this.each(function(index, node) {
  21358. processDefaults.push(browserTrigger(node, type));
  21359. });
  21360. // this is not compatible with jQuery - we return an array of returned values,
  21361. // so that scenario runner know whether JS code has preventDefault() of the event or not...
  21362. return processDefaults;
  21363. }
  21364. return parentTrigger.apply(this, arguments);
  21365. };
  21366. })(_jQuery.fn);
  21367. /**
  21368. * Finds all bindings with the substring match of name and returns an
  21369. * array of their values.
  21370. *
  21371. * @param {string} bindExp The name to match
  21372. * @return {Array.<string>} String of binding values
  21373. */
  21374. _jQuery.fn.bindings = function(windowJquery, bindExp) {
  21375. var result = [], match,
  21376. bindSelector = '.ng-binding:visible';
  21377. if (angular.isString(bindExp)) {
  21378. bindExp = bindExp.replace(/\s/g, '');
  21379. match = function (actualExp) {
  21380. if (actualExp) {
  21381. actualExp = actualExp.replace(/\s/g, '');
  21382. if (actualExp == bindExp) return true;
  21383. if (actualExp.indexOf(bindExp) == 0) {
  21384. return actualExp.charAt(bindExp.length) == '|';
  21385. }
  21386. }
  21387. }
  21388. } else if (bindExp) {
  21389. match = function(actualExp) {
  21390. return actualExp && bindExp.exec(actualExp);
  21391. }
  21392. } else {
  21393. match = function(actualExp) {
  21394. return !!actualExp;
  21395. };
  21396. }
  21397. var selection = this.find(bindSelector);
  21398. if (this.is(bindSelector)) {
  21399. selection = selection.add(this);
  21400. }
  21401. function push(value) {
  21402. if (value == undefined) {
  21403. value = '';
  21404. } else if (typeof value != 'string') {
  21405. value = angular.toJson(value);
  21406. }
  21407. result.push('' + value);
  21408. }
  21409. selection.each(function() {
  21410. var element = windowJquery(this),
  21411. binding;
  21412. if (binding = element.data('$binding')) {
  21413. if (typeof binding == 'string') {
  21414. if (match(binding)) {
  21415. push(element.scope().$eval(binding));
  21416. }
  21417. } else {
  21418. if (!angular.isArray(binding)) {
  21419. binding = [binding];
  21420. }
  21421. for(var fns, j=0, jj=binding.length; j<jj; j++) {
  21422. fns = binding[j];
  21423. if (fns.parts) {
  21424. fns = fns.parts;
  21425. } else {
  21426. fns = [fns];
  21427. }
  21428. for (var scope, fn, i = 0, ii = fns.length; i < ii; i++) {
  21429. if(match((fn = fns[i]).exp)) {
  21430. push(fn(scope = scope || element.scope()));
  21431. }
  21432. }
  21433. }
  21434. }
  21435. }
  21436. });
  21437. return result;
  21438. };
  21439. /**
  21440. * Represents the application currently being tested and abstracts usage
  21441. * of iframes or separate windows.
  21442. *
  21443. * @param {Object} context jQuery wrapper around HTML context.
  21444. */
  21445. angular.scenario.Application = function(context) {
  21446. this.context = context;
  21447. context.append(
  21448. '<h2>Current URL: <a href="about:blank">None</a></h2>' +
  21449. '<div id="test-frames"></div>'
  21450. );
  21451. };
  21452. /**
  21453. * Gets the jQuery collection of frames. Don't use this directly because
  21454. * frames may go stale.
  21455. *
  21456. * @private
  21457. * @return {Object} jQuery collection
  21458. */
  21459. angular.scenario.Application.prototype.getFrame_ = function() {
  21460. return this.context.find('#test-frames iframe:last');
  21461. };
  21462. /**
  21463. * Gets the window of the test runner frame. Always favor executeAction()
  21464. * instead of this method since it prevents you from getting a stale window.
  21465. *
  21466. * @private
  21467. * @return {Object} the window of the frame
  21468. */
  21469. angular.scenario.Application.prototype.getWindow_ = function() {
  21470. var contentWindow = this.getFrame_().prop('contentWindow');
  21471. if (!contentWindow)
  21472. throw 'Frame window is not accessible.';
  21473. return contentWindow;
  21474. };
  21475. /**
  21476. * Changes the location of the frame.
  21477. *
  21478. * @param {string} url The URL. If it begins with a # then only the
  21479. * hash of the page is changed.
  21480. * @param {function()} loadFn function($window, $document) Called when frame loads.
  21481. * @param {function()} errorFn function(error) Called if any error when loading.
  21482. */
  21483. angular.scenario.Application.prototype.navigateTo = function(url, loadFn, errorFn) {
  21484. var self = this;
  21485. var frame = this.getFrame_();
  21486. //TODO(esprehn): Refactor to use rethrow()
  21487. errorFn = errorFn || function(e) { throw e; };
  21488. if (url === 'about:blank') {
  21489. errorFn('Sandbox Error: Navigating to about:blank is not allowed.');
  21490. } else if (url.charAt(0) === '#') {
  21491. url = frame.attr('src').split('#')[0] + url;
  21492. frame.attr('src', url);
  21493. this.executeAction(loadFn);
  21494. } else {
  21495. frame.remove();
  21496. this.context.find('#test-frames').append('<iframe>');
  21497. frame = this.getFrame_();
  21498. frame.load(function() {
  21499. frame.unbind();
  21500. try {
  21501. self.executeAction(loadFn);
  21502. } catch (e) {
  21503. errorFn(e);
  21504. }
  21505. }).attr('src', url);
  21506. }
  21507. this.context.find('> h2 a').attr('href', url).text(url);
  21508. };
  21509. /**
  21510. * Executes a function in the context of the tested application. Will wait
  21511. * for all pending angular xhr requests before executing.
  21512. *
  21513. * @param {function()} action The callback to execute. function($window, $document)
  21514. * $document is a jQuery wrapped document.
  21515. */
  21516. angular.scenario.Application.prototype.executeAction = function(action) {
  21517. var self = this;
  21518. var $window = this.getWindow_();
  21519. if (!$window.document) {
  21520. throw 'Sandbox Error: Application document not accessible.';
  21521. }
  21522. if (!$window.angular) {
  21523. return action.call(this, $window, _jQuery($window.document));
  21524. }
  21525. angularInit($window.document, function(element) {
  21526. var $injector = $window.angular.element(element).injector();
  21527. var $element = _jQuery(element);
  21528. $element.injector = function() {
  21529. return $injector;
  21530. };
  21531. $injector.invoke(function($browser){
  21532. $browser.notifyWhenNoOutstandingRequests(function() {
  21533. action.call(self, $window, $element);
  21534. });
  21535. });
  21536. });
  21537. };
  21538. /**
  21539. * The representation of define blocks. Don't used directly, instead use
  21540. * define() in your tests.
  21541. *
  21542. * @param {string} descName Name of the block
  21543. * @param {Object} parent describe or undefined if the root.
  21544. */
  21545. angular.scenario.Describe = function(descName, parent) {
  21546. this.only = parent && parent.only;
  21547. this.beforeEachFns = [];
  21548. this.afterEachFns = [];
  21549. this.its = [];
  21550. this.children = [];
  21551. this.name = descName;
  21552. this.parent = parent;
  21553. this.id = angular.scenario.Describe.id++;
  21554. /**
  21555. * Calls all before functions.
  21556. */
  21557. var beforeEachFns = this.beforeEachFns;
  21558. this.setupBefore = function() {
  21559. if (parent) parent.setupBefore.call(this);
  21560. angular.forEach(beforeEachFns, function(fn) { fn.call(this); }, this);
  21561. };
  21562. /**
  21563. * Calls all after functions.
  21564. */
  21565. var afterEachFns = this.afterEachFns;
  21566. this.setupAfter = function() {
  21567. angular.forEach(afterEachFns, function(fn) { fn.call(this); }, this);
  21568. if (parent) parent.setupAfter.call(this);
  21569. };
  21570. };
  21571. // Shared Unique ID generator for every describe block
  21572. angular.scenario.Describe.id = 0;
  21573. // Shared Unique ID generator for every it (spec)
  21574. angular.scenario.Describe.specId = 0;
  21575. /**
  21576. * Defines a block to execute before each it or nested describe.
  21577. *
  21578. * @param {function()} body Body of the block.
  21579. */
  21580. angular.scenario.Describe.prototype.beforeEach = function(body) {
  21581. this.beforeEachFns.push(body);
  21582. };
  21583. /**
  21584. * Defines a block to execute after each it or nested describe.
  21585. *
  21586. * @param {function()} body Body of the block.
  21587. */
  21588. angular.scenario.Describe.prototype.afterEach = function(body) {
  21589. this.afterEachFns.push(body);
  21590. };
  21591. /**
  21592. * Creates a new describe block that's a child of this one.
  21593. *
  21594. * @param {string} name Name of the block. Appended to the parent block's name.
  21595. * @param {function()} body Body of the block.
  21596. */
  21597. angular.scenario.Describe.prototype.describe = function(name, body) {
  21598. var child = new angular.scenario.Describe(name, this);
  21599. this.children.push(child);
  21600. body.call(child);
  21601. };
  21602. /**
  21603. * Same as describe() but makes ddescribe blocks the only to run.
  21604. *
  21605. * @param {string} name Name of the test.
  21606. * @param {function()} body Body of the block.
  21607. */
  21608. angular.scenario.Describe.prototype.ddescribe = function(name, body) {
  21609. var child = new angular.scenario.Describe(name, this);
  21610. child.only = true;
  21611. this.children.push(child);
  21612. body.call(child);
  21613. };
  21614. /**
  21615. * Use to disable a describe block.
  21616. */
  21617. angular.scenario.Describe.prototype.xdescribe = angular.noop;
  21618. /**
  21619. * Defines a test.
  21620. *
  21621. * @param {string} name Name of the test.
  21622. * @param {function()} vody Body of the block.
  21623. */
  21624. angular.scenario.Describe.prototype.it = function(name, body) {
  21625. this.its.push({
  21626. id: angular.scenario.Describe.specId++,
  21627. definition: this,
  21628. only: this.only,
  21629. name: name,
  21630. before: this.setupBefore,
  21631. body: body,
  21632. after: this.setupAfter
  21633. });
  21634. };
  21635. /**
  21636. * Same as it() but makes iit tests the only test to run.
  21637. *
  21638. * @param {string} name Name of the test.
  21639. * @param {function()} body Body of the block.
  21640. */
  21641. angular.scenario.Describe.prototype.iit = function(name, body) {
  21642. this.it.apply(this, arguments);
  21643. this.its[this.its.length-1].only = true;
  21644. };
  21645. /**
  21646. * Use to disable a test block.
  21647. */
  21648. angular.scenario.Describe.prototype.xit = angular.noop;
  21649. /**
  21650. * Gets an array of functions representing all the tests (recursively).
  21651. * that can be executed with SpecRunner's.
  21652. *
  21653. * @return {Array<Object>} Array of it blocks {
  21654. * definition : Object // parent Describe
  21655. * only: boolean
  21656. * name: string
  21657. * before: Function
  21658. * body: Function
  21659. * after: Function
  21660. * }
  21661. */
  21662. angular.scenario.Describe.prototype.getSpecs = function() {
  21663. var specs = arguments[0] || [];
  21664. angular.forEach(this.children, function(child) {
  21665. child.getSpecs(specs);
  21666. });
  21667. angular.forEach(this.its, function(it) {
  21668. specs.push(it);
  21669. });
  21670. var only = [];
  21671. angular.forEach(specs, function(it) {
  21672. if (it.only) {
  21673. only.push(it);
  21674. }
  21675. });
  21676. return (only.length && only) || specs;
  21677. };
  21678. /**
  21679. * A future action in a spec.
  21680. *
  21681. * @param {string} name of the future action
  21682. * @param {function()} future callback(error, result)
  21683. * @param {function()} Optional. function that returns the file/line number.
  21684. */
  21685. angular.scenario.Future = function(name, behavior, line) {
  21686. this.name = name;
  21687. this.behavior = behavior;
  21688. this.fulfilled = false;
  21689. this.value = undefined;
  21690. this.parser = angular.identity;
  21691. this.line = line || function() { return ''; };
  21692. };
  21693. /**
  21694. * Executes the behavior of the closure.
  21695. *
  21696. * @param {function()} doneFn Callback function(error, result)
  21697. */
  21698. angular.scenario.Future.prototype.execute = function(doneFn) {
  21699. var self = this;
  21700. this.behavior(function(error, result) {
  21701. self.fulfilled = true;
  21702. if (result) {
  21703. try {
  21704. result = self.parser(result);
  21705. } catch(e) {
  21706. error = e;
  21707. }
  21708. }
  21709. self.value = error || result;
  21710. doneFn(error, result);
  21711. });
  21712. };
  21713. /**
  21714. * Configures the future to convert it's final with a function fn(value)
  21715. *
  21716. * @param {function()} fn function(value) that returns the parsed value
  21717. */
  21718. angular.scenario.Future.prototype.parsedWith = function(fn) {
  21719. this.parser = fn;
  21720. return this;
  21721. };
  21722. /**
  21723. * Configures the future to parse it's final value from JSON
  21724. * into objects.
  21725. */
  21726. angular.scenario.Future.prototype.fromJson = function() {
  21727. return this.parsedWith(angular.fromJson);
  21728. };
  21729. /**
  21730. * Configures the future to convert it's final value from objects
  21731. * into JSON.
  21732. */
  21733. angular.scenario.Future.prototype.toJson = function() {
  21734. return this.parsedWith(angular.toJson);
  21735. };
  21736. /**
  21737. * Maintains an object tree from the runner events.
  21738. *
  21739. * @param {Object} runner The scenario Runner instance to connect to.
  21740. *
  21741. * TODO(esprehn): Every output type creates one of these, but we probably
  21742. * want one global shared instance. Need to handle events better too
  21743. * so the HTML output doesn't need to do spec model.getSpec(spec.id)
  21744. * silliness.
  21745. *
  21746. * TODO(vojta) refactor on, emit methods (from all objects) - use inheritance
  21747. */
  21748. angular.scenario.ObjectModel = function(runner) {
  21749. var self = this;
  21750. this.specMap = {};
  21751. this.listeners = [];
  21752. this.value = {
  21753. name: '',
  21754. children: {}
  21755. };
  21756. runner.on('SpecBegin', function(spec) {
  21757. var block = self.value,
  21758. definitions = [];
  21759. angular.forEach(self.getDefinitionPath(spec), function(def) {
  21760. if (!block.children[def.name]) {
  21761. block.children[def.name] = {
  21762. id: def.id,
  21763. name: def.name,
  21764. children: {},
  21765. specs: {}
  21766. };
  21767. }
  21768. block = block.children[def.name];
  21769. definitions.push(def.name);
  21770. });
  21771. var it = self.specMap[spec.id] =
  21772. block.specs[spec.name] =
  21773. new angular.scenario.ObjectModel.Spec(spec.id, spec.name, definitions);
  21774. // forward the event
  21775. self.emit('SpecBegin', it);
  21776. });
  21777. runner.on('SpecError', function(spec, error) {
  21778. var it = self.getSpec(spec.id);
  21779. it.status = 'error';
  21780. it.error = error;
  21781. // forward the event
  21782. self.emit('SpecError', it, error);
  21783. });
  21784. runner.on('SpecEnd', function(spec) {
  21785. var it = self.getSpec(spec.id);
  21786. complete(it);
  21787. // forward the event
  21788. self.emit('SpecEnd', it);
  21789. });
  21790. runner.on('StepBegin', function(spec, step) {
  21791. var it = self.getSpec(spec.id);
  21792. var step = new angular.scenario.ObjectModel.Step(step.name);
  21793. it.steps.push(step);
  21794. // forward the event
  21795. self.emit('StepBegin', it, step);
  21796. });
  21797. runner.on('StepEnd', function(spec) {
  21798. var it = self.getSpec(spec.id);
  21799. var step = it.getLastStep();
  21800. if (step.name !== step.name)
  21801. throw 'Events fired in the wrong order. Step names don\'t match.';
  21802. complete(step);
  21803. // forward the event
  21804. self.emit('StepEnd', it, step);
  21805. });
  21806. runner.on('StepFailure', function(spec, step, error) {
  21807. var it = self.getSpec(spec.id),
  21808. modelStep = it.getLastStep();
  21809. modelStep.setErrorStatus('failure', error, step.line());
  21810. it.setStatusFromStep(modelStep);
  21811. // forward the event
  21812. self.emit('StepFailure', it, modelStep, error);
  21813. });
  21814. runner.on('StepError', function(spec, step, error) {
  21815. var it = self.getSpec(spec.id),
  21816. modelStep = it.getLastStep();
  21817. modelStep.setErrorStatus('error', error, step.line());
  21818. it.setStatusFromStep(modelStep);
  21819. // forward the event
  21820. self.emit('StepError', it, modelStep, error);
  21821. });
  21822. runner.on('RunnerBegin', function() {
  21823. self.emit('RunnerBegin');
  21824. });
  21825. runner.on('RunnerEnd', function() {
  21826. self.emit('RunnerEnd');
  21827. });
  21828. function complete(item) {
  21829. item.endTime = new Date().getTime();
  21830. item.duration = item.endTime - item.startTime;
  21831. item.status = item.status || 'success';
  21832. }
  21833. };
  21834. /**
  21835. * Adds a listener for an event.
  21836. *
  21837. * @param {string} eventName Name of the event to add a handler for
  21838. * @param {function()} listener Function that will be called when event is fired
  21839. */
  21840. angular.scenario.ObjectModel.prototype.on = function(eventName, listener) {
  21841. eventName = eventName.toLowerCase();
  21842. this.listeners[eventName] = this.listeners[eventName] || [];
  21843. this.listeners[eventName].push(listener);
  21844. };
  21845. /**
  21846. * Emits an event which notifies listeners and passes extra
  21847. * arguments.
  21848. *
  21849. * @param {string} eventName Name of the event to fire.
  21850. */
  21851. angular.scenario.ObjectModel.prototype.emit = function(eventName) {
  21852. var self = this,
  21853. args = Array.prototype.slice.call(arguments, 1),
  21854. eventName = eventName.toLowerCase();
  21855. if (this.listeners[eventName]) {
  21856. angular.forEach(this.listeners[eventName], function(listener) {
  21857. listener.apply(self, args);
  21858. });
  21859. }
  21860. };
  21861. /**
  21862. * Computes the path of definition describe blocks that wrap around
  21863. * this spec.
  21864. *
  21865. * @param spec Spec to compute the path for.
  21866. * @return {Array<Describe>} The describe block path
  21867. */
  21868. angular.scenario.ObjectModel.prototype.getDefinitionPath = function(spec) {
  21869. var path = [];
  21870. var currentDefinition = spec.definition;
  21871. while (currentDefinition && currentDefinition.name) {
  21872. path.unshift(currentDefinition);
  21873. currentDefinition = currentDefinition.parent;
  21874. }
  21875. return path;
  21876. };
  21877. /**
  21878. * Gets a spec by id.
  21879. *
  21880. * @param {string} The id of the spec to get the object for.
  21881. * @return {Object} the Spec instance
  21882. */
  21883. angular.scenario.ObjectModel.prototype.getSpec = function(id) {
  21884. return this.specMap[id];
  21885. };
  21886. /**
  21887. * A single it block.
  21888. *
  21889. * @param {string} id Id of the spec
  21890. * @param {string} name Name of the spec
  21891. * @param {Array<string>=} definitionNames List of all describe block names that wrap this spec
  21892. */
  21893. angular.scenario.ObjectModel.Spec = function(id, name, definitionNames) {
  21894. this.id = id;
  21895. this.name = name;
  21896. this.startTime = new Date().getTime();
  21897. this.steps = [];
  21898. this.fullDefinitionName = (definitionNames || []).join(' ');
  21899. };
  21900. /**
  21901. * Adds a new step to the Spec.
  21902. *
  21903. * @param {string} step Name of the step (really name of the future)
  21904. * @return {Object} the added step
  21905. */
  21906. angular.scenario.ObjectModel.Spec.prototype.addStep = function(name) {
  21907. var step = new angular.scenario.ObjectModel.Step(name);
  21908. this.steps.push(step);
  21909. return step;
  21910. };
  21911. /**
  21912. * Gets the most recent step.
  21913. *
  21914. * @return {Object} the step
  21915. */
  21916. angular.scenario.ObjectModel.Spec.prototype.getLastStep = function() {
  21917. return this.steps[this.steps.length-1];
  21918. };
  21919. /**
  21920. * Set status of the Spec from given Step
  21921. *
  21922. * @param {angular.scenario.ObjectModel.Step} step
  21923. */
  21924. angular.scenario.ObjectModel.Spec.prototype.setStatusFromStep = function(step) {
  21925. if (!this.status || step.status == 'error') {
  21926. this.status = step.status;
  21927. this.error = step.error;
  21928. this.line = step.line;
  21929. }
  21930. };
  21931. /**
  21932. * A single step inside a Spec.
  21933. *
  21934. * @param {string} step Name of the step
  21935. */
  21936. angular.scenario.ObjectModel.Step = function(name) {
  21937. this.name = name;
  21938. this.startTime = new Date().getTime();
  21939. };
  21940. /**
  21941. * Helper method for setting all error status related properties
  21942. *
  21943. * @param {string} status
  21944. * @param {string} error
  21945. * @param {string} line
  21946. */
  21947. angular.scenario.ObjectModel.Step.prototype.setErrorStatus = function(status, error, line) {
  21948. this.status = status;
  21949. this.error = error;
  21950. this.line = line;
  21951. };
  21952. /**
  21953. * Runner for scenarios
  21954. *
  21955. * Has to be initialized before any test is loaded,
  21956. * because it publishes the API into window (global space).
  21957. */
  21958. angular.scenario.Runner = function($window) {
  21959. this.listeners = [];
  21960. this.$window = $window;
  21961. this.rootDescribe = new angular.scenario.Describe();
  21962. this.currentDescribe = this.rootDescribe;
  21963. this.api = {
  21964. it: this.it,
  21965. iit: this.iit,
  21966. xit: angular.noop,
  21967. describe: this.describe,
  21968. ddescribe: this.ddescribe,
  21969. xdescribe: angular.noop,
  21970. beforeEach: this.beforeEach,
  21971. afterEach: this.afterEach
  21972. };
  21973. angular.forEach(this.api, angular.bind(this, function(fn, key) {
  21974. this.$window[key] = angular.bind(this, fn);
  21975. }));
  21976. };
  21977. /**
  21978. * Emits an event which notifies listeners and passes extra
  21979. * arguments.
  21980. *
  21981. * @param {string} eventName Name of the event to fire.
  21982. */
  21983. angular.scenario.Runner.prototype.emit = function(eventName) {
  21984. var self = this;
  21985. var args = Array.prototype.slice.call(arguments, 1);
  21986. eventName = eventName.toLowerCase();
  21987. if (!this.listeners[eventName])
  21988. return;
  21989. angular.forEach(this.listeners[eventName], function(listener) {
  21990. listener.apply(self, args);
  21991. });
  21992. };
  21993. /**
  21994. * Adds a listener for an event.
  21995. *
  21996. * @param {string} eventName The name of the event to add a handler for
  21997. * @param {string} listener The fn(...) that takes the extra arguments from emit()
  21998. */
  21999. angular.scenario.Runner.prototype.on = function(eventName, listener) {
  22000. eventName = eventName.toLowerCase();
  22001. this.listeners[eventName] = this.listeners[eventName] || [];
  22002. this.listeners[eventName].push(listener);
  22003. };
  22004. /**
  22005. * Defines a describe block of a spec.
  22006. *
  22007. * @see Describe.js
  22008. *
  22009. * @param {string} name Name of the block
  22010. * @param {function()} body Body of the block
  22011. */
  22012. angular.scenario.Runner.prototype.describe = function(name, body) {
  22013. var self = this;
  22014. this.currentDescribe.describe(name, function() {
  22015. var parentDescribe = self.currentDescribe;
  22016. self.currentDescribe = this;
  22017. try {
  22018. body.call(this);
  22019. } finally {
  22020. self.currentDescribe = parentDescribe;
  22021. }
  22022. });
  22023. };
  22024. /**
  22025. * Same as describe, but makes ddescribe the only blocks to run.
  22026. *
  22027. * @see Describe.js
  22028. *
  22029. * @param {string} name Name of the block
  22030. * @param {function()} body Body of the block
  22031. */
  22032. angular.scenario.Runner.prototype.ddescribe = function(name, body) {
  22033. var self = this;
  22034. this.currentDescribe.ddescribe(name, function() {
  22035. var parentDescribe = self.currentDescribe;
  22036. self.currentDescribe = this;
  22037. try {
  22038. body.call(this);
  22039. } finally {
  22040. self.currentDescribe = parentDescribe;
  22041. }
  22042. });
  22043. };
  22044. /**
  22045. * Defines a test in a describe block of a spec.
  22046. *
  22047. * @see Describe.js
  22048. *
  22049. * @param {string} name Name of the block
  22050. * @param {function()} body Body of the block
  22051. */
  22052. angular.scenario.Runner.prototype.it = function(name, body) {
  22053. this.currentDescribe.it(name, body);
  22054. };
  22055. /**
  22056. * Same as it, but makes iit tests the only tests to run.
  22057. *
  22058. * @see Describe.js
  22059. *
  22060. * @param {string} name Name of the block
  22061. * @param {function()} body Body of the block
  22062. */
  22063. angular.scenario.Runner.prototype.iit = function(name, body) {
  22064. this.currentDescribe.iit(name, body);
  22065. };
  22066. /**
  22067. * Defines a function to be called before each it block in the describe
  22068. * (and before all nested describes).
  22069. *
  22070. * @see Describe.js
  22071. *
  22072. * @param {function()} Callback to execute
  22073. */
  22074. angular.scenario.Runner.prototype.beforeEach = function(body) {
  22075. this.currentDescribe.beforeEach(body);
  22076. };
  22077. /**
  22078. * Defines a function to be called after each it block in the describe
  22079. * (and before all nested describes).
  22080. *
  22081. * @see Describe.js
  22082. *
  22083. * @param {function()} Callback to execute
  22084. */
  22085. angular.scenario.Runner.prototype.afterEach = function(body) {
  22086. this.currentDescribe.afterEach(body);
  22087. };
  22088. /**
  22089. * Creates a new spec runner.
  22090. *
  22091. * @private
  22092. * @param {Object} scope parent scope
  22093. */
  22094. angular.scenario.Runner.prototype.createSpecRunner_ = function(scope) {
  22095. var child = scope.$new();
  22096. var Cls = angular.scenario.SpecRunner;
  22097. // Export all the methods to child scope manually as now we don't mess controllers with scopes
  22098. // TODO(vojta): refactor scenario runner so that these objects are not tightly coupled as current
  22099. for (var name in Cls.prototype)
  22100. child[name] = angular.bind(child, Cls.prototype[name]);
  22101. Cls.call(child);
  22102. return child;
  22103. };
  22104. /**
  22105. * Runs all the loaded tests with the specified runner class on the
  22106. * provided application.
  22107. *
  22108. * @param {angular.scenario.Application} application App to remote control.
  22109. */
  22110. angular.scenario.Runner.prototype.run = function(application) {
  22111. var self = this;
  22112. var $root = angular.injector(['ng']).get('$rootScope');
  22113. angular.extend($root, this);
  22114. angular.forEach(angular.scenario.Runner.prototype, function(fn, name) {
  22115. $root[name] = angular.bind(self, fn);
  22116. });
  22117. $root.application = application;
  22118. $root.emit('RunnerBegin');
  22119. asyncForEach(this.rootDescribe.getSpecs(), function(spec, specDone) {
  22120. var dslCache = {};
  22121. var runner = self.createSpecRunner_($root);
  22122. angular.forEach(angular.scenario.dsl, function(fn, key) {
  22123. dslCache[key] = fn.call($root);
  22124. });
  22125. angular.forEach(angular.scenario.dsl, function(fn, key) {
  22126. self.$window[key] = function() {
  22127. var line = callerFile(3);
  22128. var scope = runner.$new();
  22129. // Make the dsl accessible on the current chain
  22130. scope.dsl = {};
  22131. angular.forEach(dslCache, function(fn, key) {
  22132. scope.dsl[key] = function() {
  22133. return dslCache[key].apply(scope, arguments);
  22134. };
  22135. });
  22136. // Make these methods work on the current chain
  22137. scope.addFuture = function() {
  22138. Array.prototype.push.call(arguments, line);
  22139. return angular.scenario.SpecRunner.
  22140. prototype.addFuture.apply(scope, arguments);
  22141. };
  22142. scope.addFutureAction = function() {
  22143. Array.prototype.push.call(arguments, line);
  22144. return angular.scenario.SpecRunner.
  22145. prototype.addFutureAction.apply(scope, arguments);
  22146. };
  22147. return scope.dsl[key].apply(scope, arguments);
  22148. };
  22149. });
  22150. runner.run(spec, function() {
  22151. runner.$destroy();
  22152. specDone.apply(this, arguments);
  22153. });
  22154. },
  22155. function(error) {
  22156. if (error) {
  22157. self.emit('RunnerError', error);
  22158. }
  22159. self.emit('RunnerEnd');
  22160. });
  22161. };
  22162. /**
  22163. * This class is the "this" of the it/beforeEach/afterEach method.
  22164. * Responsibilities:
  22165. * - "this" for it/beforeEach/afterEach
  22166. * - keep state for single it/beforeEach/afterEach execution
  22167. * - keep track of all of the futures to execute
  22168. * - run single spec (execute each future)
  22169. */
  22170. angular.scenario.SpecRunner = function() {
  22171. this.futures = [];
  22172. this.afterIndex = 0;
  22173. };
  22174. /**
  22175. * Executes a spec which is an it block with associated before/after functions
  22176. * based on the describe nesting.
  22177. *
  22178. * @param {Object} spec A spec object
  22179. * @param {function()} specDone function that is called when the spec finshes. Function(error, index)
  22180. */
  22181. angular.scenario.SpecRunner.prototype.run = function(spec, specDone) {
  22182. var self = this;
  22183. this.spec = spec;
  22184. this.emit('SpecBegin', spec);
  22185. try {
  22186. spec.before.call(this);
  22187. spec.body.call(this);
  22188. this.afterIndex = this.futures.length;
  22189. spec.after.call(this);
  22190. } catch (e) {
  22191. this.emit('SpecError', spec, e);
  22192. this.emit('SpecEnd', spec);
  22193. specDone();
  22194. return;
  22195. }
  22196. var handleError = function(error, done) {
  22197. if (self.error) {
  22198. return done();
  22199. }
  22200. self.error = true;
  22201. done(null, self.afterIndex);
  22202. };
  22203. asyncForEach(
  22204. this.futures,
  22205. function(future, futureDone) {
  22206. self.step = future;
  22207. self.emit('StepBegin', spec, future);
  22208. try {
  22209. future.execute(function(error) {
  22210. if (error) {
  22211. self.emit('StepFailure', spec, future, error);
  22212. self.emit('StepEnd', spec, future);
  22213. return handleError(error, futureDone);
  22214. }
  22215. self.emit('StepEnd', spec, future);
  22216. self.$window.setTimeout(function() { futureDone(); }, 0);
  22217. });
  22218. } catch (e) {
  22219. self.emit('StepError', spec, future, e);
  22220. self.emit('StepEnd', spec, future);
  22221. handleError(e, futureDone);
  22222. }
  22223. },
  22224. function(e) {
  22225. if (e) {
  22226. self.emit('SpecError', spec, e);
  22227. }
  22228. self.emit('SpecEnd', spec);
  22229. // Call done in a timeout so exceptions don't recursively
  22230. // call this function
  22231. self.$window.setTimeout(function() { specDone(); }, 0);
  22232. }
  22233. );
  22234. };
  22235. /**
  22236. * Adds a new future action.
  22237. *
  22238. * Note: Do not pass line manually. It happens automatically.
  22239. *
  22240. * @param {string} name Name of the future
  22241. * @param {function()} behavior Behavior of the future
  22242. * @param {function()} line fn() that returns file/line number
  22243. */
  22244. angular.scenario.SpecRunner.prototype.addFuture = function(name, behavior, line) {
  22245. var future = new angular.scenario.Future(name, angular.bind(this, behavior), line);
  22246. this.futures.push(future);
  22247. return future;
  22248. };
  22249. /**
  22250. * Adds a new future action to be executed on the application window.
  22251. *
  22252. * Note: Do not pass line manually. It happens automatically.
  22253. *
  22254. * @param {string} name Name of the future
  22255. * @param {function()} behavior Behavior of the future
  22256. * @param {function()} line fn() that returns file/line number
  22257. */
  22258. angular.scenario.SpecRunner.prototype.addFutureAction = function(name, behavior, line) {
  22259. var self = this;
  22260. var NG = /\[ng\\\:/;
  22261. return this.addFuture(name, function(done) {
  22262. this.application.executeAction(function($window, $document) {
  22263. //TODO(esprehn): Refactor this so it doesn't need to be in here.
  22264. $document.elements = function(selector) {
  22265. var args = Array.prototype.slice.call(arguments, 1);
  22266. selector = (self.selector || '') + ' ' + (selector || '');
  22267. selector = _jQuery.trim(selector) || '*';
  22268. angular.forEach(args, function(value, index) {
  22269. selector = selector.replace('$' + (index + 1), value);
  22270. });
  22271. var result = $document.find(selector);
  22272. if (selector.match(NG)) {
  22273. angular.forEach(['[ng-','[data-ng-','[x-ng-'], function(value, index){
  22274. result = result.add(selector.replace(NG, value), $document);
  22275. });
  22276. }
  22277. if (!result.length) {
  22278. throw {
  22279. type: 'selector',
  22280. message: 'Selector ' + selector + ' did not match any elements.'
  22281. };
  22282. }
  22283. return result;
  22284. };
  22285. try {
  22286. behavior.call(self, $window, $document, done);
  22287. } catch(e) {
  22288. if (e.type && e.type === 'selector') {
  22289. done(e.message);
  22290. } else {
  22291. throw e;
  22292. }
  22293. }
  22294. });
  22295. }, line);
  22296. };
  22297. /**
  22298. * Shared DSL statements that are useful to all scenarios.
  22299. */
  22300. /**
  22301. * Usage:
  22302. * pause() pauses until you call resume() in the console
  22303. */
  22304. angular.scenario.dsl('pause', function() {
  22305. return function() {
  22306. return this.addFuture('pausing for you to resume', function(done) {
  22307. this.emit('InteractivePause', this.spec, this.step);
  22308. this.$window.resume = function() { done(); };
  22309. });
  22310. };
  22311. });
  22312. /**
  22313. * Usage:
  22314. * sleep(seconds) pauses the test for specified number of seconds
  22315. */
  22316. angular.scenario.dsl('sleep', function() {
  22317. return function(time) {
  22318. return this.addFuture('sleep for ' + time + ' seconds', function(done) {
  22319. this.$window.setTimeout(function() { done(null, time * 1000); }, time * 1000);
  22320. });
  22321. };
  22322. });
  22323. /**
  22324. * Usage:
  22325. * browser().navigateTo(url) Loads the url into the frame
  22326. * browser().navigateTo(url, fn) where fn(url) is called and returns the URL to navigate to
  22327. * browser().reload() refresh the page (reload the same URL)
  22328. * browser().window.href() window.location.href
  22329. * browser().window.path() window.location.pathname
  22330. * browser().window.search() window.location.search
  22331. * browser().window.hash() window.location.hash without # prefix
  22332. * browser().location().url() see ng.$location#url
  22333. * browser().location().path() see ng.$location#path
  22334. * browser().location().search() see ng.$location#search
  22335. * browser().location().hash() see ng.$location#hash
  22336. */
  22337. angular.scenario.dsl('browser', function() {
  22338. var chain = {};
  22339. chain.navigateTo = function(url, delegate) {
  22340. var application = this.application;
  22341. return this.addFuture("browser navigate to '" + url + "'", function(done) {
  22342. if (delegate) {
  22343. url = delegate.call(this, url);
  22344. }
  22345. application.navigateTo(url, function() {
  22346. done(null, url);
  22347. }, done);
  22348. });
  22349. };
  22350. chain.reload = function() {
  22351. var application = this.application;
  22352. return this.addFutureAction('browser reload', function($window, $document, done) {
  22353. var href = $window.location.href;
  22354. application.navigateTo(href, function() {
  22355. done(null, href);
  22356. }, done);
  22357. });
  22358. };
  22359. chain.window = function() {
  22360. var api = {};
  22361. api.href = function() {
  22362. return this.addFutureAction('window.location.href', function($window, $document, done) {
  22363. done(null, $window.location.href);
  22364. });
  22365. };
  22366. api.path = function() {
  22367. return this.addFutureAction('window.location.path', function($window, $document, done) {
  22368. done(null, $window.location.pathname);
  22369. });
  22370. };
  22371. api.search = function() {
  22372. return this.addFutureAction('window.location.search', function($window, $document, done) {
  22373. done(null, $window.location.search);
  22374. });
  22375. };
  22376. api.hash = function() {
  22377. return this.addFutureAction('window.location.hash', function($window, $document, done) {
  22378. done(null, $window.location.hash.replace('#', ''));
  22379. });
  22380. };
  22381. return api;
  22382. };
  22383. chain.location = function() {
  22384. var api = {};
  22385. api.url = function() {
  22386. return this.addFutureAction('$location.url()', function($window, $document, done) {
  22387. done(null, $document.injector().get('$location').url());
  22388. });
  22389. };
  22390. api.path = function() {
  22391. return this.addFutureAction('$location.path()', function($window, $document, done) {
  22392. done(null, $document.injector().get('$location').path());
  22393. });
  22394. };
  22395. api.search = function() {
  22396. return this.addFutureAction('$location.search()', function($window, $document, done) {
  22397. done(null, $document.injector().get('$location').search());
  22398. });
  22399. };
  22400. api.hash = function() {
  22401. return this.addFutureAction('$location.hash()', function($window, $document, done) {
  22402. done(null, $document.injector().get('$location').hash());
  22403. });
  22404. };
  22405. return api;
  22406. };
  22407. return function() {
  22408. return chain;
  22409. };
  22410. });
  22411. /**
  22412. * Usage:
  22413. * expect(future).{matcher} where matcher is one of the matchers defined
  22414. * with angular.scenario.matcher
  22415. *
  22416. * ex. expect(binding("name")).toEqual("Elliott")
  22417. */
  22418. angular.scenario.dsl('expect', function() {
  22419. var chain = angular.extend({}, angular.scenario.matcher);
  22420. chain.not = function() {
  22421. this.inverse = true;
  22422. return chain;
  22423. };
  22424. return function(future) {
  22425. this.future = future;
  22426. return chain;
  22427. };
  22428. });
  22429. /**
  22430. * Usage:
  22431. * using(selector, label) scopes the next DSL element selection
  22432. *
  22433. * ex.
  22434. * using('#foo', "'Foo' text field").input('bar')
  22435. */
  22436. angular.scenario.dsl('using', function() {
  22437. return function(selector, label) {
  22438. this.selector = _jQuery.trim((this.selector||'') + ' ' + selector);
  22439. if (angular.isString(label) && label.length) {
  22440. this.label = label + ' ( ' + this.selector + ' )';
  22441. } else {
  22442. this.label = this.selector;
  22443. }
  22444. return this.dsl;
  22445. };
  22446. });
  22447. /**
  22448. * Usage:
  22449. * binding(name) returns the value of the first matching binding
  22450. */
  22451. angular.scenario.dsl('binding', function() {
  22452. return function(name) {
  22453. return this.addFutureAction("select binding '" + name + "'", function($window, $document, done) {
  22454. var values = $document.elements().bindings($window.angular.element, name);
  22455. if (!values.length) {
  22456. return done("Binding selector '" + name + "' did not match.");
  22457. }
  22458. done(null, values[0]);
  22459. });
  22460. };
  22461. });
  22462. /**
  22463. * Usage:
  22464. * input(name).enter(value) enters value in input with specified name
  22465. * input(name).check() checks checkbox
  22466. * input(name).select(value) selects the radio button with specified name/value
  22467. * input(name).val() returns the value of the input.
  22468. */
  22469. angular.scenario.dsl('input', function() {
  22470. var chain = {};
  22471. var supportInputEvent = 'oninput' in document.createElement('div') && msie != 9;
  22472. chain.enter = function(value, event) {
  22473. return this.addFutureAction("input '" + this.name + "' enter '" + value + "'", function($window, $document, done) {
  22474. var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
  22475. input.val(value);
  22476. input.trigger(event || (supportInputEvent ? 'input' : 'change'));
  22477. done();
  22478. });
  22479. };
  22480. chain.check = function() {
  22481. return this.addFutureAction("checkbox '" + this.name + "' toggle", function($window, $document, done) {
  22482. var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':checkbox');
  22483. input.trigger('click');
  22484. done();
  22485. });
  22486. };
  22487. chain.select = function(value) {
  22488. return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'", function($window, $document, done) {
  22489. var input = $document.
  22490. elements('[ng\\:model="$1"][value="$2"]', this.name, value).filter(':radio');
  22491. input.trigger('click');
  22492. done();
  22493. });
  22494. };
  22495. chain.val = function() {
  22496. return this.addFutureAction("return input val", function($window, $document, done) {
  22497. var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
  22498. done(null,input.val());
  22499. });
  22500. };
  22501. return function(name) {
  22502. this.name = name;
  22503. return chain;
  22504. };
  22505. });
  22506. /**
  22507. * Usage:
  22508. * repeater('#products table', 'Product List').count() number of rows
  22509. * repeater('#products table', 'Product List').row(1) all bindings in row as an array
  22510. * repeater('#products table', 'Product List').column('product.name') all values across all rows in an array
  22511. */
  22512. angular.scenario.dsl('repeater', function() {
  22513. var chain = {};
  22514. chain.count = function() {
  22515. return this.addFutureAction("repeater '" + this.label + "' count", function($window, $document, done) {
  22516. try {
  22517. done(null, $document.elements().length);
  22518. } catch (e) {
  22519. done(null, 0);
  22520. }
  22521. });
  22522. };
  22523. chain.column = function(binding) {
  22524. return this.addFutureAction("repeater '" + this.label + "' column '" + binding + "'", function($window, $document, done) {
  22525. done(null, $document.elements().bindings($window.angular.element, binding));
  22526. });
  22527. };
  22528. chain.row = function(index) {
  22529. return this.addFutureAction("repeater '" + this.label + "' row '" + index + "'", function($window, $document, done) {
  22530. var matches = $document.elements().slice(index, index + 1);
  22531. if (!matches.length)
  22532. return done('row ' + index + ' out of bounds');
  22533. done(null, matches.bindings($window.angular.element));
  22534. });
  22535. };
  22536. return function(selector, label) {
  22537. this.dsl.using(selector, label);
  22538. return chain;
  22539. };
  22540. });
  22541. /**
  22542. * Usage:
  22543. * select(name).option('value') select one option
  22544. * select(name).options('value1', 'value2', ...) select options from a multi select
  22545. */
  22546. angular.scenario.dsl('select', function() {
  22547. var chain = {};
  22548. chain.option = function(value) {
  22549. return this.addFutureAction("select '" + this.name + "' option '" + value + "'", function($window, $document, done) {
  22550. var select = $document.elements('select[ng\\:model="$1"]', this.name);
  22551. var option = select.find('option[value="' + value + '"]');
  22552. if (option.length) {
  22553. select.val(value);
  22554. } else {
  22555. option = select.find('option:contains("' + value + '")');
  22556. if (option.length) {
  22557. select.val(option.val());
  22558. }
  22559. }
  22560. select.trigger('change');
  22561. done();
  22562. });
  22563. };
  22564. chain.options = function() {
  22565. var values = arguments;
  22566. return this.addFutureAction("select '" + this.name + "' options '" + values + "'", function($window, $document, done) {
  22567. var select = $document.elements('select[multiple][ng\\:model="$1"]', this.name);
  22568. select.val(values);
  22569. select.trigger('change');
  22570. done();
  22571. });
  22572. };
  22573. return function(name) {
  22574. this.name = name;
  22575. return chain;
  22576. };
  22577. });
  22578. /**
  22579. * Usage:
  22580. * element(selector, label).count() get the number of elements that match selector
  22581. * element(selector, label).click() clicks an element
  22582. * element(selector, label).query(fn) executes fn(selectedElements, done)
  22583. * element(selector, label).{method}() gets the value (as defined by jQuery, ex. val)
  22584. * element(selector, label).{method}(value) sets the value (as defined by jQuery, ex. val)
  22585. * element(selector, label).{method}(key) gets the value (as defined by jQuery, ex. attr)
  22586. * element(selector, label).{method}(key, value) sets the value (as defined by jQuery, ex. attr)
  22587. */
  22588. angular.scenario.dsl('element', function() {
  22589. var KEY_VALUE_METHODS = ['attr', 'css', 'prop'];
  22590. var VALUE_METHODS = [
  22591. 'val', 'text', 'html', 'height', 'innerHeight', 'outerHeight', 'width',
  22592. 'innerWidth', 'outerWidth', 'position', 'scrollLeft', 'scrollTop', 'offset'
  22593. ];
  22594. var chain = {};
  22595. chain.count = function() {
  22596. return this.addFutureAction("element '" + this.label + "' count", function($window, $document, done) {
  22597. try {
  22598. done(null, $document.elements().length);
  22599. } catch (e) {
  22600. done(null, 0);
  22601. }
  22602. });
  22603. };
  22604. chain.click = function() {
  22605. return this.addFutureAction("element '" + this.label + "' click", function($window, $document, done) {
  22606. var elements = $document.elements();
  22607. var href = elements.attr('href');
  22608. var eventProcessDefault = elements.trigger('click')[0];
  22609. if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) {
  22610. this.application.navigateTo(href, function() {
  22611. done();
  22612. }, done);
  22613. } else {
  22614. done();
  22615. }
  22616. });
  22617. };
  22618. chain.query = function(fn) {
  22619. return this.addFutureAction('element ' + this.label + ' custom query', function($window, $document, done) {
  22620. fn.call(this, $document.elements(), done);
  22621. });
  22622. };
  22623. angular.forEach(KEY_VALUE_METHODS, function(methodName) {
  22624. chain[methodName] = function(name, value) {
  22625. var args = arguments,
  22626. futureName = (args.length == 1)
  22627. ? "element '" + this.label + "' get " + methodName + " '" + name + "'"
  22628. : "element '" + this.label + "' set " + methodName + " '" + name + "' to " + "'" + value + "'";
  22629. return this.addFutureAction(futureName, function($window, $document, done) {
  22630. var element = $document.elements();
  22631. done(null, element[methodName].apply(element, args));
  22632. });
  22633. };
  22634. });
  22635. angular.forEach(VALUE_METHODS, function(methodName) {
  22636. chain[methodName] = function(value) {
  22637. var args = arguments,
  22638. futureName = (args.length == 0)
  22639. ? "element '" + this.label + "' " + methodName
  22640. : futureName = "element '" + this.label + "' set " + methodName + " to '" + value + "'";
  22641. return this.addFutureAction(futureName, function($window, $document, done) {
  22642. var element = $document.elements();
  22643. done(null, element[methodName].apply(element, args));
  22644. });
  22645. };
  22646. });
  22647. return function(selector, label) {
  22648. this.dsl.using(selector, label);
  22649. return chain;
  22650. };
  22651. });
  22652. /**
  22653. * Matchers for implementing specs. Follows the Jasmine spec conventions.
  22654. */
  22655. angular.scenario.matcher('toEqual', function(expected) {
  22656. return angular.equals(this.actual, expected);
  22657. });
  22658. angular.scenario.matcher('toBe', function(expected) {
  22659. return this.actual === expected;
  22660. });
  22661. angular.scenario.matcher('toBeDefined', function() {
  22662. return angular.isDefined(this.actual);
  22663. });
  22664. angular.scenario.matcher('toBeTruthy', function() {
  22665. return this.actual;
  22666. });
  22667. angular.scenario.matcher('toBeFalsy', function() {
  22668. return !this.actual;
  22669. });
  22670. angular.scenario.matcher('toMatch', function(expected) {
  22671. return new RegExp(expected).test(this.actual);
  22672. });
  22673. angular.scenario.matcher('toBeNull', function() {
  22674. return this.actual === null;
  22675. });
  22676. angular.scenario.matcher('toContain', function(expected) {
  22677. return includes(this.actual, expected);
  22678. });
  22679. angular.scenario.matcher('toBeLessThan', function(expected) {
  22680. return this.actual < expected;
  22681. });
  22682. angular.scenario.matcher('toBeGreaterThan', function(expected) {
  22683. return this.actual > expected;
  22684. });
  22685. /**
  22686. * User Interface for the Scenario Runner.
  22687. *
  22688. * TODO(esprehn): This should be refactored now that ObjectModel exists
  22689. * to use angular bindings for the UI.
  22690. */
  22691. angular.scenario.output('html', function(context, runner, model) {
  22692. var specUiMap = {},
  22693. lastStepUiMap = {};
  22694. context.append(
  22695. '<div id="header">' +
  22696. ' <h1><span class="angular">AngularJS</span>: Scenario Test Runner</h1>' +
  22697. ' <ul id="status-legend" class="status-display">' +
  22698. ' <li class="status-error">0 Errors</li>' +
  22699. ' <li class="status-failure">0 Failures</li>' +
  22700. ' <li class="status-success">0 Passed</li>' +
  22701. ' </ul>' +
  22702. '</div>' +
  22703. '<div id="specs">' +
  22704. ' <div class="test-children"></div>' +
  22705. '</div>'
  22706. );
  22707. runner.on('InteractivePause', function(spec) {
  22708. var ui = lastStepUiMap[spec.id];
  22709. ui.find('.test-title').
  22710. html('paused... <a href="javascript:resume()">resume</a> when ready.');
  22711. });
  22712. runner.on('SpecBegin', function(spec) {
  22713. var ui = findContext(spec);
  22714. ui.find('> .tests').append(
  22715. '<li class="status-pending test-it"></li>'
  22716. );
  22717. ui = ui.find('> .tests li:last');
  22718. ui.append(
  22719. '<div class="test-info">' +
  22720. ' <p class="test-title">' +
  22721. ' <span class="timer-result"></span>' +
  22722. ' <span class="test-name"></span>' +
  22723. ' </p>' +
  22724. '</div>' +
  22725. '<div class="scrollpane">' +
  22726. ' <ol class="test-actions"></ol>' +
  22727. '</div>'
  22728. );
  22729. ui.find('> .test-info .test-name').text(spec.name);
  22730. ui.find('> .test-info').click(function() {
  22731. var scrollpane = ui.find('> .scrollpane');
  22732. var actions = scrollpane.find('> .test-actions');
  22733. var name = context.find('> .test-info .test-name');
  22734. if (actions.find(':visible').length) {
  22735. actions.hide();
  22736. name.removeClass('open').addClass('closed');
  22737. } else {
  22738. actions.show();
  22739. scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
  22740. name.removeClass('closed').addClass('open');
  22741. }
  22742. });
  22743. specUiMap[spec.id] = ui;
  22744. });
  22745. runner.on('SpecError', function(spec, error) {
  22746. var ui = specUiMap[spec.id];
  22747. ui.append('<pre></pre>');
  22748. ui.find('> pre').text(formatException(error));
  22749. });
  22750. runner.on('SpecEnd', function(spec) {
  22751. var ui = specUiMap[spec.id];
  22752. spec = model.getSpec(spec.id);
  22753. ui.removeClass('status-pending');
  22754. ui.addClass('status-' + spec.status);
  22755. ui.find("> .test-info .timer-result").text(spec.duration + "ms");
  22756. if (spec.status === 'success') {
  22757. ui.find('> .test-info .test-name').addClass('closed');
  22758. ui.find('> .scrollpane .test-actions').hide();
  22759. }
  22760. updateTotals(spec.status);
  22761. });
  22762. runner.on('StepBegin', function(spec, step) {
  22763. var ui = specUiMap[spec.id];
  22764. spec = model.getSpec(spec.id);
  22765. step = spec.getLastStep();
  22766. ui.find('> .scrollpane .test-actions').append('<li class="status-pending"></li>');
  22767. var stepUi = lastStepUiMap[spec.id] = ui.find('> .scrollpane .test-actions li:last');
  22768. stepUi.append(
  22769. '<div class="timer-result"></div>' +
  22770. '<div class="test-title"></div>'
  22771. );
  22772. stepUi.find('> .test-title').text(step.name);
  22773. var scrollpane = stepUi.parents('.scrollpane');
  22774. scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
  22775. });
  22776. runner.on('StepFailure', function(spec, step, error) {
  22777. var ui = lastStepUiMap[spec.id];
  22778. addError(ui, step.line, error);
  22779. });
  22780. runner.on('StepError', function(spec, step, error) {
  22781. var ui = lastStepUiMap[spec.id];
  22782. addError(ui, step.line, error);
  22783. });
  22784. runner.on('StepEnd', function(spec, step) {
  22785. var stepUi = lastStepUiMap[spec.id];
  22786. spec = model.getSpec(spec.id);
  22787. step = spec.getLastStep();
  22788. stepUi.find('.timer-result').text(step.duration + 'ms');
  22789. stepUi.removeClass('status-pending');
  22790. stepUi.addClass('status-' + step.status);
  22791. var scrollpane = specUiMap[spec.id].find('> .scrollpane');
  22792. scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
  22793. });
  22794. /**
  22795. * Finds the context of a spec block defined by the passed definition.
  22796. *
  22797. * @param {Object} The definition created by the Describe object.
  22798. */
  22799. function findContext(spec) {
  22800. var currentContext = context.find('#specs');
  22801. angular.forEach(model.getDefinitionPath(spec), function(defn) {
  22802. var id = 'describe-' + defn.id;
  22803. if (!context.find('#' + id).length) {
  22804. currentContext.find('> .test-children').append(
  22805. '<div class="test-describe" id="' + id + '">' +
  22806. ' <h2></h2>' +
  22807. ' <div class="test-children"></div>' +
  22808. ' <ul class="tests"></ul>' +
  22809. '</div>'
  22810. );
  22811. context.find('#' + id).find('> h2').text('describe: ' + defn.name);
  22812. }
  22813. currentContext = context.find('#' + id);
  22814. });
  22815. return context.find('#describe-' + spec.definition.id);
  22816. }
  22817. /**
  22818. * Updates the test counter for the status.
  22819. *
  22820. * @param {string} the status.
  22821. */
  22822. function updateTotals(status) {
  22823. var legend = context.find('#status-legend .status-' + status);
  22824. var parts = legend.text().split(' ');
  22825. var value = (parts[0] * 1) + 1;
  22826. legend.text(value + ' ' + parts[1]);
  22827. }
  22828. /**
  22829. * Add an error to a step.
  22830. *
  22831. * @param {Object} The JQuery wrapped context
  22832. * @param {function()} fn() that should return the file/line number of the error
  22833. * @param {Object} the error.
  22834. */
  22835. function addError(context, line, error) {
  22836. context.find('.test-title').append('<pre></pre>');
  22837. var message = _jQuery.trim(line() + '\n\n' + formatException(error));
  22838. context.find('.test-title pre:last').text(message);
  22839. }
  22840. });
  22841. /**
  22842. * Generates JSON output into a context.
  22843. */
  22844. angular.scenario.output('json', function(context, runner, model) {
  22845. model.on('RunnerEnd', function() {
  22846. context.text(angular.toJson(model.value));
  22847. });
  22848. });
  22849. /**
  22850. * Generates XML output into a context.
  22851. */
  22852. angular.scenario.output('xml', function(context, runner, model) {
  22853. var $ = function(args) {return new context.init(args);};
  22854. model.on('RunnerEnd', function() {
  22855. var scenario = $('<scenario></scenario>');
  22856. context.append(scenario);
  22857. serializeXml(scenario, model.value);
  22858. });
  22859. /**
  22860. * Convert the tree into XML.
  22861. *
  22862. * @param {Object} context jQuery context to add the XML to.
  22863. * @param {Object} tree node to serialize
  22864. */
  22865. function serializeXml(context, tree) {
  22866. angular.forEach(tree.children, function(child) {
  22867. var describeContext = $('<describe></describe>');
  22868. describeContext.attr('id', child.id);
  22869. describeContext.attr('name', child.name);
  22870. context.append(describeContext);
  22871. serializeXml(describeContext, child);
  22872. });
  22873. var its = $('<its></its>');
  22874. context.append(its);
  22875. angular.forEach(tree.specs, function(spec) {
  22876. var it = $('<it></it>');
  22877. it.attr('id', spec.id);
  22878. it.attr('name', spec.name);
  22879. it.attr('duration', spec.duration);
  22880. it.attr('status', spec.status);
  22881. its.append(it);
  22882. angular.forEach(spec.steps, function(step) {
  22883. var stepContext = $('<step></step>');
  22884. stepContext.attr('name', step.name);
  22885. stepContext.attr('duration', step.duration);
  22886. stepContext.attr('status', step.status);
  22887. it.append(stepContext);
  22888. if (step.error) {
  22889. var error = $('<error></error>');
  22890. stepContext.append(error);
  22891. error.text(formatException(step.error));
  22892. }
  22893. });
  22894. });
  22895. }
  22896. });
  22897. /**
  22898. * Creates a global value $result with the result of the runner.
  22899. */
  22900. angular.scenario.output('object', function(context, runner, model) {
  22901. runner.$window.$result = model.value;
  22902. });
  22903. bindJQuery();
  22904. publishExternalAPI(angular);
  22905. var $runner = new angular.scenario.Runner(window),
  22906. scripts = document.getElementsByTagName('script'),
  22907. script = scripts[scripts.length - 1],
  22908. config = {};
  22909. angular.forEach(script.attributes, function(attr) {
  22910. var match = attr.name.match(/ng[:\-](.*)/);
  22911. if (match) {
  22912. config[match[1]] = attr.value || true;
  22913. }
  22914. });
  22915. if (config.autotest) {
  22916. JQLite(document).ready(function() {
  22917. angular.scenario.setUpAndRun(config);
  22918. });
  22919. }
  22920. })(window, document);
  22921. angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak {\n display: none;\n}\n\nng\\:form {\n display: block;\n}\n</style>');
  22922. angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";\n/* CSS Document */\n\n/** Structure */\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n font-size: 14px;\n}\n\n#system-error {\n font-size: 1.5em;\n text-align: center;\n}\n\n#json, #xml {\n display: none;\n}\n\n#header {\n position: fixed;\n width: 100%;\n}\n\n#specs {\n padding-top: 50px;\n}\n\n#header .angular {\n font-family: Courier New, monospace;\n font-weight: bold;\n}\n\n#header h1 {\n font-weight: normal;\n float: left;\n font-size: 30px;\n line-height: 30px;\n margin: 0;\n padding: 10px 10px;\n height: 30px;\n}\n\n#application h2,\n#specs h2 {\n margin: 0;\n padding: 0.5em;\n font-size: 1.1em;\n}\n\n#status-legend {\n margin-top: 10px;\n margin-right: 10px;\n}\n\n#header,\n#application,\n.test-info,\n.test-actions li {\n overflow: hidden;\n}\n\n#application {\n margin: 10px;\n}\n\n#application iframe {\n width: 100%;\n height: 758px;\n}\n\n#application .popout {\n float: right;\n}\n\n#application iframe {\n border: none;\n}\n\n.tests li,\n.test-actions li,\n.test-it li,\n.test-it ol,\n.status-display {\n list-style-type: none;\n}\n\n.tests,\n.test-it ol,\n.status-display {\n margin: 0;\n padding: 0;\n}\n\n.test-info {\n margin-left: 1em;\n margin-top: 0.5em;\n border-radius: 8px 0 0 8px;\n -webkit-border-radius: 8px 0 0 8px;\n -moz-border-radius: 8px 0 0 8px;\n cursor: pointer;\n}\n\n.test-info:hover .test-name {\n text-decoration: underline;\n}\n\n.test-info .closed:before {\n content: \'\\25b8\\00A0\';\n}\n\n.test-info .open:before {\n content: \'\\25be\\00A0\';\n font-weight: bold;\n}\n\n.test-it ol {\n margin-left: 2.5em;\n}\n\n.status-display,\n.status-display li {\n float: right;\n}\n\n.status-display li {\n padding: 5px 10px;\n}\n\n.timer-result,\n.test-title {\n display: inline-block;\n margin: 0;\n padding: 4px;\n}\n\n.test-actions .test-title,\n.test-actions .test-result {\n display: table-cell;\n padding-left: 0.5em;\n padding-right: 0.5em;\n}\n\n.test-actions {\n display: table;\n}\n\n.test-actions li {\n display: table-row;\n}\n\n.timer-result {\n width: 4em;\n padding: 0 10px;\n text-align: right;\n font-family: monospace;\n}\n\n.test-it pre,\n.test-actions pre {\n clear: left;\n color: black;\n margin-left: 6em;\n}\n\n.test-describe {\n padding-bottom: 0.5em;\n}\n\n.test-describe .test-describe {\n margin: 5px 5px 10px 2em;\n}\n\n.test-actions .status-pending .test-title:before {\n content: \'\\00bb\\00A0\';\n}\n\n.scrollpane {\n max-height: 20em;\n overflow: auto;\n}\n\n/** Colors */\n\n#header {\n background-color: #F2C200;\n}\n\n#specs h2 {\n border-top: 2px solid #BABAD1;\n}\n\n#specs h2,\n#application h2 {\n background-color: #efefef;\n}\n\n#application {\n border: 1px solid #BABAD1;\n}\n\n.test-describe .test-describe {\n border-left: 1px solid #BABAD1;\n border-right: 1px solid #BABAD1;\n border-bottom: 1px solid #BABAD1;\n}\n\n.status-display {\n border: 1px solid #777;\n}\n\n.status-display .status-pending,\n.status-pending .test-info {\n background-color: #F9EEBC;\n}\n\n.status-display .status-success,\n.status-success .test-info {\n background-color: #B1D7A1;\n}\n\n.status-display .status-failure,\n.status-failure .test-info {\n background-color: #FF8286;\n}\n\n.status-display .status-error,\n.status-error .test-info {\n background-color: black;\n color: white;\n}\n\n.test-actions .status-success .test-title {\n color: #30B30A;\n}\n\n.test-actions .status-failure .test-title {\n color: #DF0000;\n}\n\n.test-actions .status-error .test-title {\n color: black;\n}\n\n.test-actions .timer-result {\n color: #888;\n}\n</style>');