ember-1.0.0-rc.1.js 725 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839
  1. // Version: v1.0.0-rc.1
  2. // Last commit: 8b061b4 (2013-02-15 12:10:22 -0800)
  3. (function() {
  4. /*global __fail__*/
  5. /**
  6. Ember Debug
  7. @module ember
  8. @submodule ember-debug
  9. */
  10. /**
  11. @class Ember
  12. */
  13. if ('undefined' === typeof Ember) {
  14. Ember = {};
  15. if ('undefined' !== typeof window) {
  16. window.Em = window.Ember = Em = Ember;
  17. }
  18. }
  19. Ember.ENV = 'undefined' === typeof ENV ? {} : ENV;
  20. if (!('MANDATORY_SETTER' in Ember.ENV)) {
  21. Ember.ENV.MANDATORY_SETTER = true; // default to true for debug dist
  22. }
  23. /**
  24. Define an assertion that will throw an exception if the condition is not
  25. met. Ember build tools will remove any calls to `Ember.assert()` when
  26. doing a production build. Example:
  27. ```javascript
  28. // Test for truthiness
  29. Ember.assert('Must pass a valid object', obj);
  30. // Fail unconditionally
  31. Ember.assert('This code path should never be run')
  32. ```
  33. @method assert
  34. @param {String} desc A description of the assertion. This will become
  35. the text of the Error thrown if the assertion fails.
  36. @param {Boolean} test Must be truthy for the assertion to pass. If
  37. falsy, an exception will be thrown.
  38. */
  39. Ember.assert = function(desc, test) {
  40. if (!test) throw new Error("assertion failed: "+desc);
  41. };
  42. /**
  43. Display a warning with the provided message. Ember build tools will
  44. remove any calls to `Ember.warn()` when doing a production build.
  45. @method warn
  46. @param {String} message A warning to display.
  47. @param {Boolean} test An optional boolean. If falsy, the warning
  48. will be displayed.
  49. */
  50. Ember.warn = function(message, test) {
  51. if (!test) {
  52. Ember.Logger.warn("WARNING: "+message);
  53. if ('trace' in Ember.Logger) Ember.Logger.trace();
  54. }
  55. };
  56. /**
  57. Display a debug notice. Ember build tools will remove any calls to
  58. `Ember.debug()` when doing a production build.
  59. ```javascript
  60. Ember.debug("I'm a debug notice!");
  61. ```
  62. @method debug
  63. @param {String} message A debug message to display.
  64. */
  65. Ember.debug = function(message) {
  66. Ember.Logger.debug("DEBUG: "+message);
  67. };
  68. /**
  69. Display a deprecation warning with the provided message and a stack trace
  70. (Chrome and Firefox only). Ember build tools will remove any calls to
  71. `Ember.deprecate()` when doing a production build.
  72. @method deprecate
  73. @param {String} message A description of the deprecation.
  74. @param {Boolean} test An optional boolean. If falsy, the deprecation
  75. will be displayed.
  76. */
  77. Ember.deprecate = function(message, test) {
  78. if (Ember && Ember.TESTING_DEPRECATION) { return; }
  79. if (arguments.length === 1) { test = false; }
  80. if (test) { return; }
  81. if (Ember && Ember.ENV.RAISE_ON_DEPRECATION) { throw new Error(message); }
  82. var error;
  83. // When using new Error, we can't do the arguments check for Chrome. Alternatives are welcome
  84. try { __fail__.fail(); } catch (e) { error = e; }
  85. if (Ember.LOG_STACKTRACE_ON_DEPRECATION && error.stack) {
  86. var stack, stackStr = '';
  87. if (error['arguments']) {
  88. // Chrome
  89. stack = error.stack.replace(/^\s+at\s+/gm, '').
  90. replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2').
  91. replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm, '{anonymous}($1)').split('\n');
  92. stack.shift();
  93. } else {
  94. // Firefox
  95. stack = error.stack.replace(/(?:\n@:0)?\s+$/m, '').
  96. replace(/^\(/gm, '{anonymous}(').split('\n');
  97. }
  98. stackStr = "\n " + stack.slice(2).join("\n ");
  99. message = message + stackStr;
  100. }
  101. Ember.Logger.warn("DEPRECATION: "+message);
  102. };
  103. /**
  104. Display a deprecation warning with the provided message and a stack trace
  105. (Chrome and Firefox only) when the wrapped method is called.
  106. Ember build tools will not remove calls to `Ember.deprecateFunc()`, though
  107. no warnings will be shown in production.
  108. @method deprecateFunc
  109. @param {String} message A description of the deprecation.
  110. @param {Function} func The function to be deprecated.
  111. */
  112. Ember.deprecateFunc = function(message, func) {
  113. return function() {
  114. Ember.deprecate(message);
  115. return func.apply(this, arguments);
  116. };
  117. };
  118. })();
  119. // Version: v1.0.0-rc.1
  120. // Last commit: 8b061b4 (2013-02-15 12:10:22 -0800)
  121. (function() {
  122. var define, requireModule;
  123. (function() {
  124. var registry = {}, seen = {};
  125. define = function(name, deps, callback) {
  126. registry[name] = { deps: deps, callback: callback };
  127. };
  128. requireModule = function(name) {
  129. if (seen[name]) { return seen[name]; }
  130. seen[name] = {};
  131. var mod = registry[name],
  132. deps = mod.deps,
  133. callback = mod.callback,
  134. reified = [],
  135. exports;
  136. for (var i=0, l=deps.length; i<l; i++) {
  137. if (deps[i] === 'exports') {
  138. reified.push(exports = {});
  139. } else {
  140. reified.push(requireModule(deps[i]));
  141. }
  142. }
  143. var value = callback.apply(this, reified);
  144. return seen[name] = exports || value;
  145. };
  146. })();
  147. (function() {
  148. /*globals Em:true ENV */
  149. /**
  150. @module ember
  151. @submodule ember-metal
  152. */
  153. /**
  154. All Ember methods and functions are defined inside of this namespace. You
  155. generally should not add new properties to this namespace as it may be
  156. overwritten by future versions of Ember.
  157. You can also use the shorthand `Em` instead of `Ember`.
  158. Ember-Runtime is a framework that provides core functions for Ember including
  159. cross-platform functions, support for property observing and objects. Its
  160. focus is on small size and performance. You can use this in place of or
  161. along-side other cross-platform libraries such as jQuery.
  162. The core Runtime framework is based on the jQuery API with a number of
  163. performance optimizations.
  164. @class Ember
  165. @static
  166. @version 1.0.0-rc.1
  167. */
  168. if ('undefined' === typeof Ember) {
  169. // Create core object. Make it act like an instance of Ember.Namespace so that
  170. // objects assigned to it are given a sane string representation.
  171. Ember = {};
  172. }
  173. // Default imports, exports and lookup to the global object;
  174. var imports = Ember.imports = Ember.imports || this;
  175. var exports = Ember.exports = Ember.exports || this;
  176. var lookup = Ember.lookup = Ember.lookup || this;
  177. // aliases needed to keep minifiers from removing the global context
  178. exports.Em = exports.Ember = Em = Ember;
  179. // Make sure these are set whether Ember was already defined or not
  180. Ember.isNamespace = true;
  181. Ember.toString = function() { return "Ember"; };
  182. /**
  183. @property VERSION
  184. @type String
  185. @default '1.0.0-rc.1'
  186. @final
  187. */
  188. Ember.VERSION = '1.0.0-rc.1';
  189. /**
  190. Standard environmental variables. You can define these in a global `ENV`
  191. variable before loading Ember to control various configuration
  192. settings.
  193. @property ENV
  194. @type Hash
  195. */
  196. Ember.ENV = Ember.ENV || ('undefined' === typeof ENV ? {} : ENV);
  197. Ember.config = Ember.config || {};
  198. // ..........................................................
  199. // BOOTSTRAP
  200. //
  201. /**
  202. Determines whether Ember should enhances some built-in object prototypes to
  203. provide a more friendly API. If enabled, a few methods will be added to
  204. `Function`, `String`, and `Array`. `Object.prototype` will not be enhanced,
  205. which is the one that causes most trouble for people.
  206. In general we recommend leaving this option set to true since it rarely
  207. conflicts with other code. If you need to turn it off however, you can
  208. define an `ENV.EXTEND_PROTOTYPES` config to disable it.
  209. @property EXTEND_PROTOTYPES
  210. @type Boolean
  211. @default true
  212. */
  213. Ember.EXTEND_PROTOTYPES = Ember.ENV.EXTEND_PROTOTYPES;
  214. if (typeof Ember.EXTEND_PROTOTYPES === 'undefined') {
  215. Ember.EXTEND_PROTOTYPES = true;
  216. }
  217. /**
  218. Determines whether Ember logs a full stack trace during deprecation warnings
  219. @property LOG_STACKTRACE_ON_DEPRECATION
  220. @type Boolean
  221. @default true
  222. */
  223. Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false);
  224. /**
  225. Determines whether Ember should add ECMAScript 5 shims to older browsers.
  226. @property SHIM_ES5
  227. @type Boolean
  228. @default Ember.EXTEND_PROTOTYPES
  229. */
  230. Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : Ember.EXTEND_PROTOTYPES;
  231. /**
  232. Empty function. Useful for some operations.
  233. @method K
  234. @private
  235. @return {Object}
  236. */
  237. Ember.K = function() { return this; };
  238. // Stub out the methods defined by the ember-debug package in case it's not loaded
  239. if ('undefined' === typeof Ember.assert) { Ember.assert = Ember.K; }
  240. if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; }
  241. if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; }
  242. if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.K; }
  243. if ('undefined' === typeof Ember.deprecateFunc) {
  244. Ember.deprecateFunc = function(_, func) { return func; };
  245. }
  246. /**
  247. Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from
  248. jQuery master. We'll just bootstrap our own uuid now.
  249. @property uuid
  250. @type Number
  251. @private
  252. */
  253. Ember.uuid = 0;
  254. // ..........................................................
  255. // LOGGER
  256. //
  257. function consoleMethod(name) {
  258. if (imports.console && imports.console[name]) {
  259. // Older IE doesn't support apply, but Chrome needs it
  260. if (imports.console[name].apply) {
  261. return function() {
  262. imports.console[name].apply(imports.console, arguments);
  263. };
  264. } else {
  265. return function() {
  266. var message = Array.prototype.join.call(arguments, ', ');
  267. imports.console[name](message);
  268. };
  269. }
  270. }
  271. }
  272. /**
  273. Inside Ember-Metal, simply uses the methods from `imports.console`.
  274. Override this to provide more robust logging functionality.
  275. @class Logger
  276. @namespace Ember
  277. */
  278. Ember.Logger = {
  279. log: consoleMethod('log') || Ember.K,
  280. warn: consoleMethod('warn') || Ember.K,
  281. error: consoleMethod('error') || Ember.K,
  282. info: consoleMethod('info') || Ember.K,
  283. debug: consoleMethod('debug') || consoleMethod('info') || Ember.K
  284. };
  285. // ..........................................................
  286. // ERROR HANDLING
  287. //
  288. /**
  289. A function may be assigned to `Ember.onerror` to be called when Ember
  290. internals encounter an error. This is useful for specialized error handling
  291. and reporting code.
  292. @event onerror
  293. @for Ember
  294. @param {Exception} error the error object
  295. */
  296. Ember.onerror = null;
  297. /**
  298. @private
  299. Wrap code block in a try/catch if {{#crossLink "Ember/onerror"}}{{/crossLink}} is set.
  300. @method handleErrors
  301. @for Ember
  302. @param {Function} func
  303. @param [context]
  304. */
  305. Ember.handleErrors = function(func, context) {
  306. // Unfortunately in some browsers we lose the backtrace if we rethrow the existing error,
  307. // so in the event that we don't have an `onerror` handler we don't wrap in a try/catch
  308. if ('function' === typeof Ember.onerror) {
  309. try {
  310. return func.apply(context || this);
  311. } catch (error) {
  312. Ember.onerror(error);
  313. }
  314. } else {
  315. return func.apply(context || this);
  316. }
  317. };
  318. Ember.merge = function(original, updates) {
  319. for (var prop in updates) {
  320. if (!updates.hasOwnProperty(prop)) { continue; }
  321. original[prop] = updates[prop];
  322. }
  323. };
  324. })();
  325. (function() {
  326. /*globals Node */
  327. /**
  328. @module ember-metal
  329. */
  330. /**
  331. Platform specific methods and feature detectors needed by the framework.
  332. @class platform
  333. @namespace Ember
  334. @static
  335. */
  336. var platform = Ember.platform = {};
  337. /**
  338. Identical to `Object.create()`. Implements if not available natively.
  339. @method create
  340. @for Ember
  341. */
  342. Ember.create = Object.create;
  343. // STUB_OBJECT_CREATE allows us to override other libraries that stub
  344. // Object.create different than we would prefer
  345. if (!Ember.create || Ember.ENV.STUB_OBJECT_CREATE) {
  346. var K = function() {};
  347. Ember.create = function(obj, props) {
  348. K.prototype = obj;
  349. obj = new K();
  350. if (props) {
  351. K.prototype = obj;
  352. for (var prop in props) {
  353. K.prototype[prop] = props[prop].value;
  354. }
  355. obj = new K();
  356. }
  357. K.prototype = null;
  358. return obj;
  359. };
  360. Ember.create.isSimulated = true;
  361. }
  362. var defineProperty = Object.defineProperty;
  363. var canRedefineProperties, canDefinePropertyOnDOM;
  364. // Catch IE8 where Object.defineProperty exists but only works on DOM elements
  365. if (defineProperty) {
  366. try {
  367. defineProperty({}, 'a',{get:function(){}});
  368. } catch (e) {
  369. defineProperty = null;
  370. }
  371. }
  372. if (defineProperty) {
  373. // Detects a bug in Android <3.2 where you cannot redefine a property using
  374. // Object.defineProperty once accessors have already been set.
  375. canRedefineProperties = (function() {
  376. var obj = {};
  377. defineProperty(obj, 'a', {
  378. configurable: true,
  379. enumerable: true,
  380. get: function() { },
  381. set: function() { }
  382. });
  383. defineProperty(obj, 'a', {
  384. configurable: true,
  385. enumerable: true,
  386. writable: true,
  387. value: true
  388. });
  389. return obj.a === true;
  390. })();
  391. // This is for Safari 5.0, which supports Object.defineProperty, but not
  392. // on DOM nodes.
  393. canDefinePropertyOnDOM = (function(){
  394. try {
  395. defineProperty(document.createElement('div'), 'definePropertyOnDOM', {});
  396. return true;
  397. } catch(e) { }
  398. return false;
  399. })();
  400. if (!canRedefineProperties) {
  401. defineProperty = null;
  402. } else if (!canDefinePropertyOnDOM) {
  403. defineProperty = function(obj, keyName, desc){
  404. var isNode;
  405. if (typeof Node === "object") {
  406. isNode = obj instanceof Node;
  407. } else {
  408. isNode = typeof obj === "object" && typeof obj.nodeType === "number" && typeof obj.nodeName === "string";
  409. }
  410. if (isNode) {
  411. // TODO: Should we have a warning here?
  412. return (obj[keyName] = desc.value);
  413. } else {
  414. return Object.defineProperty(obj, keyName, desc);
  415. }
  416. };
  417. }
  418. }
  419. /**
  420. @class platform
  421. @namespace Ember
  422. */
  423. /**
  424. Identical to `Object.defineProperty()`. Implements as much functionality
  425. as possible if not available natively.
  426. @method defineProperty
  427. @param {Object} obj The object to modify
  428. @param {String} keyName property name to modify
  429. @param {Object} desc descriptor hash
  430. @return {void}
  431. */
  432. platform.defineProperty = defineProperty;
  433. /**
  434. Set to true if the platform supports native getters and setters.
  435. @property hasPropertyAccessors
  436. @final
  437. */
  438. platform.hasPropertyAccessors = true;
  439. if (!platform.defineProperty) {
  440. platform.hasPropertyAccessors = false;
  441. platform.defineProperty = function(obj, keyName, desc) {
  442. if (!desc.get) { obj[keyName] = desc.value; }
  443. };
  444. platform.defineProperty.isSimulated = true;
  445. }
  446. if (Ember.ENV.MANDATORY_SETTER && !platform.hasPropertyAccessors) {
  447. Ember.ENV.MANDATORY_SETTER = false;
  448. }
  449. })();
  450. (function() {
  451. /**
  452. @module ember-metal
  453. */
  454. var o_defineProperty = Ember.platform.defineProperty,
  455. o_create = Ember.create,
  456. // Used for guid generation...
  457. GUID_KEY = '__ember'+ (+ new Date()),
  458. uuid = 0,
  459. numberCache = [],
  460. stringCache = {};
  461. var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER;
  462. /**
  463. @private
  464. A unique key used to assign guids and other private metadata to objects.
  465. If you inspect an object in your browser debugger you will often see these.
  466. They can be safely ignored.
  467. On browsers that support it, these properties are added with enumeration
  468. disabled so they won't show up when you iterate over your properties.
  469. @property GUID_KEY
  470. @for Ember
  471. @type String
  472. @final
  473. */
  474. Ember.GUID_KEY = GUID_KEY;
  475. var GUID_DESC = {
  476. writable: false,
  477. configurable: false,
  478. enumerable: false,
  479. value: null
  480. };
  481. /**
  482. @private
  483. Generates a new guid, optionally saving the guid to the object that you
  484. pass in. You will rarely need to use this method. Instead you should
  485. call `Ember.guidFor(obj)`, which return an existing guid if available.
  486. @method generateGuid
  487. @for Ember
  488. @param {Object} [obj] Object the guid will be used for. If passed in, the guid will
  489. be saved on the object and reused whenever you pass the same object
  490. again.
  491. If no object is passed, just generate a new guid.
  492. @param {String} [prefix] Prefix to place in front of the guid. Useful when you want to
  493. separate the guid into separate namespaces.
  494. @return {String} the guid
  495. */
  496. Ember.generateGuid = function generateGuid(obj, prefix) {
  497. if (!prefix) prefix = 'ember';
  498. var ret = (prefix + (uuid++));
  499. if (obj) {
  500. GUID_DESC.value = ret;
  501. o_defineProperty(obj, GUID_KEY, GUID_DESC);
  502. }
  503. return ret ;
  504. };
  505. /**
  506. @private
  507. Returns a unique id for the object. If the object does not yet have a guid,
  508. one will be assigned to it. You can call this on any object,
  509. `Ember.Object`-based or not, but be aware that it will add a `_guid`
  510. property.
  511. You can also use this method on DOM Element objects.
  512. @method guidFor
  513. @for Ember
  514. @param obj {Object} any object, string, number, Element, or primitive
  515. @return {String} the unique guid for this instance.
  516. */
  517. Ember.guidFor = function guidFor(obj) {
  518. // special cases where we don't want to add a key to object
  519. if (obj === undefined) return "(undefined)";
  520. if (obj === null) return "(null)";
  521. var cache, ret;
  522. var type = typeof obj;
  523. // Don't allow prototype changes to String etc. to change the guidFor
  524. switch(type) {
  525. case 'number':
  526. ret = numberCache[obj];
  527. if (!ret) ret = numberCache[obj] = 'nu'+obj;
  528. return ret;
  529. case 'string':
  530. ret = stringCache[obj];
  531. if (!ret) ret = stringCache[obj] = 'st'+(uuid++);
  532. return ret;
  533. case 'boolean':
  534. return obj ? '(true)' : '(false)';
  535. default:
  536. if (obj[GUID_KEY]) return obj[GUID_KEY];
  537. if (obj === Object) return '(Object)';
  538. if (obj === Array) return '(Array)';
  539. ret = 'ember'+(uuid++);
  540. GUID_DESC.value = ret;
  541. o_defineProperty(obj, GUID_KEY, GUID_DESC);
  542. return ret;
  543. }
  544. };
  545. // ..........................................................
  546. // META
  547. //
  548. var META_DESC = {
  549. writable: true,
  550. configurable: false,
  551. enumerable: false,
  552. value: null
  553. };
  554. var META_KEY = Ember.GUID_KEY+'_meta';
  555. /**
  556. The key used to store meta information on object for property observing.
  557. @property META_KEY
  558. @for Ember
  559. @private
  560. @final
  561. @type String
  562. */
  563. Ember.META_KEY = META_KEY;
  564. // Placeholder for non-writable metas.
  565. var EMPTY_META = {
  566. descs: {},
  567. watching: {}
  568. };
  569. if (MANDATORY_SETTER) { EMPTY_META.values = {}; }
  570. Ember.EMPTY_META = EMPTY_META;
  571. if (Object.freeze) Object.freeze(EMPTY_META);
  572. var isDefinePropertySimulated = Ember.platform.defineProperty.isSimulated;
  573. function Meta(obj) {
  574. this.descs = {};
  575. this.watching = {};
  576. this.cache = {};
  577. this.source = obj;
  578. }
  579. if (isDefinePropertySimulated) {
  580. // on platforms that don't support enumerable false
  581. // make meta fail jQuery.isPlainObject() to hide from
  582. // jQuery.extend() by having a property that fails
  583. // hasOwnProperty check.
  584. Meta.prototype.__preventPlainObject__ = true;
  585. // Without non-enumerable properties, meta objects will be output in JSON
  586. // unless explicitly suppressed
  587. Meta.prototype.toJSON = function () { };
  588. }
  589. /**
  590. Retrieves the meta hash for an object. If `writable` is true ensures the
  591. hash is writable for this object as well.
  592. The meta object contains information about computed property descriptors as
  593. well as any watched properties and other information. You generally will
  594. not access this information directly but instead work with higher level
  595. methods that manipulate this hash indirectly.
  596. @method meta
  597. @for Ember
  598. @private
  599. @param {Object} obj The object to retrieve meta for
  600. @param {Boolean} [writable=true] Pass `false` if you do not intend to modify
  601. the meta hash, allowing the method to avoid making an unnecessary copy.
  602. @return {Hash}
  603. */
  604. Ember.meta = function meta(obj, writable) {
  605. var ret = obj[META_KEY];
  606. if (writable===false) return ret || EMPTY_META;
  607. if (!ret) {
  608. if (!isDefinePropertySimulated) o_defineProperty(obj, META_KEY, META_DESC);
  609. ret = new Meta(obj);
  610. if (MANDATORY_SETTER) { ret.values = {}; }
  611. obj[META_KEY] = ret;
  612. // make sure we don't accidentally try to create constructor like desc
  613. ret.descs.constructor = null;
  614. } else if (ret.source !== obj) {
  615. if (!isDefinePropertySimulated) o_defineProperty(obj, META_KEY, META_DESC);
  616. ret = o_create(ret);
  617. ret.descs = o_create(ret.descs);
  618. ret.watching = o_create(ret.watching);
  619. ret.cache = {};
  620. ret.source = obj;
  621. if (MANDATORY_SETTER) { ret.values = o_create(ret.values); }
  622. obj[META_KEY] = ret;
  623. }
  624. return ret;
  625. };
  626. Ember.getMeta = function getMeta(obj, property) {
  627. var meta = Ember.meta(obj, false);
  628. return meta[property];
  629. };
  630. Ember.setMeta = function setMeta(obj, property, value) {
  631. var meta = Ember.meta(obj, true);
  632. meta[property] = value;
  633. return value;
  634. };
  635. /**
  636. @private
  637. In order to store defaults for a class, a prototype may need to create
  638. a default meta object, which will be inherited by any objects instantiated
  639. from the class's constructor.
  640. However, the properties of that meta object are only shallow-cloned,
  641. so if a property is a hash (like the event system's `listeners` hash),
  642. it will by default be shared across all instances of that class.
  643. This method allows extensions to deeply clone a series of nested hashes or
  644. other complex objects. For instance, the event system might pass
  645. `['listeners', 'foo:change', 'ember157']` to `prepareMetaPath`, which will
  646. walk down the keys provided.
  647. For each key, if the key does not exist, it is created. If it already
  648. exists and it was inherited from its constructor, the constructor's
  649. key is cloned.
  650. You can also pass false for `writable`, which will simply return
  651. undefined if `prepareMetaPath` discovers any part of the path that
  652. shared or undefined.
  653. @method metaPath
  654. @for Ember
  655. @param {Object} obj The object whose meta we are examining
  656. @param {Array} path An array of keys to walk down
  657. @param {Boolean} writable whether or not to create a new meta
  658. (or meta property) if one does not already exist or if it's
  659. shared with its constructor
  660. */
  661. Ember.metaPath = function metaPath(obj, path, writable) {
  662. var meta = Ember.meta(obj, writable), keyName, value;
  663. for (var i=0, l=path.length; i<l; i++) {
  664. keyName = path[i];
  665. value = meta[keyName];
  666. if (!value) {
  667. if (!writable) { return undefined; }
  668. value = meta[keyName] = { __ember_source__: obj };
  669. } else if (value.__ember_source__ !== obj) {
  670. if (!writable) { return undefined; }
  671. value = meta[keyName] = o_create(value);
  672. value.__ember_source__ = obj;
  673. }
  674. meta = value;
  675. }
  676. return value;
  677. };
  678. /**
  679. @private
  680. Wraps the passed function so that `this._super` will point to the superFunc
  681. when the function is invoked. This is the primitive we use to implement
  682. calls to super.
  683. @method wrap
  684. @for Ember
  685. @param {Function} func The function to call
  686. @param {Function} superFunc The super function.
  687. @return {Function} wrapped function.
  688. */
  689. Ember.wrap = function(func, superFunc) {
  690. function K() {}
  691. function superWrapper() {
  692. var ret, sup = this._super;
  693. this._super = superFunc || K;
  694. ret = func.apply(this, arguments);
  695. this._super = sup;
  696. return ret;
  697. }
  698. superWrapper.wrappedFunction = func;
  699. superWrapper.__ember_observes__ = func.__ember_observes__;
  700. superWrapper.__ember_observesBefore__ = func.__ember_observesBefore__;
  701. return superWrapper;
  702. };
  703. /**
  704. Returns true if the passed object is an array or Array-like.
  705. Ember Array Protocol:
  706. - the object has an objectAt property
  707. - the object is a native Array
  708. - the object is an Object, and has a length property
  709. Unlike `Ember.typeOf` this method returns true even if the passed object is
  710. not formally array but appears to be array-like (i.e. implements `Ember.Array`)
  711. ```javascript
  712. Ember.isArray(); // false
  713. Ember.isArray([]); // true
  714. Ember.isArray( Ember.ArrayProxy.create({ content: [] }) ); // true
  715. ```
  716. @method isArray
  717. @for Ember
  718. @param {Object} obj The object to test
  719. @return {Boolean}
  720. */
  721. Ember.isArray = function(obj) {
  722. if (!obj || obj.setInterval) { return false; }
  723. if (Array.isArray && Array.isArray(obj)) { return true; }
  724. if (Ember.Array && Ember.Array.detect(obj)) { return true; }
  725. if ((obj.length !== undefined) && 'object'===typeof obj) { return true; }
  726. return false;
  727. };
  728. /**
  729. Forces the passed object to be part of an array. If the object is already
  730. an array or array-like, returns the object. Otherwise adds the object to
  731. an array. If obj is `null` or `undefined`, returns an empty array.
  732. ```javascript
  733. Ember.makeArray(); // []
  734. Ember.makeArray(null); // []
  735. Ember.makeArray(undefined); // []
  736. Ember.makeArray('lindsay'); // ['lindsay']
  737. Ember.makeArray([1,2,42]); // [1,2,42]
  738. var controller = Ember.ArrayProxy.create({ content: [] });
  739. Ember.makeArray(controller) === controller; // true
  740. ```
  741. @method makeArray
  742. @for Ember
  743. @param {Object} obj the object
  744. @return {Array}
  745. */
  746. Ember.makeArray = function(obj) {
  747. if (obj === null || obj === undefined) { return []; }
  748. return Ember.isArray(obj) ? obj : [obj];
  749. };
  750. function canInvoke(obj, methodName) {
  751. return !!(obj && typeof obj[methodName] === 'function');
  752. }
  753. /**
  754. Checks to see if the `methodName` exists on the `obj`.
  755. @method canInvoke
  756. @for Ember
  757. @param {Object} obj The object to check for the method
  758. @param {String} methodName The method name to check for
  759. */
  760. Ember.canInvoke = canInvoke;
  761. /**
  762. Checks to see if the `methodName` exists on the `obj`,
  763. and if it does, invokes it with the arguments passed.
  764. @method tryInvoke
  765. @for Ember
  766. @param {Object} obj The object to check for the method
  767. @param {String} methodName The method name to check for
  768. @param {Array} [args] The arguments to pass to the method
  769. @return {anything} the return value of the invoked method or undefined if it cannot be invoked
  770. */
  771. Ember.tryInvoke = function(obj, methodName, args) {
  772. if (canInvoke(obj, methodName)) {
  773. return obj[methodName].apply(obj, args || []);
  774. }
  775. };
  776. // https://github.com/emberjs/ember.js/pull/1617
  777. var needsFinallyFix = (function() {
  778. var count = 0;
  779. try{
  780. try { }
  781. finally {
  782. count++;
  783. throw new Error('needsFinallyFixTest');
  784. }
  785. } catch (e) {}
  786. return count !== 1;
  787. })();
  788. /**
  789. Provides try { } finally { } functionality, while working
  790. around Safari's double finally bug.
  791. @method tryFinally
  792. @for Ember
  793. @param {Function} function The function to run the try callback
  794. @param {Function} function The function to run the finally callback
  795. @param [binding]
  796. @return {anything} The return value is the that of the finalizer,
  797. unless that valueis undefined, in which case it is the return value
  798. of the tryable
  799. */
  800. if (needsFinallyFix) {
  801. Ember.tryFinally = function(tryable, finalizer, binding) {
  802. var result, finalResult, finalError;
  803. binding = binding || this;
  804. try {
  805. result = tryable.call(binding);
  806. } finally {
  807. try {
  808. finalResult = finalizer.call(binding);
  809. } catch (e){
  810. finalError = e;
  811. }
  812. }
  813. if (finalError) { throw finalError; }
  814. return (finalResult === undefined) ? result : finalResult;
  815. };
  816. } else {
  817. Ember.tryFinally = function(tryable, finalizer, binding) {
  818. var result, finalResult;
  819. binding = binding || this;
  820. try {
  821. result = tryable.call(binding);
  822. } finally {
  823. finalResult = finalizer.call(binding);
  824. }
  825. return (finalResult === undefined) ? result : finalResult;
  826. };
  827. }
  828. /**
  829. Provides try { } catch finally { } functionality, while working
  830. around Safari's double finally bug.
  831. @method tryCatchFinally
  832. @for Ember
  833. @param {Function} function The function to run the try callback
  834. @param {Function} function The function to run the catchable callback
  835. @param {Function} function The function to run the finally callback
  836. @param [binding]
  837. @return {anything} The return value is the that of the finalizer,
  838. unless that value is undefined, in which case it is the return value
  839. of the tryable.
  840. */
  841. if (needsFinallyFix) {
  842. Ember.tryCatchFinally = function(tryable, catchable, finalizer, binding) {
  843. var result, finalResult, finalError, finalReturn;
  844. binding = binding || this;
  845. try {
  846. result = tryable.call(binding);
  847. } catch(error) {
  848. result = catchable.call(binding, error);
  849. } finally {
  850. try {
  851. finalResult = finalizer.call(binding);
  852. } catch (e){
  853. finalError = e;
  854. }
  855. }
  856. if (finalError) { throw finalError; }
  857. return (finalResult === undefined) ? result : finalResult;
  858. };
  859. } else {
  860. Ember.tryCatchFinally = function(tryable, catchable, finalizer, binding) {
  861. var result, finalResult;
  862. binding = binding || this;
  863. try {
  864. result = tryable.call(binding);
  865. } catch(error) {
  866. result = catchable.call(binding, error);
  867. } finally {
  868. finalResult = finalizer.call(binding);
  869. }
  870. return (finalResult === undefined) ? result : finalResult;
  871. };
  872. }
  873. })();
  874. (function() {
  875. // Ember.tryCatchFinally
  876. /**
  877. The purpose of the Ember Instrumentation module is
  878. to provide efficient, general-purpose instrumentation
  879. for Ember.
  880. Subscribe to a listener by using `Ember.subscribe`:
  881. ```javascript
  882. Ember.subscribe("render", {
  883. before: function(name, timestamp, payload) {
  884. },
  885. after: function(name, timestamp, payload) {
  886. }
  887. });
  888. ```
  889. If you return a value from the `before` callback, that same
  890. value will be passed as a fourth parameter to the `after`
  891. callback.
  892. Instrument a block of code by using `Ember.instrument`:
  893. ```javascript
  894. Ember.instrument("render.handlebars", payload, function() {
  895. // rendering logic
  896. }, binding);
  897. ```
  898. Event names passed to `Ember.instrument` are namespaced
  899. by periods, from more general to more specific. Subscribers
  900. can listen for events by whatever level of granularity they
  901. are interested in.
  902. In the above example, the event is `render.handlebars`,
  903. and the subscriber listened for all events beginning with
  904. `render`. It would receive callbacks for events named
  905. `render`, `render.handlebars`, `render.container`, or
  906. even `render.handlebars.layout`.
  907. @class Instrumentation
  908. @namespace Ember
  909. @static
  910. */
  911. Ember.Instrumentation = {};
  912. var subscribers = [], cache = {};
  913. var populateListeners = function(name) {
  914. var listeners = [], subscriber;
  915. for (var i=0, l=subscribers.length; i<l; i++) {
  916. subscriber = subscribers[i];
  917. if (subscriber.regex.test(name)) {
  918. listeners.push(subscriber.object);
  919. }
  920. }
  921. cache[name] = listeners;
  922. return listeners;
  923. };
  924. var time = (function() {
  925. var perf = 'undefined' !== typeof window ? window.performance || {} : {};
  926. var fn = perf.now || perf.mozNow || perf.webkitNow || perf.msNow || perf.oNow;
  927. // fn.bind will be available in all the browsers that support the advanced window.performance... ;-)
  928. return fn ? fn.bind(perf) : function() { return +new Date(); };
  929. })();
  930. Ember.Instrumentation.instrument = function(name, payload, callback, binding) {
  931. var listeners = cache[name], timeName, ret;
  932. if (Ember.STRUCTURED_PROFILE) {
  933. timeName = name + ": " + payload.object;
  934. console.time(timeName);
  935. }
  936. if (!listeners) {
  937. listeners = populateListeners(name);
  938. }
  939. if (listeners.length === 0) {
  940. ret = callback.call(binding);
  941. if (Ember.STRUCTURED_PROFILE) { console.timeEnd(timeName); }
  942. return ret;
  943. }
  944. var beforeValues = [], listener, i, l;
  945. function tryable(){
  946. for (i=0, l=listeners.length; i<l; i++) {
  947. listener = listeners[i];
  948. beforeValues[i] = listener.before(name, time(), payload);
  949. }
  950. return callback.call(binding);
  951. }
  952. function catchable(e){
  953. payload = payload || {};
  954. payload.exception = e;
  955. }
  956. function finalizer() {
  957. for (i=0, l=listeners.length; i<l; i++) {
  958. listener = listeners[i];
  959. listener.after(name, time(), payload, beforeValues[i]);
  960. }
  961. if (Ember.STRUCTURED_PROFILE) {
  962. console.timeEnd(timeName);
  963. }
  964. }
  965. return Ember.tryCatchFinally(tryable, catchable, finalizer);
  966. };
  967. Ember.Instrumentation.subscribe = function(pattern, object) {
  968. var paths = pattern.split("."), path, regex = [];
  969. for (var i=0, l=paths.length; i<l; i++) {
  970. path = paths[i];
  971. if (path === "*") {
  972. regex.push("[^\\.]*");
  973. } else {
  974. regex.push(path);
  975. }
  976. }
  977. regex = regex.join("\\.");
  978. regex = regex + "(\\..*)?";
  979. var subscriber = {
  980. pattern: pattern,
  981. regex: new RegExp("^" + regex + "$"),
  982. object: object
  983. };
  984. subscribers.push(subscriber);
  985. cache = {};
  986. return subscriber;
  987. };
  988. Ember.Instrumentation.unsubscribe = function(subscriber) {
  989. var index;
  990. for (var i=0, l=subscribers.length; i<l; i++) {
  991. if (subscribers[i] === subscriber) {
  992. index = i;
  993. }
  994. }
  995. subscribers.splice(index, 1);
  996. cache = {};
  997. };
  998. Ember.Instrumentation.reset = function() {
  999. subscribers = [];
  1000. cache = {};
  1001. };
  1002. Ember.instrument = Ember.Instrumentation.instrument;
  1003. Ember.subscribe = Ember.Instrumentation.subscribe;
  1004. })();
  1005. (function() {
  1006. var utils = Ember.EnumerableUtils = {
  1007. map: function(obj, callback, thisArg) {
  1008. return obj.map ? obj.map.call(obj, callback, thisArg) : Array.prototype.map.call(obj, callback, thisArg);
  1009. },
  1010. forEach: function(obj, callback, thisArg) {
  1011. return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : Array.prototype.forEach.call(obj, callback, thisArg);
  1012. },
  1013. indexOf: function(obj, element, index) {
  1014. return obj.indexOf ? obj.indexOf.call(obj, element, index) : Array.prototype.indexOf.call(obj, element, index);
  1015. },
  1016. indexesOf: function(obj, elements) {
  1017. return elements === undefined ? [] : utils.map(elements, function(item) {
  1018. return utils.indexOf(obj, item);
  1019. });
  1020. },
  1021. addObject: function(array, item) {
  1022. var index = utils.indexOf(array, item);
  1023. if (index === -1) { array.push(item); }
  1024. },
  1025. removeObject: function(array, item) {
  1026. var index = utils.indexOf(array, item);
  1027. if (index !== -1) { array.splice(index, 1); }
  1028. },
  1029. replace: function(array, idx, amt, objects) {
  1030. if (array.replace) {
  1031. return array.replace(idx, amt, objects);
  1032. } else {
  1033. var args = Array.prototype.concat.apply([idx, amt], objects);
  1034. return array.splice.apply(array, args);
  1035. }
  1036. },
  1037. intersection: function(array1, array2) {
  1038. var intersection = [];
  1039. array1.forEach(function(element) {
  1040. if (array2.indexOf(element) >= 0) {
  1041. intersection.push(element);
  1042. }
  1043. });
  1044. return intersection;
  1045. }
  1046. };
  1047. })();
  1048. (function() {
  1049. /*jshint newcap:false*/
  1050. /**
  1051. @module ember-metal
  1052. */
  1053. // NOTE: There is a bug in jshint that doesn't recognize `Object()` without `new`
  1054. // as being ok unless both `newcap:false` and not `use strict`.
  1055. // https://github.com/jshint/jshint/issues/392
  1056. // Testing this is not ideal, but we want to use native functions
  1057. // if available, but not to use versions created by libraries like Prototype
  1058. var isNativeFunc = function(func) {
  1059. // This should probably work in all browsers likely to have ES5 array methods
  1060. return func && Function.prototype.toString.call(func).indexOf('[native code]') > -1;
  1061. };
  1062. // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map
  1063. var arrayMap = isNativeFunc(Array.prototype.map) ? Array.prototype.map : function(fun /*, thisp */) {
  1064. //"use strict";
  1065. if (this === void 0 || this === null) {
  1066. throw new TypeError();
  1067. }
  1068. var t = Object(this);
  1069. var len = t.length >>> 0;
  1070. if (typeof fun !== "function") {
  1071. throw new TypeError();
  1072. }
  1073. var res = new Array(len);
  1074. var thisp = arguments[1];
  1075. for (var i = 0; i < len; i++) {
  1076. if (i in t) {
  1077. res[i] = fun.call(thisp, t[i], i, t);
  1078. }
  1079. }
  1080. return res;
  1081. };
  1082. // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach
  1083. var arrayForEach = isNativeFunc(Array.prototype.forEach) ? Array.prototype.forEach : function(fun /*, thisp */) {
  1084. //"use strict";
  1085. if (this === void 0 || this === null) {
  1086. throw new TypeError();
  1087. }
  1088. var t = Object(this);
  1089. var len = t.length >>> 0;
  1090. if (typeof fun !== "function") {
  1091. throw new TypeError();
  1092. }
  1093. var thisp = arguments[1];
  1094. for (var i = 0; i < len; i++) {
  1095. if (i in t) {
  1096. fun.call(thisp, t[i], i, t);
  1097. }
  1098. }
  1099. };
  1100. var arrayIndexOf = isNativeFunc(Array.prototype.indexOf) ? Array.prototype.indexOf : function (obj, fromIndex) {
  1101. if (fromIndex === null || fromIndex === undefined) { fromIndex = 0; }
  1102. else if (fromIndex < 0) { fromIndex = Math.max(0, this.length + fromIndex); }
  1103. for (var i = fromIndex, j = this.length; i < j; i++) {
  1104. if (this[i] === obj) { return i; }
  1105. }
  1106. return -1;
  1107. };
  1108. Ember.ArrayPolyfills = {
  1109. map: arrayMap,
  1110. forEach: arrayForEach,
  1111. indexOf: arrayIndexOf
  1112. };
  1113. if (Ember.SHIM_ES5) {
  1114. if (!Array.prototype.map) {
  1115. Array.prototype.map = arrayMap;
  1116. }
  1117. if (!Array.prototype.forEach) {
  1118. Array.prototype.forEach = arrayForEach;
  1119. }
  1120. if (!Array.prototype.indexOf) {
  1121. Array.prototype.indexOf = arrayIndexOf;
  1122. }
  1123. }
  1124. })();
  1125. (function() {
  1126. /**
  1127. @module ember-metal
  1128. */
  1129. /*
  1130. JavaScript (before ES6) does not have a Map implementation. Objects,
  1131. which are often used as dictionaries, may only have Strings as keys.
  1132. Because Ember has a way to get a unique identifier for every object
  1133. via `Ember.guidFor`, we can implement a performant Map with arbitrary
  1134. keys. Because it is commonly used in low-level bookkeeping, Map is
  1135. implemented as a pure JavaScript object for performance.
  1136. This implementation follows the current iteration of the ES6 proposal for
  1137. maps (http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets),
  1138. with two exceptions. First, because we need our implementation to be pleasant
  1139. on older browsers, we do not use the `delete` name (using `remove` instead).
  1140. Second, as we do not have the luxury of in-VM iteration, we implement a
  1141. forEach method for iteration.
  1142. Map is mocked out to look like an Ember object, so you can do
  1143. `Ember.Map.create()` for symmetry with other Ember classes.
  1144. */
  1145. var guidFor = Ember.guidFor,
  1146. indexOf = Ember.ArrayPolyfills.indexOf;
  1147. var copy = function(obj) {
  1148. var output = {};
  1149. for (var prop in obj) {
  1150. if (obj.hasOwnProperty(prop)) { output[prop] = obj[prop]; }
  1151. }
  1152. return output;
  1153. };
  1154. var copyMap = function(original, newObject) {
  1155. var keys = original.keys.copy(),
  1156. values = copy(original.values);
  1157. newObject.keys = keys;
  1158. newObject.values = values;
  1159. return newObject;
  1160. };
  1161. /**
  1162. This class is used internally by Ember and Ember Data.
  1163. Please do not use it at this time. We plan to clean it up
  1164. and add many tests soon.
  1165. @class OrderedSet
  1166. @namespace Ember
  1167. @constructor
  1168. @private
  1169. */
  1170. var OrderedSet = Ember.OrderedSet = function() {
  1171. this.clear();
  1172. };
  1173. /**
  1174. @method create
  1175. @static
  1176. @return {Ember.OrderedSet}
  1177. */
  1178. OrderedSet.create = function() {
  1179. return new OrderedSet();
  1180. };
  1181. OrderedSet.prototype = {
  1182. /**
  1183. @method clear
  1184. */
  1185. clear: function() {
  1186. this.presenceSet = {};
  1187. this.list = [];
  1188. },
  1189. /**
  1190. @method add
  1191. @param obj
  1192. */
  1193. add: function(obj) {
  1194. var guid = guidFor(obj),
  1195. presenceSet = this.presenceSet,
  1196. list = this.list;
  1197. if (guid in presenceSet) { return; }
  1198. presenceSet[guid] = true;
  1199. list.push(obj);
  1200. },
  1201. /**
  1202. @method remove
  1203. @param obj
  1204. */
  1205. remove: function(obj) {
  1206. var guid = guidFor(obj),
  1207. presenceSet = this.presenceSet,
  1208. list = this.list;
  1209. delete presenceSet[guid];
  1210. var index = indexOf.call(list, obj);
  1211. if (index > -1) {
  1212. list.splice(index, 1);
  1213. }
  1214. },
  1215. /**
  1216. @method isEmpty
  1217. @return {Boolean}
  1218. */
  1219. isEmpty: function() {
  1220. return this.list.length === 0;
  1221. },
  1222. /**
  1223. @method has
  1224. @param obj
  1225. @return {Boolean}
  1226. */
  1227. has: function(obj) {
  1228. var guid = guidFor(obj),
  1229. presenceSet = this.presenceSet;
  1230. return guid in presenceSet;
  1231. },
  1232. /**
  1233. @method forEach
  1234. @param {Function} function
  1235. @param target
  1236. */
  1237. forEach: function(fn, self) {
  1238. // allow mutation during iteration
  1239. var list = this.list.slice();
  1240. for (var i = 0, j = list.length; i < j; i++) {
  1241. fn.call(self, list[i]);
  1242. }
  1243. },
  1244. /**
  1245. @method toArray
  1246. @return {Array}
  1247. */
  1248. toArray: function() {
  1249. return this.list.slice();
  1250. },
  1251. /**
  1252. @method copy
  1253. @return {Ember.OrderedSet}
  1254. */
  1255. copy: function() {
  1256. var set = new OrderedSet();
  1257. set.presenceSet = copy(this.presenceSet);
  1258. set.list = this.list.slice();
  1259. return set;
  1260. }
  1261. };
  1262. /**
  1263. A Map stores values indexed by keys. Unlike JavaScript's
  1264. default Objects, the keys of a Map can be any JavaScript
  1265. object.
  1266. Internally, a Map has two data structures:
  1267. 1. `keys`: an OrderedSet of all of the existing keys
  1268. 2. `values`: a JavaScript Object indexed by the `Ember.guidFor(key)`
  1269. When a key/value pair is added for the first time, we
  1270. add the key to the `keys` OrderedSet, and create or
  1271. replace an entry in `values`. When an entry is deleted,
  1272. we delete its entry in `keys` and `values`.
  1273. @class Map
  1274. @namespace Ember
  1275. @private
  1276. @constructor
  1277. */
  1278. var Map = Ember.Map = function() {
  1279. this.keys = Ember.OrderedSet.create();
  1280. this.values = {};
  1281. };
  1282. /**
  1283. @method create
  1284. @static
  1285. */
  1286. Map.create = function() {
  1287. return new Map();
  1288. };
  1289. Map.prototype = {
  1290. /**
  1291. Retrieve the value associated with a given key.
  1292. @method get
  1293. @param {anything} key
  1294. @return {anything} the value associated with the key, or `undefined`
  1295. */
  1296. get: function(key) {
  1297. var values = this.values,
  1298. guid = guidFor(key);
  1299. return values[guid];
  1300. },
  1301. /**
  1302. Adds a value to the map. If a value for the given key has already been
  1303. provided, the new value will replace the old value.
  1304. @method set
  1305. @param {anything} key
  1306. @param {anything} value
  1307. */
  1308. set: function(key, value) {
  1309. var keys = this.keys,
  1310. values = this.values,
  1311. guid = guidFor(key);
  1312. keys.add(key);
  1313. values[guid] = value;
  1314. },
  1315. /**
  1316. Removes a value from the map for an associated key.
  1317. @method remove
  1318. @param {anything} key
  1319. @return {Boolean} true if an item was removed, false otherwise
  1320. */
  1321. remove: function(key) {
  1322. // don't use ES6 "delete" because it will be annoying
  1323. // to use in browsers that are not ES6 friendly;
  1324. var keys = this.keys,
  1325. values = this.values,
  1326. guid = guidFor(key),
  1327. value;
  1328. if (values.hasOwnProperty(guid)) {
  1329. keys.remove(key);
  1330. value = values[guid];
  1331. delete values[guid];
  1332. return true;
  1333. } else {
  1334. return false;
  1335. }
  1336. },
  1337. /**
  1338. Check whether a key is present.
  1339. @method has
  1340. @param {anything} key
  1341. @return {Boolean} true if the item was present, false otherwise
  1342. */
  1343. has: function(key) {
  1344. var values = this.values,
  1345. guid = guidFor(key);
  1346. return values.hasOwnProperty(guid);
  1347. },
  1348. /**
  1349. Iterate over all the keys and values. Calls the function once
  1350. for each key, passing in the key and value, in that order.
  1351. The keys are guaranteed to be iterated over in insertion order.
  1352. @method forEach
  1353. @param {Function} callback
  1354. @param {anything} self if passed, the `this` value inside the
  1355. callback. By default, `this` is the map.
  1356. */
  1357. forEach: function(callback, self) {
  1358. var keys = this.keys,
  1359. values = this.values;
  1360. keys.forEach(function(key) {
  1361. var guid = guidFor(key);
  1362. callback.call(self, key, values[guid]);
  1363. });
  1364. },
  1365. /**
  1366. @method copy
  1367. @return {Ember.Map}
  1368. */
  1369. copy: function() {
  1370. return copyMap(this, new Map());
  1371. }
  1372. };
  1373. /**
  1374. @class MapWithDefault
  1375. @namespace Ember
  1376. @extends Ember.Map
  1377. @private
  1378. @constructor
  1379. @param [options]
  1380. @param {anything} [options.defaultValue]
  1381. */
  1382. var MapWithDefault = Ember.MapWithDefault = function(options) {
  1383. Map.call(this);
  1384. this.defaultValue = options.defaultValue;
  1385. };
  1386. /**
  1387. @method create
  1388. @static
  1389. @param [options]
  1390. @param {anything} [options.defaultValue]
  1391. @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns
  1392. `Ember.MapWithDefault` otherwise returns `Ember.Map`
  1393. */
  1394. MapWithDefault.create = function(options) {
  1395. if (options) {
  1396. return new MapWithDefault(options);
  1397. } else {
  1398. return new Map();
  1399. }
  1400. };
  1401. MapWithDefault.prototype = Ember.create(Map.prototype);
  1402. /**
  1403. Retrieve the value associated with a given key.
  1404. @method get
  1405. @param {anything} key
  1406. @return {anything} the value associated with the key, or the default value
  1407. */
  1408. MapWithDefault.prototype.get = function(key) {
  1409. var hasValue = this.has(key);
  1410. if (hasValue) {
  1411. return Map.prototype.get.call(this, key);
  1412. } else {
  1413. var defaultValue = this.defaultValue(key);
  1414. this.set(key, defaultValue);
  1415. return defaultValue;
  1416. }
  1417. };
  1418. /**
  1419. @method copy
  1420. @return {Ember.MapWithDefault}
  1421. */
  1422. MapWithDefault.prototype.copy = function() {
  1423. return copyMap(this, new MapWithDefault({
  1424. defaultValue: this.defaultValue
  1425. }));
  1426. };
  1427. })();
  1428. (function() {
  1429. /**
  1430. @module ember-metal
  1431. */
  1432. var META_KEY = Ember.META_KEY, get, set;
  1433. var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER;
  1434. var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/;
  1435. var IS_GLOBAL_PATH = /^([A-Z$]|([0-9][A-Z$])).*[\.\*]/;
  1436. var HAS_THIS = /^this[\.\*]/;
  1437. var FIRST_KEY = /^([^\.\*]+)/;
  1438. // ..........................................................
  1439. // GET AND SET
  1440. //
  1441. // If we are on a platform that supports accessors we can get use those.
  1442. // Otherwise simulate accessors by looking up the property directly on the
  1443. // object.
  1444. /**
  1445. Gets the value of a property on an object. If the property is computed,
  1446. the function will be invoked. If the property is not defined but the
  1447. object implements the `unknownProperty` method then that will be invoked.
  1448. If you plan to run on IE8 and older browsers then you should use this
  1449. method anytime you want to retrieve a property on an object that you don't
  1450. know for sure is private. (Properties beginning with an underscore '_'
  1451. are considered private.)
  1452. On all newer browsers, you only need to use this method to retrieve
  1453. properties if the property might not be defined on the object and you want
  1454. to respect the `unknownProperty` handler. Otherwise you can ignore this
  1455. method.
  1456. Note that if the object itself is `undefined`, this method will throw
  1457. an error.
  1458. @method get
  1459. @for Ember
  1460. @param {Object} obj The object to retrieve from.
  1461. @param {String} keyName The property key to retrieve
  1462. @return {Object} the property value or `null`.
  1463. */
  1464. get = function get(obj, keyName) {
  1465. // Helpers that operate with 'this' within an #each
  1466. if (keyName === '') {
  1467. return obj;
  1468. }
  1469. if (!keyName && 'string'===typeof obj) {
  1470. keyName = obj;
  1471. obj = null;
  1472. }
  1473. if (!obj || keyName.indexOf('.') !== -1) {
  1474. Ember.assert("Cannot call get with '"+ keyName +"' on an undefined object.", obj !== undefined);
  1475. return getPath(obj, keyName);
  1476. }
  1477. Ember.assert("You need to provide an object and key to `get`.", !!obj && keyName);
  1478. var meta = obj[META_KEY], desc = meta && meta.descs[keyName], ret;
  1479. if (desc) {
  1480. return desc.get(obj, keyName);
  1481. } else {
  1482. if (MANDATORY_SETTER && meta && meta.watching[keyName] > 0) {
  1483. ret = meta.values[keyName];
  1484. } else {
  1485. ret = obj[keyName];
  1486. }
  1487. if (ret === undefined &&
  1488. 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) {
  1489. return obj.unknownProperty(keyName);
  1490. }
  1491. return ret;
  1492. }
  1493. };
  1494. /**
  1495. Sets the value of a property on an object, respecting computed properties
  1496. and notifying observers and other listeners of the change. If the
  1497. property is not defined but the object implements the `unknownProperty`
  1498. method then that will be invoked as well.
  1499. If you plan to run on IE8 and older browsers then you should use this
  1500. method anytime you want to set a property on an object that you don't
  1501. know for sure is private. (Properties beginning with an underscore '_'
  1502. are considered private.)
  1503. On all newer browsers, you only need to use this method to set
  1504. properties if the property might not be defined on the object and you want
  1505. to respect the `unknownProperty` handler. Otherwise you can ignore this
  1506. method.
  1507. @method set
  1508. @for Ember
  1509. @param {Object} obj The object to modify.
  1510. @param {String} keyName The property key to set
  1511. @param {Object} value The value to set
  1512. @return {Object} the passed value.
  1513. */
  1514. set = function set(obj, keyName, value, tolerant) {
  1515. if (typeof obj === 'string') {
  1516. Ember.assert("Path '" + obj + "' must be global if no obj is given.", IS_GLOBAL.test(obj));
  1517. value = keyName;
  1518. keyName = obj;
  1519. obj = null;
  1520. }
  1521. if (!obj || keyName.indexOf('.') !== -1) {
  1522. return setPath(obj, keyName, value, tolerant);
  1523. }
  1524. Ember.assert("You need to provide an object and key to `set`.", !!obj && keyName !== undefined);
  1525. Ember.assert('calling set on destroyed object', !obj.isDestroyed);
  1526. var meta = obj[META_KEY], desc = meta && meta.descs[keyName],
  1527. isUnknown, currentValue;
  1528. if (desc) {
  1529. desc.set(obj, keyName, value);
  1530. } else {
  1531. isUnknown = 'object' === typeof obj && !(keyName in obj);
  1532. // setUnknownProperty is called if `obj` is an object,
  1533. // the property does not already exist, and the
  1534. // `setUnknownProperty` method exists on the object
  1535. if (isUnknown && 'function' === typeof obj.setUnknownProperty) {
  1536. obj.setUnknownProperty(keyName, value);
  1537. } else if (meta && meta.watching[keyName] > 0) {
  1538. if (MANDATORY_SETTER) {
  1539. currentValue = meta.values[keyName];
  1540. } else {
  1541. currentValue = obj[keyName];
  1542. }
  1543. // only trigger a change if the value has changed
  1544. if (value !== currentValue) {
  1545. Ember.propertyWillChange(obj, keyName);
  1546. if (MANDATORY_SETTER) {
  1547. if (currentValue === undefined && !(keyName in obj)) {
  1548. Ember.defineProperty(obj, keyName, null, value); // setup mandatory setter
  1549. } else {
  1550. meta.values[keyName] = value;
  1551. }
  1552. } else {
  1553. obj[keyName] = value;
  1554. }
  1555. Ember.propertyDidChange(obj, keyName);
  1556. }
  1557. } else {
  1558. obj[keyName] = value;
  1559. }
  1560. }
  1561. return value;
  1562. };
  1563. // Currently used only by Ember Data tests
  1564. if (Ember.config.overrideAccessors) {
  1565. Ember.get = get;
  1566. Ember.set = set;
  1567. Ember.config.overrideAccessors();
  1568. get = Ember.get;
  1569. set = Ember.set;
  1570. }
  1571. function firstKey(path) {
  1572. return path.match(FIRST_KEY)[0];
  1573. }
  1574. // assumes path is already normalized
  1575. function normalizeTuple(target, path) {
  1576. var hasThis = HAS_THIS.test(path),
  1577. isGlobal = !hasThis && IS_GLOBAL_PATH.test(path),
  1578. key;
  1579. if (!target || isGlobal) target = Ember.lookup;
  1580. if (hasThis) path = path.slice(5);
  1581. if (target === Ember.lookup) {
  1582. key = firstKey(path);
  1583. target = get(target, key);
  1584. path = path.slice(key.length+1);
  1585. }
  1586. // must return some kind of path to be valid else other things will break.
  1587. if (!path || path.length===0) throw new Error('Invalid Path');
  1588. return [ target, path ];
  1589. }
  1590. function getPath(root, path) {
  1591. var hasThis, parts, tuple, idx, len;
  1592. // If there is no root and path is a key name, return that
  1593. // property from the global object.
  1594. // E.g. get('Ember') -> Ember
  1595. if (root === null && path.indexOf('.') === -1) { return get(Ember.lookup, path); }
  1596. // detect complicated paths and normalize them
  1597. hasThis = HAS_THIS.test(path);
  1598. if (!root || hasThis) {
  1599. tuple = normalizeTuple(root, path);
  1600. root = tuple[0];
  1601. path = tuple[1];
  1602. tuple.length = 0;
  1603. }
  1604. parts = path.split(".");
  1605. len = parts.length;
  1606. for (idx=0; root && idx<len; idx++) {
  1607. root = get(root, parts[idx], true);
  1608. if (root && root.isDestroyed) { return undefined; }
  1609. }
  1610. return root;
  1611. }
  1612. function setPath(root, path, value, tolerant) {
  1613. var keyName;
  1614. // get the last part of the path
  1615. keyName = path.slice(path.lastIndexOf('.') + 1);
  1616. // get the first part of the part
  1617. path = path.slice(0, path.length-(keyName.length+1));
  1618. // unless the path is this, look up the first part to
  1619. // get the root
  1620. if (path !== 'this') {
  1621. root = getPath(root, path);
  1622. }
  1623. if (!keyName || keyName.length === 0) {
  1624. throw new Error('You passed an empty path');
  1625. }
  1626. if (!root) {
  1627. if (tolerant) { return; }
  1628. else { throw new Error('Object in path '+path+' could not be found or was destroyed.'); }
  1629. }
  1630. return set(root, keyName, value);
  1631. }
  1632. /**
  1633. @private
  1634. Normalizes a target/path pair to reflect that actual target/path that should
  1635. be observed, etc. This takes into account passing in global property
  1636. paths (i.e. a path beginning with a captial letter not defined on the
  1637. target) and * separators.
  1638. @method normalizeTuple
  1639. @for Ember
  1640. @param {Object} target The current target. May be `null`.
  1641. @param {String} path A path on the target or a global property path.
  1642. @return {Array} a temporary array with the normalized target/path pair.
  1643. */
  1644. Ember.normalizeTuple = function(target, path) {
  1645. return normalizeTuple(target, path);
  1646. };
  1647. Ember.getWithDefault = function(root, key, defaultValue) {
  1648. var value = get(root, key);
  1649. if (value === undefined) { return defaultValue; }
  1650. return value;
  1651. };
  1652. Ember.get = get;
  1653. Ember.getPath = Ember.deprecateFunc('getPath is deprecated since get now supports paths', Ember.get);
  1654. Ember.set = set;
  1655. Ember.setPath = Ember.deprecateFunc('setPath is deprecated since set now supports paths', Ember.set);
  1656. /**
  1657. Error-tolerant form of `Ember.set`. Will not blow up if any part of the
  1658. chain is `undefined`, `null`, or destroyed.
  1659. This is primarily used when syncing bindings, which may try to update after
  1660. an object has been destroyed.
  1661. @method trySet
  1662. @for Ember
  1663. @param {Object} obj The object to modify.
  1664. @param {String} keyName The property key to set
  1665. @param {Object} value The value to set
  1666. */
  1667. Ember.trySet = function(root, path, value) {
  1668. return set(root, path, value, true);
  1669. };
  1670. Ember.trySetPath = Ember.deprecateFunc('trySetPath has been renamed to trySet', Ember.trySet);
  1671. /**
  1672. Returns true if the provided path is global (e.g., `MyApp.fooController.bar`)
  1673. instead of local (`foo.bar.baz`).
  1674. @method isGlobalPath
  1675. @for Ember
  1676. @private
  1677. @param {String} path
  1678. @return Boolean
  1679. */
  1680. Ember.isGlobalPath = function(path) {
  1681. return IS_GLOBAL.test(path);
  1682. };
  1683. })();
  1684. (function() {
  1685. /**
  1686. @module ember-metal
  1687. */
  1688. var GUID_KEY = Ember.GUID_KEY,
  1689. META_KEY = Ember.META_KEY,
  1690. EMPTY_META = Ember.EMPTY_META,
  1691. metaFor = Ember.meta,
  1692. o_create = Ember.create,
  1693. objectDefineProperty = Ember.platform.defineProperty;
  1694. var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER;
  1695. // ..........................................................
  1696. // DESCRIPTOR
  1697. //
  1698. /**
  1699. Objects of this type can implement an interface to responds requests to
  1700. get and set. The default implementation handles simple properties.
  1701. You generally won't need to create or subclass this directly.
  1702. @class Descriptor
  1703. @namespace Ember
  1704. @private
  1705. @constructor
  1706. */
  1707. var Descriptor = Ember.Descriptor = function() {};
  1708. // ..........................................................
  1709. // DEFINING PROPERTIES API
  1710. //
  1711. var MANDATORY_SETTER_FUNCTION = Ember.MANDATORY_SETTER_FUNCTION = function(value) {
  1712. Ember.assert("You must use Ember.set() to access this property (of " + this + ")", false);
  1713. };
  1714. var DEFAULT_GETTER_FUNCTION = Ember.DEFAULT_GETTER_FUNCTION = function(name) {
  1715. return function() {
  1716. var meta = this[META_KEY];
  1717. return meta && meta.values[name];
  1718. };
  1719. };
  1720. /**
  1721. @private
  1722. NOTE: This is a low-level method used by other parts of the API. You almost
  1723. never want to call this method directly. Instead you should use
  1724. `Ember.mixin()` to define new properties.
  1725. Defines a property on an object. This method works much like the ES5
  1726. `Object.defineProperty()` method except that it can also accept computed
  1727. properties and other special descriptors.
  1728. Normally this method takes only three parameters. However if you pass an
  1729. instance of `Ember.Descriptor` as the third param then you can pass an
  1730. optional value as the fourth parameter. This is often more efficient than
  1731. creating new descriptor hashes for each property.
  1732. ## Examples
  1733. ```javascript
  1734. // ES5 compatible mode
  1735. Ember.defineProperty(contact, 'firstName', {
  1736. writable: true,
  1737. configurable: false,
  1738. enumerable: true,
  1739. value: 'Charles'
  1740. });
  1741. // define a simple property
  1742. Ember.defineProperty(contact, 'lastName', undefined, 'Jolley');
  1743. // define a computed property
  1744. Ember.defineProperty(contact, 'fullName', Ember.computed(function() {
  1745. return this.firstName+' '+this.lastName;
  1746. }).property('firstName', 'lastName'));
  1747. ```
  1748. @method defineProperty
  1749. @for Ember
  1750. @param {Object} obj the object to define this property on. This may be a prototype.
  1751. @param {String} keyName the name of the property
  1752. @param {Ember.Descriptor} [desc] an instance of `Ember.Descriptor` (typically a
  1753. computed property) or an ES5 descriptor.
  1754. You must provide this or `data` but not both.
  1755. @param {anything} [data] something other than a descriptor, that will
  1756. become the explicit value of this property.
  1757. */
  1758. Ember.defineProperty = function(obj, keyName, desc, data, meta) {
  1759. var descs, existingDesc, watching, value;
  1760. if (!meta) meta = metaFor(obj);
  1761. descs = meta.descs;
  1762. existingDesc = meta.descs[keyName];
  1763. watching = meta.watching[keyName] > 0;
  1764. if (existingDesc instanceof Ember.Descriptor) {
  1765. existingDesc.teardown(obj, keyName);
  1766. }
  1767. if (desc instanceof Ember.Descriptor) {
  1768. value = desc;
  1769. descs[keyName] = desc;
  1770. if (MANDATORY_SETTER && watching) {
  1771. objectDefineProperty(obj, keyName, {
  1772. configurable: true,
  1773. enumerable: true,
  1774. writable: true,
  1775. value: undefined // make enumerable
  1776. });
  1777. } else {
  1778. obj[keyName] = undefined; // make enumerable
  1779. }
  1780. desc.setup(obj, keyName);
  1781. } else {
  1782. descs[keyName] = undefined; // shadow descriptor in proto
  1783. if (desc == null) {
  1784. value = data;
  1785. if (MANDATORY_SETTER && watching) {
  1786. meta.values[keyName] = data;
  1787. objectDefineProperty(obj, keyName, {
  1788. configurable: true,
  1789. enumerable: true,
  1790. set: MANDATORY_SETTER_FUNCTION,
  1791. get: DEFAULT_GETTER_FUNCTION(keyName)
  1792. });
  1793. } else {
  1794. obj[keyName] = data;
  1795. }
  1796. } else {
  1797. value = desc;
  1798. // compatibility with ES5
  1799. objectDefineProperty(obj, keyName, desc);
  1800. }
  1801. }
  1802. // if key is being watched, override chains that
  1803. // were initialized with the prototype
  1804. if (watching) { Ember.overrideChains(obj, keyName, meta); }
  1805. // The `value` passed to the `didDefineProperty` hook is
  1806. // either the descriptor or data, whichever was passed.
  1807. if (obj.didDefineProperty) { obj.didDefineProperty(obj, keyName, value); }
  1808. return this;
  1809. };
  1810. })();
  1811. (function() {
  1812. // Ember.tryFinally
  1813. /**
  1814. @module ember-metal
  1815. */
  1816. var AFTER_OBSERVERS = ':change';
  1817. var BEFORE_OBSERVERS = ':before';
  1818. var guidFor = Ember.guidFor;
  1819. var deferred = 0;
  1820. /*
  1821. this.observerSet = {
  1822. [senderGuid]: { // variable name: `keySet`
  1823. [keyName]: listIndex
  1824. }
  1825. },
  1826. this.observers = [
  1827. {
  1828. sender: obj,
  1829. keyName: keyName,
  1830. eventName: eventName,
  1831. listeners: [
  1832. [target, method, onceFlag, suspendedFlag]
  1833. ]
  1834. },
  1835. ...
  1836. ]
  1837. */
  1838. function ObserverSet() {
  1839. this.clear();
  1840. }
  1841. ObserverSet.prototype.add = function(sender, keyName, eventName) {
  1842. var observerSet = this.observerSet,
  1843. observers = this.observers,
  1844. senderGuid = Ember.guidFor(sender),
  1845. keySet = observerSet[senderGuid],
  1846. index;
  1847. if (!keySet) {
  1848. observerSet[senderGuid] = keySet = {};
  1849. }
  1850. index = keySet[keyName];
  1851. if (index === undefined) {
  1852. index = observers.push({
  1853. sender: sender,
  1854. keyName: keyName,
  1855. eventName: eventName,
  1856. listeners: []
  1857. }) - 1;
  1858. keySet[keyName] = index;
  1859. }
  1860. return observers[index].listeners;
  1861. };
  1862. ObserverSet.prototype.flush = function() {
  1863. var observers = this.observers, i, len, observer, sender;
  1864. this.clear();
  1865. for (i=0, len=observers.length; i < len; ++i) {
  1866. observer = observers[i];
  1867. sender = observer.sender;
  1868. if (sender.isDestroying || sender.isDestroyed) { continue; }
  1869. Ember.sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners);
  1870. }
  1871. };
  1872. ObserverSet.prototype.clear = function() {
  1873. this.observerSet = {};
  1874. this.observers = [];
  1875. };
  1876. var beforeObserverSet = new ObserverSet(), observerSet = new ObserverSet();
  1877. /**
  1878. @method beginPropertyChanges
  1879. @chainable
  1880. */
  1881. Ember.beginPropertyChanges = function() {
  1882. deferred++;
  1883. };
  1884. /**
  1885. @method endPropertyChanges
  1886. */
  1887. Ember.endPropertyChanges = function() {
  1888. deferred--;
  1889. if (deferred<=0) {
  1890. beforeObserverSet.clear();
  1891. observerSet.flush();
  1892. }
  1893. };
  1894. /**
  1895. Make a series of property changes together in an
  1896. exception-safe way.
  1897. ```javascript
  1898. Ember.changeProperties(function() {
  1899. obj1.set('foo', mayBlowUpWhenSet);
  1900. obj2.set('bar', baz);
  1901. });
  1902. ```
  1903. @method changeProperties
  1904. @param {Function} callback
  1905. @param [binding]
  1906. */
  1907. Ember.changeProperties = function(cb, binding){
  1908. Ember.beginPropertyChanges();
  1909. Ember.tryFinally(cb, Ember.endPropertyChanges, binding);
  1910. };
  1911. /**
  1912. Set a list of properties on an object. These properties are set inside
  1913. a single `beginPropertyChanges` and `endPropertyChanges` batch, so
  1914. observers will be buffered.
  1915. @method setProperties
  1916. @param target
  1917. @param {Hash} properties
  1918. @return target
  1919. */
  1920. Ember.setProperties = function(self, hash) {
  1921. Ember.changeProperties(function(){
  1922. for(var prop in hash) {
  1923. if (hash.hasOwnProperty(prop)) Ember.set(self, prop, hash[prop]);
  1924. }
  1925. });
  1926. return self;
  1927. };
  1928. function changeEvent(keyName) {
  1929. return keyName+AFTER_OBSERVERS;
  1930. }
  1931. function beforeEvent(keyName) {
  1932. return keyName+BEFORE_OBSERVERS;
  1933. }
  1934. /**
  1935. @method addObserver
  1936. @param obj
  1937. @param {String} path
  1938. @param {Object|Function} targetOrMethod
  1939. @param {Function|String} [method]
  1940. */
  1941. Ember.addObserver = function(obj, path, target, method) {
  1942. Ember.addListener(obj, changeEvent(path), target, method);
  1943. Ember.watch(obj, path);
  1944. return this;
  1945. };
  1946. Ember.observersFor = function(obj, path) {
  1947. return Ember.listenersFor(obj, changeEvent(path));
  1948. };
  1949. /**
  1950. @method removeObserver
  1951. @param obj
  1952. @param {String} path
  1953. @param {Object|Function} targetOrMethod
  1954. @param {Function|String} [method]
  1955. */
  1956. Ember.removeObserver = function(obj, path, target, method) {
  1957. Ember.unwatch(obj, path);
  1958. Ember.removeListener(obj, changeEvent(path), target, method);
  1959. return this;
  1960. };
  1961. /**
  1962. @method addBeforeObserver
  1963. @param obj
  1964. @param {String} path
  1965. @param {Object|Function} targetOrMethod
  1966. @param {Function|String} [method]
  1967. */
  1968. Ember.addBeforeObserver = function(obj, path, target, method) {
  1969. Ember.addListener(obj, beforeEvent(path), target, method);
  1970. Ember.watch(obj, path);
  1971. return this;
  1972. };
  1973. // Suspend observer during callback.
  1974. //
  1975. // This should only be used by the target of the observer
  1976. // while it is setting the observed path.
  1977. Ember._suspendBeforeObserver = function(obj, path, target, method, callback) {
  1978. return Ember._suspendListener(obj, beforeEvent(path), target, method, callback);
  1979. };
  1980. Ember._suspendObserver = function(obj, path, target, method, callback) {
  1981. return Ember._suspendListener(obj, changeEvent(path), target, method, callback);
  1982. };
  1983. var map = Ember.ArrayPolyfills.map;
  1984. Ember._suspendBeforeObservers = function(obj, paths, target, method, callback) {
  1985. var events = map.call(paths, beforeEvent);
  1986. return Ember._suspendListeners(obj, events, target, method, callback);
  1987. };
  1988. Ember._suspendObservers = function(obj, paths, target, method, callback) {
  1989. var events = map.call(paths, changeEvent);
  1990. return Ember._suspendListeners(obj, events, target, method, callback);
  1991. };
  1992. Ember.beforeObserversFor = function(obj, path) {
  1993. return Ember.listenersFor(obj, beforeEvent(path));
  1994. };
  1995. /**
  1996. @method removeBeforeObserver
  1997. @param obj
  1998. @param {String} path
  1999. @param {Object|Function} targetOrMethod
  2000. @param {Function|String} [method]
  2001. */
  2002. Ember.removeBeforeObserver = function(obj, path, target, method) {
  2003. Ember.unwatch(obj, path);
  2004. Ember.removeListener(obj, beforeEvent(path), target, method);
  2005. return this;
  2006. };
  2007. Ember.notifyBeforeObservers = function(obj, keyName) {
  2008. if (obj.isDestroying) { return; }
  2009. var eventName = beforeEvent(keyName), listeners, listenersDiff;
  2010. if (deferred) {
  2011. listeners = beforeObserverSet.add(obj, keyName, eventName);
  2012. listenersDiff = Ember.listenersDiff(obj, eventName, listeners);
  2013. Ember.sendEvent(obj, eventName, [obj, keyName], listenersDiff);
  2014. } else {
  2015. Ember.sendEvent(obj, eventName, [obj, keyName]);
  2016. }
  2017. };
  2018. Ember.notifyObservers = function(obj, keyName) {
  2019. if (obj.isDestroying) { return; }
  2020. var eventName = changeEvent(keyName), listeners;
  2021. if (deferred) {
  2022. listeners = observerSet.add(obj, keyName, eventName);
  2023. Ember.listenersUnion(obj, eventName, listeners);
  2024. } else {
  2025. Ember.sendEvent(obj, eventName, [obj, keyName]);
  2026. }
  2027. };
  2028. })();
  2029. (function() {
  2030. /**
  2031. @module ember-metal
  2032. */
  2033. var guidFor = Ember.guidFor, // utils.js
  2034. metaFor = Ember.meta, // utils.js
  2035. get = Ember.get, // accessors.js
  2036. set = Ember.set, // accessors.js
  2037. normalizeTuple = Ember.normalizeTuple, // accessors.js
  2038. GUID_KEY = Ember.GUID_KEY, // utils.js
  2039. META_KEY = Ember.META_KEY, // utils.js
  2040. // circular reference observer depends on Ember.watch
  2041. // we should move change events to this file or its own property_events.js
  2042. notifyObservers = Ember.notifyObservers, // observer.js
  2043. forEach = Ember.ArrayPolyfills.forEach, // array.js
  2044. FIRST_KEY = /^([^\.\*]+)/,
  2045. IS_PATH = /[\.\*]/;
  2046. var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER,
  2047. o_defineProperty = Ember.platform.defineProperty;
  2048. function firstKey(path) {
  2049. return path.match(FIRST_KEY)[0];
  2050. }
  2051. // returns true if the passed path is just a keyName
  2052. function isKeyName(path) {
  2053. return path==='*' || !IS_PATH.test(path);
  2054. }
  2055. // ..........................................................
  2056. // DEPENDENT KEYS
  2057. //
  2058. function iterDeps(method, obj, depKey, seen, meta) {
  2059. var guid = guidFor(obj);
  2060. if (!seen[guid]) seen[guid] = {};
  2061. if (seen[guid][depKey]) return;
  2062. seen[guid][depKey] = true;
  2063. var deps = meta.deps;
  2064. deps = deps && deps[depKey];
  2065. if (deps) {
  2066. for(var key in deps) {
  2067. var desc = meta.descs[key];
  2068. if (desc && desc._suspended === obj) continue;
  2069. method(obj, key);
  2070. }
  2071. }
  2072. }
  2073. var WILL_SEEN, DID_SEEN;
  2074. // called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...)
  2075. function dependentKeysWillChange(obj, depKey, meta) {
  2076. if (obj.isDestroying) { return; }
  2077. var seen = WILL_SEEN, top = !seen;
  2078. if (top) { seen = WILL_SEEN = {}; }
  2079. iterDeps(propertyWillChange, obj, depKey, seen, meta);
  2080. if (top) { WILL_SEEN = null; }
  2081. }
  2082. // called whenever a property has just changed to update dependent keys
  2083. function dependentKeysDidChange(obj, depKey, meta) {
  2084. if (obj.isDestroying) { return; }
  2085. var seen = DID_SEEN, top = !seen;
  2086. if (top) { seen = DID_SEEN = {}; }
  2087. iterDeps(propertyDidChange, obj, depKey, seen, meta);
  2088. if (top) { DID_SEEN = null; }
  2089. }
  2090. // ..........................................................
  2091. // CHAIN
  2092. //
  2093. function addChainWatcher(obj, keyName, node) {
  2094. if (!obj || ('object' !== typeof obj)) { return; } // nothing to do
  2095. var m = metaFor(obj), nodes = m.chainWatchers;
  2096. if (!m.hasOwnProperty('chainWatchers')) {
  2097. nodes = m.chainWatchers = {};
  2098. }
  2099. if (!nodes[keyName]) { nodes[keyName] = []; }
  2100. nodes[keyName].push(node);
  2101. Ember.watch(obj, keyName);
  2102. }
  2103. function removeChainWatcher(obj, keyName, node) {
  2104. if (!obj || 'object' !== typeof obj) { return; } // nothing to do
  2105. var m = metaFor(obj, false);
  2106. if (!m.hasOwnProperty('chainWatchers')) { return; } // nothing to do
  2107. var nodes = m.chainWatchers;
  2108. if (nodes[keyName]) {
  2109. nodes = nodes[keyName];
  2110. for (var i = 0, l = nodes.length; i < l; i++) {
  2111. if (nodes[i] === node) { nodes.splice(i, 1); }
  2112. }
  2113. }
  2114. Ember.unwatch(obj, keyName);
  2115. }
  2116. var pendingQueue = [];
  2117. // attempts to add the pendingQueue chains again. If some of them end up
  2118. // back in the queue and reschedule is true, schedules a timeout to try
  2119. // again.
  2120. function flushPendingChains() {
  2121. if (pendingQueue.length === 0) { return; } // nothing to do
  2122. var queue = pendingQueue;
  2123. pendingQueue = [];
  2124. forEach.call(queue, function(q) { q[0].add(q[1]); });
  2125. Ember.warn('Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0);
  2126. }
  2127. function isProto(pvalue) {
  2128. return metaFor(pvalue, false).proto === pvalue;
  2129. }
  2130. // A ChainNode watches a single key on an object. If you provide a starting
  2131. // value for the key then the node won't actually watch it. For a root node
  2132. // pass null for parent and key and object for value.
  2133. var ChainNode = function(parent, key, value) {
  2134. var obj;
  2135. this._parent = parent;
  2136. this._key = key;
  2137. // _watching is true when calling get(this._parent, this._key) will
  2138. // return the value of this node.
  2139. //
  2140. // It is false for the root of a chain (because we have no parent)
  2141. // and for global paths (because the parent node is the object with
  2142. // the observer on it)
  2143. this._watching = value===undefined;
  2144. this._value = value;
  2145. this._paths = {};
  2146. if (this._watching) {
  2147. this._object = parent.value();
  2148. if (this._object) { addChainWatcher(this._object, this._key, this); }
  2149. }
  2150. // Special-case: the EachProxy relies on immediate evaluation to
  2151. // establish its observers.
  2152. //
  2153. // TODO: Replace this with an efficient callback that the EachProxy
  2154. // can implement.
  2155. if (this._parent && this._parent._key === '@each') {
  2156. this.value();
  2157. }
  2158. };
  2159. var ChainNodePrototype = ChainNode.prototype;
  2160. ChainNodePrototype.value = function() {
  2161. if (this._value === undefined && this._watching) {
  2162. var obj = this._parent.value();
  2163. this._value = (obj && !isProto(obj)) ? get(obj, this._key) : undefined;
  2164. }
  2165. return this._value;
  2166. };
  2167. ChainNodePrototype.destroy = function() {
  2168. if (this._watching) {
  2169. var obj = this._object;
  2170. if (obj) { removeChainWatcher(obj, this._key, this); }
  2171. this._watching = false; // so future calls do nothing
  2172. }
  2173. };
  2174. // copies a top level object only
  2175. ChainNodePrototype.copy = function(obj) {
  2176. var ret = new ChainNode(null, null, obj),
  2177. paths = this._paths, path;
  2178. for (path in paths) {
  2179. if (paths[path] <= 0) { continue; } // this check will also catch non-number vals.
  2180. ret.add(path);
  2181. }
  2182. return ret;
  2183. };
  2184. // called on the root node of a chain to setup watchers on the specified
  2185. // path.
  2186. ChainNodePrototype.add = function(path) {
  2187. var obj, tuple, key, src, paths;
  2188. paths = this._paths;
  2189. paths[path] = (paths[path] || 0) + 1;
  2190. obj = this.value();
  2191. tuple = normalizeTuple(obj, path);
  2192. // the path was a local path
  2193. if (tuple[0] && tuple[0] === obj) {
  2194. path = tuple[1];
  2195. key = firstKey(path);
  2196. path = path.slice(key.length+1);
  2197. // global path, but object does not exist yet.
  2198. // put into a queue and try to connect later.
  2199. } else if (!tuple[0]) {
  2200. pendingQueue.push([this, path]);
  2201. tuple.length = 0;
  2202. return;
  2203. // global path, and object already exists
  2204. } else {
  2205. src = tuple[0];
  2206. key = path.slice(0, 0-(tuple[1].length+1));
  2207. path = tuple[1];
  2208. }
  2209. tuple.length = 0;
  2210. this.chain(key, path, src);
  2211. };
  2212. // called on the root node of a chain to teardown watcher on the specified
  2213. // path
  2214. ChainNodePrototype.remove = function(path) {
  2215. var obj, tuple, key, src, paths;
  2216. paths = this._paths;
  2217. if (paths[path] > 0) { paths[path]--; }
  2218. obj = this.value();
  2219. tuple = normalizeTuple(obj, path);
  2220. if (tuple[0] === obj) {
  2221. path = tuple[1];
  2222. key = firstKey(path);
  2223. path = path.slice(key.length+1);
  2224. } else {
  2225. src = tuple[0];
  2226. key = path.slice(0, 0-(tuple[1].length+1));
  2227. path = tuple[1];
  2228. }
  2229. tuple.length = 0;
  2230. this.unchain(key, path);
  2231. };
  2232. ChainNodePrototype.count = 0;
  2233. ChainNodePrototype.chain = function(key, path, src) {
  2234. var chains = this._chains, node;
  2235. if (!chains) { chains = this._chains = {}; }
  2236. node = chains[key];
  2237. if (!node) { node = chains[key] = new ChainNode(this, key, src); }
  2238. node.count++; // count chains...
  2239. // chain rest of path if there is one
  2240. if (path && path.length>0) {
  2241. key = firstKey(path);
  2242. path = path.slice(key.length+1);
  2243. node.chain(key, path); // NOTE: no src means it will observe changes...
  2244. }
  2245. };
  2246. ChainNodePrototype.unchain = function(key, path) {
  2247. var chains = this._chains, node = chains[key];
  2248. // unchain rest of path first...
  2249. if (path && path.length>1) {
  2250. key = firstKey(path);
  2251. path = path.slice(key.length+1);
  2252. node.unchain(key, path);
  2253. }
  2254. // delete node if needed.
  2255. node.count--;
  2256. if (node.count<=0) {
  2257. delete chains[node._key];
  2258. node.destroy();
  2259. }
  2260. };
  2261. ChainNodePrototype.willChange = function() {
  2262. var chains = this._chains;
  2263. if (chains) {
  2264. for(var key in chains) {
  2265. if (!chains.hasOwnProperty(key)) { continue; }
  2266. chains[key].willChange();
  2267. }
  2268. }
  2269. if (this._parent) { this._parent.chainWillChange(this, this._key, 1); }
  2270. };
  2271. ChainNodePrototype.chainWillChange = function(chain, path, depth) {
  2272. if (this._key) { path = this._key + '.' + path; }
  2273. if (this._parent) {
  2274. this._parent.chainWillChange(this, path, depth+1);
  2275. } else {
  2276. if (depth > 1) { Ember.propertyWillChange(this.value(), path); }
  2277. path = 'this.' + path;
  2278. if (this._paths[path] > 0) { Ember.propertyWillChange(this.value(), path); }
  2279. }
  2280. };
  2281. ChainNodePrototype.chainDidChange = function(chain, path, depth) {
  2282. if (this._key) { path = this._key + '.' + path; }
  2283. if (this._parent) {
  2284. this._parent.chainDidChange(this, path, depth+1);
  2285. } else {
  2286. if (depth > 1) { Ember.propertyDidChange(this.value(), path); }
  2287. path = 'this.' + path;
  2288. if (this._paths[path] > 0) { Ember.propertyDidChange(this.value(), path); }
  2289. }
  2290. };
  2291. ChainNodePrototype.didChange = function(suppressEvent) {
  2292. // invalidate my own value first.
  2293. if (this._watching) {
  2294. var obj = this._parent.value();
  2295. if (obj !== this._object) {
  2296. removeChainWatcher(this._object, this._key, this);
  2297. this._object = obj;
  2298. addChainWatcher(obj, this._key, this);
  2299. }
  2300. this._value = undefined;
  2301. // Special-case: the EachProxy relies on immediate evaluation to
  2302. // establish its observers.
  2303. if (this._parent && this._parent._key === '@each')
  2304. this.value();
  2305. }
  2306. // then notify chains...
  2307. var chains = this._chains;
  2308. if (chains) {
  2309. for(var key in chains) {
  2310. if (!chains.hasOwnProperty(key)) { continue; }
  2311. chains[key].didChange(suppressEvent);
  2312. }
  2313. }
  2314. if (suppressEvent) { return; }
  2315. // and finally tell parent about my path changing...
  2316. if (this._parent) { this._parent.chainDidChange(this, this._key, 1); }
  2317. };
  2318. // get the chains for the current object. If the current object has
  2319. // chains inherited from the proto they will be cloned and reconfigured for
  2320. // the current object.
  2321. function chainsFor(obj) {
  2322. var m = metaFor(obj), ret = m.chains;
  2323. if (!ret) {
  2324. ret = m.chains = new ChainNode(null, null, obj);
  2325. } else if (ret.value() !== obj) {
  2326. ret = m.chains = ret.copy(obj);
  2327. }
  2328. return ret;
  2329. }
  2330. Ember.overrideChains = function(obj, keyName, m) {
  2331. chainsDidChange(obj, keyName, m, true);
  2332. };
  2333. function chainsWillChange(obj, keyName, m, arg) {
  2334. if (!m.hasOwnProperty('chainWatchers')) { return; } // nothing to do
  2335. var nodes = m.chainWatchers;
  2336. nodes = nodes[keyName];
  2337. if (!nodes) { return; }
  2338. for(var i = 0, l = nodes.length; i < l; i++) {
  2339. nodes[i].willChange(arg);
  2340. }
  2341. }
  2342. function chainsDidChange(obj, keyName, m, arg) {
  2343. if (!m.hasOwnProperty('chainWatchers')) { return; } // nothing to do
  2344. var nodes = m.chainWatchers;
  2345. nodes = nodes[keyName];
  2346. if (!nodes) { return; }
  2347. // looping in reverse because the chainWatchers array can be modified inside didChange
  2348. for (var i = nodes.length - 1; i >= 0; i--) {
  2349. nodes[i].didChange(arg);
  2350. }
  2351. }
  2352. // ..........................................................
  2353. // WATCH
  2354. //
  2355. /**
  2356. @private
  2357. Starts watching a property on an object. Whenever the property changes,
  2358. invokes `Ember.propertyWillChange` and `Ember.propertyDidChange`. This is the
  2359. primitive used by observers and dependent keys; usually you will never call
  2360. this method directly but instead use higher level methods like
  2361. `Ember.addObserver()`
  2362. @method watch
  2363. @for Ember
  2364. @param obj
  2365. @param {String} keyName
  2366. */
  2367. Ember.watch = function(obj, keyName) {
  2368. // can't watch length on Array - it is special...
  2369. if (keyName === 'length' && Ember.typeOf(obj) === 'array') { return this; }
  2370. var m = metaFor(obj), watching = m.watching, desc;
  2371. // activate watching first time
  2372. if (!watching[keyName]) {
  2373. watching[keyName] = 1;
  2374. if (isKeyName(keyName)) {
  2375. desc = m.descs[keyName];
  2376. if (desc && desc.willWatch) { desc.willWatch(obj, keyName); }
  2377. if ('function' === typeof obj.willWatchProperty) {
  2378. obj.willWatchProperty(keyName);
  2379. }
  2380. if (MANDATORY_SETTER && keyName in obj) {
  2381. m.values[keyName] = obj[keyName];
  2382. o_defineProperty(obj, keyName, {
  2383. configurable: true,
  2384. enumerable: true,
  2385. set: Ember.MANDATORY_SETTER_FUNCTION,
  2386. get: Ember.DEFAULT_GETTER_FUNCTION(keyName)
  2387. });
  2388. }
  2389. } else {
  2390. chainsFor(obj).add(keyName);
  2391. }
  2392. } else {
  2393. watching[keyName] = (watching[keyName] || 0) + 1;
  2394. }
  2395. return this;
  2396. };
  2397. Ember.isWatching = function isWatching(obj, key) {
  2398. var meta = obj[META_KEY];
  2399. return (meta && meta.watching[key]) > 0;
  2400. };
  2401. Ember.watch.flushPending = flushPendingChains;
  2402. Ember.unwatch = function(obj, keyName) {
  2403. // can't watch length on Array - it is special...
  2404. if (keyName === 'length' && Ember.typeOf(obj) === 'array') { return this; }
  2405. var m = metaFor(obj), watching = m.watching, desc;
  2406. if (watching[keyName] === 1) {
  2407. watching[keyName] = 0;
  2408. if (isKeyName(keyName)) {
  2409. desc = m.descs[keyName];
  2410. if (desc && desc.didUnwatch) { desc.didUnwatch(obj, keyName); }
  2411. if ('function' === typeof obj.didUnwatchProperty) {
  2412. obj.didUnwatchProperty(keyName);
  2413. }
  2414. if (MANDATORY_SETTER && keyName in obj) {
  2415. o_defineProperty(obj, keyName, {
  2416. configurable: true,
  2417. enumerable: true,
  2418. writable: true,
  2419. value: m.values[keyName]
  2420. });
  2421. delete m.values[keyName];
  2422. }
  2423. } else {
  2424. chainsFor(obj).remove(keyName);
  2425. }
  2426. } else if (watching[keyName]>1) {
  2427. watching[keyName]--;
  2428. }
  2429. return this;
  2430. };
  2431. /**
  2432. @private
  2433. Call on an object when you first beget it from another object. This will
  2434. setup any chained watchers on the object instance as needed. This method is
  2435. safe to call multiple times.
  2436. @method rewatch
  2437. @for Ember
  2438. @param obj
  2439. */
  2440. Ember.rewatch = function(obj) {
  2441. var m = metaFor(obj, false), chains = m.chains;
  2442. // make sure the object has its own guid.
  2443. if (GUID_KEY in obj && !obj.hasOwnProperty(GUID_KEY)) {
  2444. Ember.generateGuid(obj, 'ember');
  2445. }
  2446. // make sure any chained watchers update.
  2447. if (chains && chains.value() !== obj) {
  2448. m.chains = chains.copy(obj);
  2449. }
  2450. return this;
  2451. };
  2452. Ember.finishChains = function(obj) {
  2453. var m = metaFor(obj, false), chains = m.chains;
  2454. if (chains) {
  2455. if (chains.value() !== obj) {
  2456. m.chains = chains = chains.copy(obj);
  2457. }
  2458. chains.didChange(true);
  2459. }
  2460. };
  2461. // ..........................................................
  2462. // PROPERTY CHANGES
  2463. //
  2464. /**
  2465. This function is called just before an object property is about to change.
  2466. It will notify any before observers and prepare caches among other things.
  2467. Normally you will not need to call this method directly but if for some
  2468. reason you can't directly watch a property you can invoke this method
  2469. manually along with `Ember.propertyDidChange()` which you should call just
  2470. after the property value changes.
  2471. @method propertyWillChange
  2472. @for Ember
  2473. @param {Object} obj The object with the property that will change
  2474. @param {String} keyName The property key (or path) that will change.
  2475. @return {void}
  2476. */
  2477. function propertyWillChange(obj, keyName, value) {
  2478. var m = metaFor(obj, false),
  2479. watching = m.watching[keyName] > 0 || keyName === 'length',
  2480. proto = m.proto,
  2481. desc = m.descs[keyName];
  2482. if (!watching) { return; }
  2483. if (proto === obj) { return; }
  2484. if (desc && desc.willChange) { desc.willChange(obj, keyName); }
  2485. dependentKeysWillChange(obj, keyName, m);
  2486. chainsWillChange(obj, keyName, m);
  2487. Ember.notifyBeforeObservers(obj, keyName);
  2488. }
  2489. Ember.propertyWillChange = propertyWillChange;
  2490. /**
  2491. This function is called just after an object property has changed.
  2492. It will notify any observers and clear caches among other things.
  2493. Normally you will not need to call this method directly but if for some
  2494. reason you can't directly watch a property you can invoke this method
  2495. manually along with `Ember.propertyWilLChange()` which you should call just
  2496. before the property value changes.
  2497. @method propertyDidChange
  2498. @for Ember
  2499. @param {Object} obj The object with the property that will change
  2500. @param {String} keyName The property key (or path) that will change.
  2501. @return {void}
  2502. */
  2503. function propertyDidChange(obj, keyName) {
  2504. var m = metaFor(obj, false),
  2505. watching = m.watching[keyName] > 0 || keyName === 'length',
  2506. proto = m.proto,
  2507. desc = m.descs[keyName];
  2508. if (proto === obj) { return; }
  2509. // shouldn't this mean that we're watching this key?
  2510. if (desc && desc.didChange) { desc.didChange(obj, keyName); }
  2511. if (!watching && keyName !== 'length') { return; }
  2512. dependentKeysDidChange(obj, keyName, m);
  2513. chainsDidChange(obj, keyName, m);
  2514. Ember.notifyObservers(obj, keyName);
  2515. }
  2516. Ember.propertyDidChange = propertyDidChange;
  2517. var NODE_STACK = [];
  2518. /**
  2519. Tears down the meta on an object so that it can be garbage collected.
  2520. Multiple calls will have no effect.
  2521. @method destroy
  2522. @for Ember
  2523. @param {Object} obj the object to destroy
  2524. @return {void}
  2525. */
  2526. Ember.destroy = function (obj) {
  2527. var meta = obj[META_KEY], node, nodes, key, nodeObject;
  2528. if (meta) {
  2529. obj[META_KEY] = null;
  2530. // remove chainWatchers to remove circular references that would prevent GC
  2531. node = meta.chains;
  2532. if (node) {
  2533. NODE_STACK.push(node);
  2534. // process tree
  2535. while (NODE_STACK.length > 0) {
  2536. node = NODE_STACK.pop();
  2537. // push children
  2538. nodes = node._chains;
  2539. if (nodes) {
  2540. for (key in nodes) {
  2541. if (nodes.hasOwnProperty(key)) {
  2542. NODE_STACK.push(nodes[key]);
  2543. }
  2544. }
  2545. }
  2546. // remove chainWatcher in node object
  2547. if (node._watching) {
  2548. nodeObject = node._object;
  2549. if (nodeObject) {
  2550. removeChainWatcher(nodeObject, node._key, node);
  2551. }
  2552. }
  2553. }
  2554. }
  2555. }
  2556. };
  2557. })();
  2558. (function() {
  2559. /**
  2560. @module ember-metal
  2561. */
  2562. Ember.warn("The CP_DEFAULT_CACHEABLE flag has been removed and computed properties are always cached by default. Use `volatile` if you don't want caching.", Ember.ENV.CP_DEFAULT_CACHEABLE !== false);
  2563. var get = Ember.get,
  2564. set = Ember.set,
  2565. metaFor = Ember.meta,
  2566. guidFor = Ember.guidFor,
  2567. a_slice = [].slice,
  2568. o_create = Ember.create,
  2569. META_KEY = Ember.META_KEY,
  2570. watch = Ember.watch,
  2571. unwatch = Ember.unwatch;
  2572. // ..........................................................
  2573. // DEPENDENT KEYS
  2574. //
  2575. // data structure:
  2576. // meta.deps = {
  2577. // 'depKey': {
  2578. // 'keyName': count,
  2579. // }
  2580. // }
  2581. /*
  2582. This function returns a map of unique dependencies for a
  2583. given object and key.
  2584. */
  2585. function keysForDep(obj, depsMeta, depKey) {
  2586. var keys = depsMeta[depKey];
  2587. if (!keys) {
  2588. // if there are no dependencies yet for a the given key
  2589. // create a new empty list of dependencies for the key
  2590. keys = depsMeta[depKey] = {};
  2591. } else if (!depsMeta.hasOwnProperty(depKey)) {
  2592. // otherwise if the dependency list is inherited from
  2593. // a superclass, clone the hash
  2594. keys = depsMeta[depKey] = o_create(keys);
  2595. }
  2596. return keys;
  2597. }
  2598. /* return obj[META_KEY].deps */
  2599. function metaForDeps(obj, meta) {
  2600. var deps = meta.deps;
  2601. // If the current object has no dependencies...
  2602. if (!deps) {
  2603. // initialize the dependencies with a pointer back to
  2604. // the current object
  2605. deps = meta.deps = {};
  2606. } else if (!meta.hasOwnProperty('deps')) {
  2607. // otherwise if the dependencies are inherited from the
  2608. // object's superclass, clone the deps
  2609. deps = meta.deps = o_create(deps);
  2610. }
  2611. return deps;
  2612. }
  2613. function addDependentKeys(desc, obj, keyName, meta) {
  2614. // the descriptor has a list of dependent keys, so
  2615. // add all of its dependent keys.
  2616. var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys;
  2617. if (!depKeys) return;
  2618. depsMeta = metaForDeps(obj, meta);
  2619. for(idx = 0, len = depKeys.length; idx < len; idx++) {
  2620. depKey = depKeys[idx];
  2621. // Lookup keys meta for depKey
  2622. keys = keysForDep(obj, depsMeta, depKey);
  2623. // Increment the number of times depKey depends on keyName.
  2624. keys[keyName] = (keys[keyName] || 0) + 1;
  2625. // Watch the depKey
  2626. watch(obj, depKey);
  2627. }
  2628. }
  2629. function removeDependentKeys(desc, obj, keyName, meta) {
  2630. // the descriptor has a list of dependent keys, so
  2631. // add all of its dependent keys.
  2632. var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys;
  2633. if (!depKeys) return;
  2634. depsMeta = metaForDeps(obj, meta);
  2635. for(idx = 0, len = depKeys.length; idx < len; idx++) {
  2636. depKey = depKeys[idx];
  2637. // Lookup keys meta for depKey
  2638. keys = keysForDep(obj, depsMeta, depKey);
  2639. // Increment the number of times depKey depends on keyName.
  2640. keys[keyName] = (keys[keyName] || 0) - 1;
  2641. // Watch the depKey
  2642. unwatch(obj, depKey);
  2643. }
  2644. }
  2645. // ..........................................................
  2646. // COMPUTED PROPERTY
  2647. //
  2648. /**
  2649. @class ComputedProperty
  2650. @namespace Ember
  2651. @extends Ember.Descriptor
  2652. @constructor
  2653. */
  2654. function ComputedProperty(func, opts) {
  2655. this.func = func;
  2656. this._cacheable = (opts && opts.cacheable !== undefined) ? opts.cacheable : true;
  2657. this._dependentKeys = opts && opts.dependentKeys;
  2658. }
  2659. Ember.ComputedProperty = ComputedProperty;
  2660. ComputedProperty.prototype = new Ember.Descriptor();
  2661. var ComputedPropertyPrototype = ComputedProperty.prototype;
  2662. /**
  2663. Call on a computed property to set it into cacheable mode. When in this
  2664. mode the computed property will automatically cache the return value of
  2665. your function until one of the dependent keys changes.
  2666. ```javascript
  2667. MyApp.president = Ember.Object.create({
  2668. fullName: function() {
  2669. return this.get('firstName') + ' ' + this.get('lastName');
  2670. // After calculating the value of this function, Ember will
  2671. // return that value without re-executing this function until
  2672. // one of the dependent properties change.
  2673. }.property('firstName', 'lastName')
  2674. });
  2675. ```
  2676. Properties are cacheable by default.
  2677. @method cacheable
  2678. @param {Boolean} aFlag optional set to `false` to disable caching
  2679. @chainable
  2680. */
  2681. ComputedPropertyPrototype.cacheable = function(aFlag) {
  2682. this._cacheable = aFlag !== false;
  2683. return this;
  2684. };
  2685. /**
  2686. Call on a computed property to set it into non-cached mode. When in this
  2687. mode the computed property will not automatically cache the return value.
  2688. ```javascript
  2689. MyApp.outsideService = Ember.Object.create({
  2690. value: function() {
  2691. return OutsideService.getValue();
  2692. }.property().volatile()
  2693. });
  2694. ```
  2695. @method volatile
  2696. @chainable
  2697. */
  2698. ComputedPropertyPrototype.volatile = function() {
  2699. return this.cacheable(false);
  2700. };
  2701. /**
  2702. Sets the dependent keys on this computed property. Pass any number of
  2703. arguments containing key paths that this computed property depends on.
  2704. ```javascript
  2705. MyApp.president = Ember.Object.create({
  2706. fullName: Ember.computed(function() {
  2707. return this.get('firstName') + ' ' + this.get('lastName');
  2708. // Tell Ember that this computed property depends on firstName
  2709. // and lastName
  2710. }).property('firstName', 'lastName')
  2711. });
  2712. ```
  2713. @method property
  2714. @param {String} path* zero or more property paths
  2715. @chainable
  2716. */
  2717. ComputedPropertyPrototype.property = function() {
  2718. var args = [];
  2719. for (var i = 0, l = arguments.length; i < l; i++) {
  2720. args.push(arguments[i]);
  2721. }
  2722. this._dependentKeys = args;
  2723. return this;
  2724. };
  2725. /**
  2726. In some cases, you may want to annotate computed properties with additional
  2727. metadata about how they function or what values they operate on. For example,
  2728. computed property functions may close over variables that are then no longer
  2729. available for introspection.
  2730. You can pass a hash of these values to a computed property like this:
  2731. ```
  2732. person: function() {
  2733. var personId = this.get('personId');
  2734. return App.Person.create({ id: personId });
  2735. }.property().meta({ type: App.Person })
  2736. ```
  2737. The hash that you pass to the `meta()` function will be saved on the
  2738. computed property descriptor under the `_meta` key. Ember runtime
  2739. exposes a public API for retrieving these values from classes,
  2740. via the `metaForProperty()` function.
  2741. @method meta
  2742. @param {Hash} meta
  2743. @chainable
  2744. */
  2745. ComputedPropertyPrototype.meta = function(meta) {
  2746. if (arguments.length === 0) {
  2747. return this._meta || {};
  2748. } else {
  2749. this._meta = meta;
  2750. return this;
  2751. }
  2752. };
  2753. /* impl descriptor API */
  2754. ComputedPropertyPrototype.willWatch = function(obj, keyName) {
  2755. // watch already creates meta for this instance
  2756. var meta = obj[META_KEY];
  2757. Ember.assert('watch should have setup meta to be writable', meta.source === obj);
  2758. if (!(keyName in meta.cache)) {
  2759. addDependentKeys(this, obj, keyName, meta);
  2760. }
  2761. };
  2762. ComputedPropertyPrototype.didUnwatch = function(obj, keyName) {
  2763. var meta = obj[META_KEY];
  2764. Ember.assert('unwatch should have setup meta to be writable', meta.source === obj);
  2765. if (!(keyName in meta.cache)) {
  2766. // unwatch already creates meta for this instance
  2767. removeDependentKeys(this, obj, keyName, meta);
  2768. }
  2769. };
  2770. /* impl descriptor API */
  2771. ComputedPropertyPrototype.didChange = function(obj, keyName) {
  2772. // _suspended is set via a CP.set to ensure we don't clear
  2773. // the cached value set by the setter
  2774. if (this._cacheable && this._suspended !== obj) {
  2775. var meta = metaFor(obj);
  2776. if (keyName in meta.cache) {
  2777. delete meta.cache[keyName];
  2778. if (!meta.watching[keyName]) {
  2779. removeDependentKeys(this, obj, keyName, meta);
  2780. }
  2781. }
  2782. }
  2783. };
  2784. /* impl descriptor API */
  2785. ComputedPropertyPrototype.get = function(obj, keyName) {
  2786. var ret, cache, meta;
  2787. if (this._cacheable) {
  2788. meta = metaFor(obj);
  2789. cache = meta.cache;
  2790. if (keyName in cache) { return cache[keyName]; }
  2791. ret = cache[keyName] = this.func.call(obj, keyName);
  2792. if (!meta.watching[keyName]) {
  2793. addDependentKeys(this, obj, keyName, meta);
  2794. }
  2795. } else {
  2796. ret = this.func.call(obj, keyName);
  2797. }
  2798. return ret;
  2799. };
  2800. /* impl descriptor API */
  2801. ComputedPropertyPrototype.set = function(obj, keyName, value) {
  2802. var cacheable = this._cacheable,
  2803. func = this.func,
  2804. meta = metaFor(obj, cacheable),
  2805. watched = meta.watching[keyName],
  2806. oldSuspended = this._suspended,
  2807. hadCachedValue = false,
  2808. cache = meta.cache,
  2809. cachedValue, ret;
  2810. this._suspended = obj;
  2811. try {
  2812. if (cacheable && cache.hasOwnProperty(keyName)) {
  2813. cachedValue = cache[keyName];
  2814. hadCachedValue = true;
  2815. }
  2816. // Check if the CP has been wrapped
  2817. if (func.wrappedFunction) { func = func.wrappedFunction; }
  2818. // For backwards-compatibility with computed properties
  2819. // that check for arguments.length === 2 to determine if
  2820. // they are being get or set, only pass the old cached
  2821. // value if the computed property opts into a third
  2822. // argument.
  2823. if (func.length === 3) {
  2824. ret = func.call(obj, keyName, value, cachedValue);
  2825. } else if (func.length === 2) {
  2826. ret = func.call(obj, keyName, value);
  2827. } else {
  2828. Ember.defineProperty(obj, keyName, null, cachedValue);
  2829. Ember.set(obj, keyName, value);
  2830. return;
  2831. }
  2832. if (hadCachedValue && cachedValue === ret) { return; }
  2833. if (watched) { Ember.propertyWillChange(obj, keyName); }
  2834. if (hadCachedValue) {
  2835. delete cache[keyName];
  2836. }
  2837. if (cacheable) {
  2838. if (!watched && !hadCachedValue) {
  2839. addDependentKeys(this, obj, keyName, meta);
  2840. }
  2841. cache[keyName] = ret;
  2842. }
  2843. if (watched) { Ember.propertyDidChange(obj, keyName); }
  2844. } finally {
  2845. this._suspended = oldSuspended;
  2846. }
  2847. return ret;
  2848. };
  2849. /* called when property is defined */
  2850. ComputedPropertyPrototype.setup = function(obj, keyName) {
  2851. var meta = obj[META_KEY];
  2852. if (meta && meta.watching[keyName]) {
  2853. addDependentKeys(this, obj, keyName, metaFor(obj));
  2854. }
  2855. };
  2856. /* called before property is overridden */
  2857. ComputedPropertyPrototype.teardown = function(obj, keyName) {
  2858. var meta = metaFor(obj);
  2859. if (meta.watching[keyName] || keyName in meta.cache) {
  2860. removeDependentKeys(this, obj, keyName, meta);
  2861. }
  2862. if (this._cacheable) { delete meta.cache[keyName]; }
  2863. return null; // no value to restore
  2864. };
  2865. /**
  2866. This helper returns a new property descriptor that wraps the passed
  2867. computed property function. You can use this helper to define properties
  2868. with mixins or via `Ember.defineProperty()`.
  2869. The function you pass will be used to both get and set property values.
  2870. The function should accept two parameters, key and value. If value is not
  2871. undefined you should set the value first. In either case return the
  2872. current value of the property.
  2873. @method computed
  2874. @for Ember
  2875. @param {Function} func The computed property function.
  2876. @return {Ember.ComputedProperty} property descriptor instance
  2877. */
  2878. Ember.computed = function(func) {
  2879. var args;
  2880. if (arguments.length > 1) {
  2881. args = a_slice.call(arguments, 0, -1);
  2882. func = a_slice.call(arguments, -1)[0];
  2883. }
  2884. var cp = new ComputedProperty(func);
  2885. if (args) {
  2886. cp.property.apply(cp, args);
  2887. }
  2888. return cp;
  2889. };
  2890. /**
  2891. Returns the cached value for a property, if one exists.
  2892. This can be useful for peeking at the value of a computed
  2893. property that is generated lazily, without accidentally causing
  2894. it to be created.
  2895. @method cacheFor
  2896. @for Ember
  2897. @param {Object} obj the object whose property you want to check
  2898. @param {String} key the name of the property whose cached value you want
  2899. to return
  2900. */
  2901. Ember.cacheFor = function cacheFor(obj, key) {
  2902. var cache = metaFor(obj, false).cache;
  2903. if (cache && key in cache) {
  2904. return cache[key];
  2905. }
  2906. };
  2907. /**
  2908. @method computed.not
  2909. @for Ember
  2910. @param {String} dependentKey
  2911. */
  2912. Ember.computed.not = function(dependentKey) {
  2913. return Ember.computed(dependentKey, function(key) {
  2914. return !get(this, dependentKey);
  2915. });
  2916. };
  2917. /**
  2918. @method computed.empty
  2919. @for Ember
  2920. @param {String} dependentKey
  2921. */
  2922. Ember.computed.empty = function(dependentKey) {
  2923. return Ember.computed(dependentKey, function(key) {
  2924. var val = get(this, dependentKey);
  2925. return val === undefined || val === null || val === '' || (Ember.isArray(val) && get(val, 'length') === 0);
  2926. });
  2927. };
  2928. /**
  2929. @method computed.bool
  2930. @for Ember
  2931. @param {String} dependentKey
  2932. */
  2933. Ember.computed.bool = function(dependentKey) {
  2934. return Ember.computed(dependentKey, function(key) {
  2935. return !!get(this, dependentKey);
  2936. });
  2937. };
  2938. /**
  2939. @method computed.alias
  2940. @for Ember
  2941. @param {String} dependentKey
  2942. */
  2943. Ember.computed.alias = function(dependentKey) {
  2944. return Ember.computed(dependentKey, function(key, value){
  2945. if (arguments.length === 1) {
  2946. return get(this, dependentKey);
  2947. } else {
  2948. set(this, dependentKey, value);
  2949. return value;
  2950. }
  2951. });
  2952. };
  2953. })();
  2954. (function() {
  2955. /**
  2956. @module ember-metal
  2957. */
  2958. var o_create = Ember.create,
  2959. metaFor = Ember.meta,
  2960. metaPath = Ember.metaPath,
  2961. META_KEY = Ember.META_KEY;
  2962. /*
  2963. The event system uses a series of nested hashes to store listeners on an
  2964. object. When a listener is registered, or when an event arrives, these
  2965. hashes are consulted to determine which target and action pair to invoke.
  2966. The hashes are stored in the object's meta hash, and look like this:
  2967. // Object's meta hash
  2968. {
  2969. listeners: { // variable name: `listenerSet`
  2970. "foo:changed": [ // variable name: `actions`
  2971. [target, method, onceFlag, suspendedFlag]
  2972. ]
  2973. }
  2974. }
  2975. */
  2976. function indexOf(array, target, method) {
  2977. var index = -1;
  2978. for (var i = 0, l = array.length; i < l; i++) {
  2979. if (target === array[i][0] && method === array[i][1]) { index = i; break; }
  2980. }
  2981. return index;
  2982. }
  2983. function actionsFor(obj, eventName) {
  2984. var meta = metaFor(obj, true),
  2985. actions;
  2986. if (!meta.listeners) { meta.listeners = {}; }
  2987. if (!meta.hasOwnProperty('listeners')) {
  2988. // setup inherited copy of the listeners object
  2989. meta.listeners = o_create(meta.listeners);
  2990. }
  2991. actions = meta.listeners[eventName];
  2992. // if there are actions, but the eventName doesn't exist in our listeners, then copy them from the prototype
  2993. if (actions && !meta.listeners.hasOwnProperty(eventName)) {
  2994. actions = meta.listeners[eventName] = meta.listeners[eventName].slice();
  2995. } else if (!actions) {
  2996. actions = meta.listeners[eventName] = [];
  2997. }
  2998. return actions;
  2999. }
  3000. function actionsUnion(obj, eventName, otherActions) {
  3001. var meta = obj[META_KEY],
  3002. actions = meta && meta.listeners && meta.listeners[eventName];
  3003. if (!actions) { return; }
  3004. for (var i = actions.length - 1; i >= 0; i--) {
  3005. var target = actions[i][0],
  3006. method = actions[i][1],
  3007. once = actions[i][2],
  3008. suspended = actions[i][3],
  3009. actionIndex = indexOf(otherActions, target, method);
  3010. if (actionIndex === -1) {
  3011. otherActions.push([target, method, once, suspended]);
  3012. }
  3013. }
  3014. }
  3015. function actionsDiff(obj, eventName, otherActions) {
  3016. var meta = obj[META_KEY],
  3017. actions = meta && meta.listeners && meta.listeners[eventName],
  3018. diffActions = [];
  3019. if (!actions) { return; }
  3020. for (var i = actions.length - 1; i >= 0; i--) {
  3021. var target = actions[i][0],
  3022. method = actions[i][1],
  3023. once = actions[i][2],
  3024. suspended = actions[i][3],
  3025. actionIndex = indexOf(otherActions, target, method);
  3026. if (actionIndex !== -1) { continue; }
  3027. otherActions.push([target, method, once, suspended]);
  3028. diffActions.push([target, method, once, suspended]);
  3029. }
  3030. return diffActions;
  3031. }
  3032. /**
  3033. Add an event listener
  3034. @method addListener
  3035. @for Ember
  3036. @param obj
  3037. @param {String} eventName
  3038. @param {Object|Function} targetOrMethod A target object or a function
  3039. @param {Function|String} method A function or the name of a function to be called on `target`
  3040. */
  3041. function addListener(obj, eventName, target, method, once) {
  3042. Ember.assert("You must pass at least an object and event name to Ember.addListener", !!obj && !!eventName);
  3043. if (!method && 'function' === typeof target) {
  3044. method = target;
  3045. target = null;
  3046. }
  3047. var actions = actionsFor(obj, eventName),
  3048. actionIndex = indexOf(actions, target, method);
  3049. if (actionIndex !== -1) { return; }
  3050. actions.push([target, method, once, undefined]);
  3051. if ('function' === typeof obj.didAddListener) {
  3052. obj.didAddListener(eventName, target, method);
  3053. }
  3054. }
  3055. /**
  3056. Remove an event listener
  3057. Arguments should match those passed to {{#crossLink "Ember/addListener"}}{{/crossLink}}
  3058. @method removeListener
  3059. @for Ember
  3060. @param obj
  3061. @param {String} eventName
  3062. @param {Object|Function} targetOrMethod A target object or a function
  3063. @param {Function|String} method A function or the name of a function to be called on `target`
  3064. */
  3065. function removeListener(obj, eventName, target, method) {
  3066. Ember.assert("You must pass at least an object and event name to Ember.removeListener", !!obj && !!eventName);
  3067. if (!method && 'function' === typeof target) {
  3068. method = target;
  3069. target = null;
  3070. }
  3071. function _removeListener(target, method, once) {
  3072. var actions = actionsFor(obj, eventName),
  3073. actionIndex = indexOf(actions, target, method);
  3074. // action doesn't exist, give up silently
  3075. if (actionIndex === -1) { return; }
  3076. actions.splice(actionIndex, 1);
  3077. if ('function' === typeof obj.didRemoveListener) {
  3078. obj.didRemoveListener(eventName, target, method);
  3079. }
  3080. }
  3081. if (method) {
  3082. _removeListener(target, method);
  3083. } else {
  3084. var meta = obj[META_KEY],
  3085. actions = meta && meta.listeners && meta.listeners[eventName];
  3086. if (!actions) { return; }
  3087. for (var i = actions.length - 1; i >= 0; i--) {
  3088. _removeListener(actions[i][0], actions[i][1]);
  3089. }
  3090. }
  3091. }
  3092. /**
  3093. @private
  3094. Suspend listener during callback.
  3095. This should only be used by the target of the event listener
  3096. when it is taking an action that would cause the event, e.g.
  3097. an object might suspend its property change listener while it is
  3098. setting that property.
  3099. @method suspendListener
  3100. @for Ember
  3101. @param obj
  3102. @param {String} eventName
  3103. @param {Object|Function} targetOrMethod A target object or a function
  3104. @param {Function|String} method A function or the name of a function to be called on `target`
  3105. @param {Function} callback
  3106. */
  3107. function suspendListener(obj, eventName, target, method, callback) {
  3108. if (!method && 'function' === typeof target) {
  3109. method = target;
  3110. target = null;
  3111. }
  3112. var actions = actionsFor(obj, eventName),
  3113. actionIndex = indexOf(actions, target, method),
  3114. action;
  3115. if (actionIndex !== -1) {
  3116. action = actions[actionIndex].slice(); // copy it, otherwise we're modifying a shared object
  3117. action[3] = true; // mark the action as suspended
  3118. actions[actionIndex] = action; // replace the shared object with our copy
  3119. }
  3120. function tryable() { return callback.call(target); }
  3121. function finalizer() { if (action) { action[3] = undefined; } }
  3122. return Ember.tryFinally(tryable, finalizer);
  3123. }
  3124. /**
  3125. @private
  3126. Suspend listener during callback.
  3127. This should only be used by the target of the event listener
  3128. when it is taking an action that would cause the event, e.g.
  3129. an object might suspend its property change listener while it is
  3130. setting that property.
  3131. @method suspendListener
  3132. @for Ember
  3133. @param obj
  3134. @param {Array} eventName Array of event names
  3135. @param {Object|Function} targetOrMethod A target object or a function
  3136. @param {Function|String} method A function or the name of a function to be called on `target`
  3137. @param {Function} callback
  3138. */
  3139. function suspendListeners(obj, eventNames, target, method, callback) {
  3140. if (!method && 'function' === typeof target) {
  3141. method = target;
  3142. target = null;
  3143. }
  3144. var suspendedActions = [],
  3145. eventName, actions, action, i, l;
  3146. for (i=0, l=eventNames.length; i<l; i++) {
  3147. eventName = eventNames[i];
  3148. actions = actionsFor(obj, eventName);
  3149. var actionIndex = indexOf(actions, target, method);
  3150. if (actionIndex !== -1) {
  3151. action = actions[actionIndex].slice();
  3152. action[3] = true;
  3153. actions[actionIndex] = action;
  3154. suspendedActions.push(action);
  3155. }
  3156. }
  3157. function tryable() { return callback.call(target); }
  3158. function finalizer() {
  3159. for (i = 0, l = suspendedActions.length; i < l; i++) {
  3160. suspendedActions[i][3] = undefined;
  3161. }
  3162. }
  3163. return Ember.tryFinally(tryable, finalizer);
  3164. }
  3165. /**
  3166. @private
  3167. Return a list of currently watched events
  3168. @method watchedEvents
  3169. @for Ember
  3170. @param obj
  3171. */
  3172. function watchedEvents(obj) {
  3173. var listeners = obj[META_KEY].listeners, ret = [];
  3174. if (listeners) {
  3175. for(var eventName in listeners) {
  3176. if (listeners[eventName]) { ret.push(eventName); }
  3177. }
  3178. }
  3179. return ret;
  3180. }
  3181. /**
  3182. @method sendEvent
  3183. @for Ember
  3184. @param obj
  3185. @param {String} eventName
  3186. @param {Array} params
  3187. @return true
  3188. */
  3189. function sendEvent(obj, eventName, params, actions) {
  3190. // first give object a chance to handle it
  3191. if (obj !== Ember && 'function' === typeof obj.sendEvent) {
  3192. obj.sendEvent(eventName, params);
  3193. }
  3194. if (!actions) {
  3195. var meta = obj[META_KEY];
  3196. actions = meta && meta.listeners && meta.listeners[eventName];
  3197. }
  3198. if (!actions) { return; }
  3199. for (var i = actions.length - 1; i >= 0; i--) { // looping in reverse for once listeners
  3200. if (!actions[i] || actions[i][3] === true) { continue; }
  3201. var target = actions[i][0],
  3202. method = actions[i][1],
  3203. once = actions[i][2];
  3204. if (once) { removeListener(obj, eventName, target, method); }
  3205. if (!target) { target = obj; }
  3206. if ('string' === typeof method) { method = target[method]; }
  3207. if (params) {
  3208. method.apply(target, params);
  3209. } else {
  3210. method.apply(target);
  3211. }
  3212. }
  3213. return true;
  3214. }
  3215. /**
  3216. @private
  3217. @method hasListeners
  3218. @for Ember
  3219. @param obj
  3220. @param {String} eventName
  3221. */
  3222. function hasListeners(obj, eventName) {
  3223. var meta = obj[META_KEY],
  3224. actions = meta && meta.listeners && meta.listeners[eventName];
  3225. return !!(actions && actions.length);
  3226. }
  3227. /**
  3228. @private
  3229. @method listenersFor
  3230. @for Ember
  3231. @param obj
  3232. @param {String} eventName
  3233. */
  3234. function listenersFor(obj, eventName) {
  3235. var ret = [];
  3236. var meta = obj[META_KEY],
  3237. actions = meta && meta.listeners && meta.listeners[eventName];
  3238. if (!actions) { return ret; }
  3239. for (var i = 0, l = actions.length; i < l; i++) {
  3240. var target = actions[i][0],
  3241. method = actions[i][1];
  3242. ret.push([target, method]);
  3243. }
  3244. return ret;
  3245. }
  3246. Ember.addListener = addListener;
  3247. Ember.removeListener = removeListener;
  3248. Ember._suspendListener = suspendListener;
  3249. Ember._suspendListeners = suspendListeners;
  3250. Ember.sendEvent = sendEvent;
  3251. Ember.hasListeners = hasListeners;
  3252. Ember.watchedEvents = watchedEvents;
  3253. Ember.listenersFor = listenersFor;
  3254. Ember.listenersDiff = actionsDiff;
  3255. Ember.listenersUnion = actionsUnion;
  3256. })();
  3257. (function() {
  3258. // Ember.Logger
  3259. // Ember.watch.flushPending
  3260. // Ember.beginPropertyChanges, Ember.endPropertyChanges
  3261. // Ember.guidFor, Ember.tryFinally
  3262. /**
  3263. @module ember-metal
  3264. */
  3265. // ..........................................................
  3266. // HELPERS
  3267. //
  3268. var slice = [].slice,
  3269. forEach = Ember.ArrayPolyfills.forEach;
  3270. // invokes passed params - normalizing so you can pass target/func,
  3271. // target/string or just func
  3272. function invoke(target, method, args, ignore) {
  3273. if (method === undefined) {
  3274. method = target;
  3275. target = undefined;
  3276. }
  3277. if ('string' === typeof method) { method = target[method]; }
  3278. if (args && ignore > 0) {
  3279. args = args.length > ignore ? slice.call(args, ignore) : null;
  3280. }
  3281. return Ember.handleErrors(function() {
  3282. // IE8's Function.prototype.apply doesn't accept undefined/null arguments.
  3283. return method.apply(target || this, args || []);
  3284. }, this);
  3285. }
  3286. // ..........................................................
  3287. // RUNLOOP
  3288. //
  3289. var timerMark; // used by timers...
  3290. /**
  3291. Ember RunLoop (Private)
  3292. @class RunLoop
  3293. @namespace Ember
  3294. @private
  3295. @constructor
  3296. */
  3297. var RunLoop = function(prev) {
  3298. this._prev = prev || null;
  3299. this.onceTimers = {};
  3300. };
  3301. RunLoop.prototype = {
  3302. /**
  3303. @method end
  3304. */
  3305. end: function() {
  3306. this.flush();
  3307. },
  3308. /**
  3309. @method prev
  3310. */
  3311. prev: function() {
  3312. return this._prev;
  3313. },
  3314. // ..........................................................
  3315. // Delayed Actions
  3316. //
  3317. /**
  3318. @method schedule
  3319. @param {String} queueName
  3320. @param target
  3321. @param method
  3322. */
  3323. schedule: function(queueName, target, method) {
  3324. var queues = this._queues, queue;
  3325. if (!queues) { queues = this._queues = {}; }
  3326. queue = queues[queueName];
  3327. if (!queue) { queue = queues[queueName] = []; }
  3328. var args = arguments.length > 3 ? slice.call(arguments, 3) : null;
  3329. queue.push({ target: target, method: method, args: args });
  3330. return this;
  3331. },
  3332. /**
  3333. @method flush
  3334. @param {String} queueName
  3335. */
  3336. flush: function(queueName) {
  3337. var queueNames, idx, len, queue, log;
  3338. if (!this._queues) { return this; } // nothing to do
  3339. function iter(item) {
  3340. invoke(item.target, item.method, item.args);
  3341. }
  3342. function tryable() {
  3343. forEach.call(queue, iter);
  3344. }
  3345. Ember.watch.flushPending(); // make sure all chained watchers are setup
  3346. if (queueName) {
  3347. while (this._queues && (queue = this._queues[queueName])) {
  3348. this._queues[queueName] = null;
  3349. // the sync phase is to allow property changes to propagate. don't
  3350. // invoke observers until that is finished.
  3351. if (queueName === 'sync') {
  3352. log = Ember.LOG_BINDINGS;
  3353. if (log) { Ember.Logger.log('Begin: Flush Sync Queue'); }
  3354. Ember.beginPropertyChanges();
  3355. Ember.tryFinally(tryable, Ember.endPropertyChanges);
  3356. if (log) { Ember.Logger.log('End: Flush Sync Queue'); }
  3357. } else {
  3358. forEach.call(queue, iter);
  3359. }
  3360. }
  3361. } else {
  3362. queueNames = Ember.run.queues;
  3363. len = queueNames.length;
  3364. idx = 0;
  3365. outerloop:
  3366. while (idx < len) {
  3367. queueName = queueNames[idx];
  3368. queue = this._queues && this._queues[queueName];
  3369. delete this._queues[queueName];
  3370. if (queue) {
  3371. // the sync phase is to allow property changes to propagate. don't
  3372. // invoke observers until that is finished.
  3373. if (queueName === 'sync') {
  3374. log = Ember.LOG_BINDINGS;
  3375. if (log) { Ember.Logger.log('Begin: Flush Sync Queue'); }
  3376. Ember.beginPropertyChanges();
  3377. Ember.tryFinally(tryable, Ember.endPropertyChanges);
  3378. if (log) { Ember.Logger.log('End: Flush Sync Queue'); }
  3379. } else {
  3380. forEach.call(queue, iter);
  3381. }
  3382. }
  3383. // Loop through prior queues
  3384. for (var i = 0; i <= idx; i++) {
  3385. if (this._queues && this._queues[queueNames[i]]) {
  3386. // Start over at the first queue with contents
  3387. idx = i;
  3388. continue outerloop;
  3389. }
  3390. }
  3391. idx++;
  3392. }
  3393. }
  3394. timerMark = null;
  3395. return this;
  3396. }
  3397. };
  3398. Ember.RunLoop = RunLoop;
  3399. // ..........................................................
  3400. // Ember.run - this is ideally the only public API the dev sees
  3401. //
  3402. /**
  3403. Runs the passed target and method inside of a RunLoop, ensuring any
  3404. deferred actions including bindings and views updates are flushed at the
  3405. end.
  3406. Normally you should not need to invoke this method yourself. However if
  3407. you are implementing raw event handlers when interfacing with other
  3408. libraries or plugins, you should probably wrap all of your code inside this
  3409. call.
  3410. ```javascript
  3411. Ember.run(function(){
  3412. // code to be execute within a RunLoop
  3413. });
  3414. ```
  3415. @class run
  3416. @namespace Ember
  3417. @static
  3418. @constructor
  3419. @param {Object} [target] target of method to call
  3420. @param {Function|String} method Method to invoke.
  3421. May be a function or a string. If you pass a string
  3422. then it will be looked up on the passed target.
  3423. @param {Object} [args*] Any additional arguments you wish to pass to the method.
  3424. @return {Object} return value from invoking the passed function.
  3425. */
  3426. Ember.run = function(target, method) {
  3427. var loop,
  3428. args = arguments;
  3429. run.begin();
  3430. function tryable() {
  3431. if (target || method) {
  3432. return invoke(target, method, args, 2);
  3433. }
  3434. }
  3435. return Ember.tryFinally(tryable, run.end);
  3436. };
  3437. var run = Ember.run;
  3438. /**
  3439. Begins a new RunLoop. Any deferred actions invoked after the begin will
  3440. be buffered until you invoke a matching call to `Ember.run.end()`. This is
  3441. an lower-level way to use a RunLoop instead of using `Ember.run()`.
  3442. ```javascript
  3443. Ember.run.begin();
  3444. // code to be execute within a RunLoop
  3445. Ember.run.end();
  3446. ```
  3447. @method begin
  3448. @return {void}
  3449. */
  3450. Ember.run.begin = function() {
  3451. run.currentRunLoop = new RunLoop(run.currentRunLoop);
  3452. };
  3453. /**
  3454. Ends a RunLoop. This must be called sometime after you call
  3455. `Ember.run.begin()` to flush any deferred actions. This is a lower-level way
  3456. to use a RunLoop instead of using `Ember.run()`.
  3457. ```javascript
  3458. Ember.run.begin();
  3459. // code to be execute within a RunLoop
  3460. Ember.run.end();
  3461. ```
  3462. @method end
  3463. @return {void}
  3464. */
  3465. Ember.run.end = function() {
  3466. Ember.assert('must have a current run loop', run.currentRunLoop);
  3467. function tryable() { run.currentRunLoop.end(); }
  3468. function finalizer() { run.currentRunLoop = run.currentRunLoop.prev(); }
  3469. Ember.tryFinally(tryable, finalizer);
  3470. };
  3471. /**
  3472. Array of named queues. This array determines the order in which queues
  3473. are flushed at the end of the RunLoop. You can define your own queues by
  3474. simply adding the queue name to this array. Normally you should not need
  3475. to inspect or modify this property.
  3476. @property queues
  3477. @type Array
  3478. @default ['sync', 'actions', 'destroy', 'timers']
  3479. */
  3480. Ember.run.queues = ['sync', 'actions', 'destroy', 'timers'];
  3481. /**
  3482. Adds the passed target/method and any optional arguments to the named
  3483. queue to be executed at the end of the RunLoop. If you have not already
  3484. started a RunLoop when calling this method one will be started for you
  3485. automatically.
  3486. At the end of a RunLoop, any methods scheduled in this way will be invoked.
  3487. Methods will be invoked in an order matching the named queues defined in
  3488. the `run.queues` property.
  3489. ```javascript
  3490. Ember.run.schedule('timers', this, function(){
  3491. // this will be executed at the end of the RunLoop, when timers are run
  3492. console.log("scheduled on timers queue");
  3493. });
  3494. Ember.run.schedule('sync', this, function(){
  3495. // this will be executed at the end of the RunLoop, when bindings are synced
  3496. console.log("scheduled on sync queue");
  3497. });
  3498. // Note the functions will be run in order based on the run queues order. Output would be:
  3499. // scheduled on sync queue
  3500. // scheduled on timers queue
  3501. ```
  3502. @method schedule
  3503. @param {String} queue The name of the queue to schedule against.
  3504. Default queues are 'sync' and 'actions'
  3505. @param {Object} [target] target object to use as the context when invoking a method.
  3506. @param {String|Function} method The method to invoke. If you pass a string it
  3507. will be resolved on the target object at the time the scheduled item is
  3508. invoked allowing you to change the target function.
  3509. @param {Object} [arguments*] Optional arguments to be passed to the queued method.
  3510. @return {void}
  3511. */
  3512. Ember.run.schedule = function(queue, target, method) {
  3513. var loop = run.autorun();
  3514. loop.schedule.apply(loop, arguments);
  3515. };
  3516. var scheduledAutorun;
  3517. function autorun() {
  3518. scheduledAutorun = null;
  3519. if (run.currentRunLoop) { run.end(); }
  3520. }
  3521. // Used by global test teardown
  3522. Ember.run.hasScheduledTimers = function() {
  3523. return !!(scheduledAutorun || scheduledLater || scheduledNext);
  3524. };
  3525. // Used by global test teardown
  3526. Ember.run.cancelTimers = function () {
  3527. if (scheduledAutorun) {
  3528. clearTimeout(scheduledAutorun);
  3529. scheduledAutorun = null;
  3530. }
  3531. if (scheduledLater) {
  3532. clearTimeout(scheduledLater);
  3533. scheduledLater = null;
  3534. }
  3535. if (scheduledNext) {
  3536. clearTimeout(scheduledNext);
  3537. scheduledNext = null;
  3538. }
  3539. timers = {};
  3540. };
  3541. /**
  3542. Begins a new RunLoop if necessary and schedules a timer to flush the
  3543. RunLoop at a later time. This method is used by parts of Ember to
  3544. ensure the RunLoop always finishes. You normally do not need to call this
  3545. method directly. Instead use `Ember.run()`
  3546. @method autorun
  3547. @example
  3548. Ember.run.autorun();
  3549. @return {Ember.RunLoop} the new current RunLoop
  3550. */
  3551. Ember.run.autorun = function() {
  3552. if (!run.currentRunLoop) {
  3553. Ember.assert("You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in an Ember.run", !Ember.testing);
  3554. run.begin();
  3555. if (!scheduledAutorun) {
  3556. scheduledAutorun = setTimeout(autorun, 1);
  3557. }
  3558. }
  3559. return run.currentRunLoop;
  3560. };
  3561. /**
  3562. Immediately flushes any events scheduled in the 'sync' queue. Bindings
  3563. use this queue so this method is a useful way to immediately force all
  3564. bindings in the application to sync.
  3565. You should call this method anytime you need any changed state to propagate
  3566. throughout the app immediately without repainting the UI.
  3567. ```javascript
  3568. Ember.run.sync();
  3569. ```
  3570. @method sync
  3571. @return {void}
  3572. */
  3573. Ember.run.sync = function() {
  3574. run.autorun();
  3575. run.currentRunLoop.flush('sync');
  3576. };
  3577. // ..........................................................
  3578. // TIMERS
  3579. //
  3580. var timers = {}; // active timers...
  3581. var scheduledLater;
  3582. function invokeLaterTimers() {
  3583. scheduledLater = null;
  3584. var now = (+ new Date()), earliest = -1;
  3585. for (var key in timers) {
  3586. if (!timers.hasOwnProperty(key)) { continue; }
  3587. var timer = timers[key];
  3588. if (timer && timer.expires) {
  3589. if (now >= timer.expires) {
  3590. delete timers[key];
  3591. invoke(timer.target, timer.method, timer.args, 2);
  3592. } else {
  3593. if (earliest<0 || (timer.expires < earliest)) earliest=timer.expires;
  3594. }
  3595. }
  3596. }
  3597. // schedule next timeout to fire...
  3598. if (earliest > 0) { scheduledLater = setTimeout(invokeLaterTimers, earliest-(+ new Date())); }
  3599. }
  3600. /**
  3601. Invokes the passed target/method and optional arguments after a specified
  3602. period if time. The last parameter of this method must always be a number
  3603. of milliseconds.
  3604. You should use this method whenever you need to run some action after a
  3605. period of time instead of using `setTimeout()`. This method will ensure that
  3606. items that expire during the same script execution cycle all execute
  3607. together, which is often more efficient than using a real setTimeout.
  3608. ```javascript
  3609. Ember.run.later(myContext, function(){
  3610. // code here will execute within a RunLoop in about 500ms with this == myContext
  3611. }, 500);
  3612. ```
  3613. @method later
  3614. @param {Object} [target] target of method to invoke
  3615. @param {Function|String} method The method to invoke.
  3616. If you pass a string it will be resolved on the
  3617. target at the time the method is invoked.
  3618. @param {Object} [args*] Optional arguments to pass to the timeout.
  3619. @param {Number} wait
  3620. Number of milliseconds to wait.
  3621. @return {String} a string you can use to cancel the timer in
  3622. {{#crossLink "Ember/run.cancel"}}{{/crossLink}} later.
  3623. */
  3624. Ember.run.later = function(target, method) {
  3625. var args, expires, timer, guid, wait;
  3626. // setTimeout compatibility...
  3627. if (arguments.length===2 && 'function' === typeof target) {
  3628. wait = method;
  3629. method = target;
  3630. target = undefined;
  3631. args = [target, method];
  3632. } else {
  3633. args = slice.call(arguments);
  3634. wait = args.pop();
  3635. }
  3636. expires = (+ new Date()) + wait;
  3637. timer = { target: target, method: method, expires: expires, args: args };
  3638. guid = Ember.guidFor(timer);
  3639. timers[guid] = timer;
  3640. run.once(timers, invokeLaterTimers);
  3641. return guid;
  3642. };
  3643. function invokeOnceTimer(guid, onceTimers) {
  3644. if (onceTimers[this.tguid]) { delete onceTimers[this.tguid][this.mguid]; }
  3645. if (timers[guid]) { invoke(this.target, this.method, this.args); }
  3646. delete timers[guid];
  3647. }
  3648. function scheduleOnce(queue, target, method, args) {
  3649. var tguid = Ember.guidFor(target),
  3650. mguid = Ember.guidFor(method),
  3651. onceTimers = run.autorun().onceTimers,
  3652. guid = onceTimers[tguid] && onceTimers[tguid][mguid],
  3653. timer;
  3654. if (guid && timers[guid]) {
  3655. timers[guid].args = args; // replace args
  3656. } else {
  3657. timer = {
  3658. target: target,
  3659. method: method,
  3660. args: args,
  3661. tguid: tguid,
  3662. mguid: mguid
  3663. };
  3664. guid = Ember.guidFor(timer);
  3665. timers[guid] = timer;
  3666. if (!onceTimers[tguid]) { onceTimers[tguid] = {}; }
  3667. onceTimers[tguid][mguid] = guid; // so it isn't scheduled more than once
  3668. run.schedule(queue, timer, invokeOnceTimer, guid, onceTimers);
  3669. }
  3670. return guid;
  3671. }
  3672. /**
  3673. Schedules an item to run one time during the current RunLoop. Calling
  3674. this method with the same target/method combination will have no effect.
  3675. Note that although you can pass optional arguments these will not be
  3676. considered when looking for duplicates. New arguments will replace previous
  3677. calls.
  3678. ```javascript
  3679. Ember.run(function(){
  3680. var doFoo = function() { foo(); }
  3681. Ember.run.once(myContext, doFoo);
  3682. Ember.run.once(myContext, doFoo);
  3683. // doFoo will only be executed once at the end of the RunLoop
  3684. });
  3685. ```
  3686. @method once
  3687. @param {Object} [target] target of method to invoke
  3688. @param {Function|String} method The method to invoke.
  3689. If you pass a string it will be resolved on the
  3690. target at the time the method is invoked.
  3691. @param {Object} [args*] Optional arguments to pass to the timeout.
  3692. @return {Object} timer
  3693. */
  3694. Ember.run.once = function(target, method) {
  3695. return scheduleOnce('actions', target, method, slice.call(arguments, 2));
  3696. };
  3697. Ember.run.scheduleOnce = function(queue, target, method, args) {
  3698. return scheduleOnce(queue, target, method, slice.call(arguments, 3));
  3699. };
  3700. var scheduledNext;
  3701. function invokeNextTimers() {
  3702. scheduledNext = null;
  3703. for(var key in timers) {
  3704. if (!timers.hasOwnProperty(key)) { continue; }
  3705. var timer = timers[key];
  3706. if (timer.next) {
  3707. delete timers[key];
  3708. invoke(timer.target, timer.method, timer.args, 2);
  3709. }
  3710. }
  3711. }
  3712. /**
  3713. Schedules an item to run after control has been returned to the system.
  3714. This is often equivalent to calling `setTimeout(function() {}, 1)`.
  3715. ```javascript
  3716. Ember.run.next(myContext, function(){
  3717. // code to be executed in the next RunLoop, which will be scheduled after the current one
  3718. });
  3719. ```
  3720. @method next
  3721. @param {Object} [target] target of method to invoke
  3722. @param {Function|String} method The method to invoke.
  3723. If you pass a string it will be resolved on the
  3724. target at the time the method is invoked.
  3725. @param {Object} [args*] Optional arguments to pass to the timeout.
  3726. @return {Object} timer
  3727. */
  3728. Ember.run.next = function(target, method) {
  3729. var guid,
  3730. timer = {
  3731. target: target,
  3732. method: method,
  3733. args: slice.call(arguments),
  3734. next: true
  3735. };
  3736. guid = Ember.guidFor(timer);
  3737. timers[guid] = timer;
  3738. if (!scheduledNext) { scheduledNext = setTimeout(invokeNextTimers, 1); }
  3739. return guid;
  3740. };
  3741. /**
  3742. Cancels a scheduled item. Must be a value returned by `Ember.run.later()`,
  3743. `Ember.run.once()`, or `Ember.run.next()`.
  3744. ```javascript
  3745. var runNext = Ember.run.next(myContext, function(){
  3746. // will not be executed
  3747. });
  3748. Ember.run.cancel(runNext);
  3749. var runLater = Ember.run.later(myContext, function(){
  3750. // will not be executed
  3751. }, 500);
  3752. Ember.run.cancel(runLater);
  3753. var runOnce = Ember.run.once(myContext, function(){
  3754. // will not be executed
  3755. });
  3756. Ember.run.cancel(runOnce);
  3757. ```
  3758. @method cancel
  3759. @param {Object} timer Timer object to cancel
  3760. @return {void}
  3761. */
  3762. Ember.run.cancel = function(timer) {
  3763. delete timers[timer];
  3764. };
  3765. })();
  3766. (function() {
  3767. // Ember.Logger
  3768. // get, set, trySet
  3769. // guidFor, isArray, meta
  3770. // addObserver, removeObserver
  3771. // Ember.run.schedule
  3772. /**
  3773. @module ember-metal
  3774. */
  3775. // ..........................................................
  3776. // CONSTANTS
  3777. //
  3778. /**
  3779. Debug parameter you can turn on. This will log all bindings that fire to
  3780. the console. This should be disabled in production code. Note that you
  3781. can also enable this from the console or temporarily.
  3782. @property LOG_BINDINGS
  3783. @for Ember
  3784. @type Boolean
  3785. @default false
  3786. */
  3787. Ember.LOG_BINDINGS = false || !!Ember.ENV.LOG_BINDINGS;
  3788. var get = Ember.get,
  3789. set = Ember.set,
  3790. guidFor = Ember.guidFor,
  3791. isGlobalPath = Ember.isGlobalPath;
  3792. function getWithGlobals(obj, path) {
  3793. return get(isGlobalPath(path) ? Ember.lookup : obj, path);
  3794. }
  3795. // ..........................................................
  3796. // BINDING
  3797. //
  3798. var Binding = function(toPath, fromPath) {
  3799. this._direction = 'fwd';
  3800. this._from = fromPath;
  3801. this._to = toPath;
  3802. this._directionMap = Ember.Map.create();
  3803. };
  3804. /**
  3805. @class Binding
  3806. @namespace Ember
  3807. */
  3808. Binding.prototype = {
  3809. /**
  3810. This copies the Binding so it can be connected to another object.
  3811. @method copy
  3812. @return {Ember.Binding}
  3813. */
  3814. copy: function () {
  3815. var copy = new Binding(this._to, this._from);
  3816. if (this._oneWay) { copy._oneWay = true; }
  3817. return copy;
  3818. },
  3819. // ..........................................................
  3820. // CONFIG
  3821. //
  3822. /**
  3823. This will set `from` property path to the specified value. It will not
  3824. attempt to resolve this property path to an actual object until you
  3825. connect the binding.
  3826. The binding will search for the property path starting at the root object
  3827. you pass when you `connect()` the binding. It follows the same rules as
  3828. `get()` - see that method for more information.
  3829. @method from
  3830. @param {String} propertyPath the property path to connect to
  3831. @return {Ember.Binding} `this`
  3832. */
  3833. from: function(path) {
  3834. this._from = path;
  3835. return this;
  3836. },
  3837. /**
  3838. This will set the `to` property path to the specified value. It will not
  3839. attempt to resolve this property path to an actual object until you
  3840. connect the binding.
  3841. The binding will search for the property path starting at the root object
  3842. you pass when you `connect()` the binding. It follows the same rules as
  3843. `get()` - see that method for more information.
  3844. @method to
  3845. @param {String|Tuple} propertyPath A property path or tuple
  3846. @return {Ember.Binding} `this`
  3847. */
  3848. to: function(path) {
  3849. this._to = path;
  3850. return this;
  3851. },
  3852. /**
  3853. Configures the binding as one way. A one-way binding will relay changes
  3854. on the `from` side to the `to` side, but not the other way around. This
  3855. means that if you change the `to` side directly, the `from` side may have
  3856. a different value.
  3857. @method oneWay
  3858. @return {Ember.Binding} `this`
  3859. */
  3860. oneWay: function() {
  3861. this._oneWay = true;
  3862. return this;
  3863. },
  3864. toString: function() {
  3865. var oneWay = this._oneWay ? '[oneWay]' : '';
  3866. return "Ember.Binding<" + guidFor(this) + ">(" + this._from + " -> " + this._to + ")" + oneWay;
  3867. },
  3868. // ..........................................................
  3869. // CONNECT AND SYNC
  3870. //
  3871. /**
  3872. Attempts to connect this binding instance so that it can receive and relay
  3873. changes. This method will raise an exception if you have not set the
  3874. from/to properties yet.
  3875. @method connect
  3876. @param {Object} obj The root object for this binding.
  3877. @return {Ember.Binding} `this`
  3878. */
  3879. connect: function(obj) {
  3880. Ember.assert('Must pass a valid object to Ember.Binding.connect()', !!obj);
  3881. var fromPath = this._from, toPath = this._to;
  3882. Ember.trySet(obj, toPath, getWithGlobals(obj, fromPath));
  3883. // add an observer on the object to be notified when the binding should be updated
  3884. Ember.addObserver(obj, fromPath, this, this.fromDidChange);
  3885. // if the binding is a two-way binding, also set up an observer on the target
  3886. if (!this._oneWay) { Ember.addObserver(obj, toPath, this, this.toDidChange); }
  3887. this._readyToSync = true;
  3888. return this;
  3889. },
  3890. /**
  3891. Disconnects the binding instance. Changes will no longer be relayed. You
  3892. will not usually need to call this method.
  3893. @method disconnect
  3894. @param {Object} obj The root object you passed when connecting the binding.
  3895. @return {Ember.Binding} `this`
  3896. */
  3897. disconnect: function(obj) {
  3898. Ember.assert('Must pass a valid object to Ember.Binding.disconnect()', !!obj);
  3899. var twoWay = !this._oneWay;
  3900. // remove an observer on the object so we're no longer notified of
  3901. // changes that should update bindings.
  3902. Ember.removeObserver(obj, this._from, this, this.fromDidChange);
  3903. // if the binding is two-way, remove the observer from the target as well
  3904. if (twoWay) { Ember.removeObserver(obj, this._to, this, this.toDidChange); }
  3905. this._readyToSync = false; // disable scheduled syncs...
  3906. return this;
  3907. },
  3908. // ..........................................................
  3909. // PRIVATE
  3910. //
  3911. /* called when the from side changes */
  3912. fromDidChange: function(target) {
  3913. this._scheduleSync(target, 'fwd');
  3914. },
  3915. /* called when the to side changes */
  3916. toDidChange: function(target) {
  3917. this._scheduleSync(target, 'back');
  3918. },
  3919. _scheduleSync: function(obj, dir) {
  3920. var directionMap = this._directionMap;
  3921. var existingDir = directionMap.get(obj);
  3922. // if we haven't scheduled the binding yet, schedule it
  3923. if (!existingDir) {
  3924. Ember.run.schedule('sync', this, this._sync, obj);
  3925. directionMap.set(obj, dir);
  3926. }
  3927. // If both a 'back' and 'fwd' sync have been scheduled on the same object,
  3928. // default to a 'fwd' sync so that it remains deterministic.
  3929. if (existingDir === 'back' && dir === 'fwd') {
  3930. directionMap.set(obj, 'fwd');
  3931. }
  3932. },
  3933. _sync: function(obj) {
  3934. var log = Ember.LOG_BINDINGS;
  3935. // don't synchronize destroyed objects or disconnected bindings
  3936. if (obj.isDestroyed || !this._readyToSync) { return; }
  3937. // get the direction of the binding for the object we are
  3938. // synchronizing from
  3939. var directionMap = this._directionMap;
  3940. var direction = directionMap.get(obj);
  3941. var fromPath = this._from, toPath = this._to;
  3942. directionMap.remove(obj);
  3943. // if we're synchronizing from the remote object...
  3944. if (direction === 'fwd') {
  3945. var fromValue = getWithGlobals(obj, this._from);
  3946. if (log) {
  3947. Ember.Logger.log(' ', this.toString(), '->', fromValue, obj);
  3948. }
  3949. if (this._oneWay) {
  3950. Ember.trySet(obj, toPath, fromValue);
  3951. } else {
  3952. Ember._suspendObserver(obj, toPath, this, this.toDidChange, function () {
  3953. Ember.trySet(obj, toPath, fromValue);
  3954. });
  3955. }
  3956. // if we're synchronizing *to* the remote object
  3957. } else if (direction === 'back') {
  3958. var toValue = get(obj, this._to);
  3959. if (log) {
  3960. Ember.Logger.log(' ', this.toString(), '<-', toValue, obj);
  3961. }
  3962. Ember._suspendObserver(obj, fromPath, this, this.fromDidChange, function () {
  3963. Ember.trySet(Ember.isGlobalPath(fromPath) ? Ember.lookup : obj, fromPath, toValue);
  3964. });
  3965. }
  3966. }
  3967. };
  3968. function mixinProperties(to, from) {
  3969. for (var key in from) {
  3970. if (from.hasOwnProperty(key)) {
  3971. to[key] = from[key];
  3972. }
  3973. }
  3974. }
  3975. mixinProperties(Binding, {
  3976. /**
  3977. See {{#crossLink "Ember.Binding/from"}}{{/crossLink}}
  3978. @method from
  3979. @static
  3980. */
  3981. from: function() {
  3982. var C = this, binding = new C();
  3983. return binding.from.apply(binding, arguments);
  3984. },
  3985. /**
  3986. See {{#crossLink "Ember.Binding/to"}}{{/crossLink}}
  3987. @method to
  3988. @static
  3989. */
  3990. to: function() {
  3991. var C = this, binding = new C();
  3992. return binding.to.apply(binding, arguments);
  3993. },
  3994. /**
  3995. Creates a new Binding instance and makes it apply in a single direction.
  3996. A one-way binding will relay changes on the `from` side object (supplied
  3997. as the `from` argument) the `to` side, but not the other way around.
  3998. This means that if you change the "to" side directly, the "from" side may have
  3999. a different value.
  4000. See {{#crossLink "Binding/oneWay"}}{{/crossLink}}
  4001. @method oneWay
  4002. @param {String} from from path.
  4003. @param {Boolean} [flag] (Optional) passing nothing here will make the
  4004. binding `oneWay`. You can instead pass `false` to disable `oneWay`, making the
  4005. binding two way again.
  4006. */
  4007. oneWay: function(from, flag) {
  4008. var C = this, binding = new C(null, from);
  4009. return binding.oneWay(flag);
  4010. }
  4011. });
  4012. /**
  4013. An `Ember.Binding` connects the properties of two objects so that whenever
  4014. the value of one property changes, the other property will be changed also.
  4015. ## Automatic Creation of Bindings with `/^*Binding/`-named Properties
  4016. You do not usually create Binding objects directly but instead describe
  4017. bindings in your class or object definition using automatic binding
  4018. detection.
  4019. Properties ending in a `Binding` suffix will be converted to `Ember.Binding`
  4020. instances. The value of this property should be a string representing a path
  4021. to another object or a custom binding instanced created using Binding helpers
  4022. (see "Customizing Your Bindings"):
  4023. ```
  4024. valueBinding: "MyApp.someController.title"
  4025. ```
  4026. This will create a binding from `MyApp.someController.title` to the `value`
  4027. property of your object instance automatically. Now the two values will be
  4028. kept in sync.
  4029. ## One Way Bindings
  4030. One especially useful binding customization you can use is the `oneWay()`
  4031. helper. This helper tells Ember that you are only interested in
  4032. receiving changes on the object you are binding from. For example, if you
  4033. are binding to a preference and you want to be notified if the preference
  4034. has changed, but your object will not be changing the preference itself, you
  4035. could do:
  4036. ```
  4037. bigTitlesBinding: Ember.Binding.oneWay("MyApp.preferencesController.bigTitles")
  4038. ```
  4039. This way if the value of `MyApp.preferencesController.bigTitles` changes the
  4040. `bigTitles` property of your object will change also. However, if you
  4041. change the value of your `bigTitles` property, it will not update the
  4042. `preferencesController`.
  4043. One way bindings are almost twice as fast to setup and twice as fast to
  4044. execute because the binding only has to worry about changes to one side.
  4045. You should consider using one way bindings anytime you have an object that
  4046. may be created frequently and you do not intend to change a property; only
  4047. to monitor it for changes. (such as in the example above).
  4048. ## Adding Bindings Manually
  4049. All of the examples above show you how to configure a custom binding, but the
  4050. result of these customizations will be a binding template, not a fully active
  4051. Binding instance. The binding will actually become active only when you
  4052. instantiate the object the binding belongs to. It is useful however, to
  4053. understand what actually happens when the binding is activated.
  4054. For a binding to function it must have at least a `from` property and a `to`
  4055. property. The `from` property path points to the object/key that you want to
  4056. bind from while the `to` path points to the object/key you want to bind to.
  4057. When you define a custom binding, you are usually describing the property
  4058. you want to bind from (such as `MyApp.someController.value` in the examples
  4059. above). When your object is created, it will automatically assign the value
  4060. you want to bind `to` based on the name of your binding key. In the
  4061. examples above, during init, Ember objects will effectively call
  4062. something like this on your binding:
  4063. ```javascript
  4064. binding = Ember.Binding.from(this.valueBinding).to("value");
  4065. ```
  4066. This creates a new binding instance based on the template you provide, and
  4067. sets the to path to the `value` property of the new object. Now that the
  4068. binding is fully configured with a `from` and a `to`, it simply needs to be
  4069. connected to become active. This is done through the `connect()` method:
  4070. ```javascript
  4071. binding.connect(this);
  4072. ```
  4073. Note that when you connect a binding you pass the object you want it to be
  4074. connected to. This object will be used as the root for both the from and
  4075. to side of the binding when inspecting relative paths. This allows the
  4076. binding to be automatically inherited by subclassed objects as well.
  4077. Now that the binding is connected, it will observe both the from and to side
  4078. and relay changes.
  4079. If you ever needed to do so (you almost never will, but it is useful to
  4080. understand this anyway), you could manually create an active binding by
  4081. using the `Ember.bind()` helper method. (This is the same method used by
  4082. to setup your bindings on objects):
  4083. ```javascript
  4084. Ember.bind(MyApp.anotherObject, "value", "MyApp.someController.value");
  4085. ```
  4086. Both of these code fragments have the same effect as doing the most friendly
  4087. form of binding creation like so:
  4088. ```javascript
  4089. MyApp.anotherObject = Ember.Object.create({
  4090. valueBinding: "MyApp.someController.value",
  4091. // OTHER CODE FOR THIS OBJECT...
  4092. });
  4093. ```
  4094. Ember's built in binding creation method makes it easy to automatically
  4095. create bindings for you. You should always use the highest-level APIs
  4096. available, even if you understand how it works underneath.
  4097. @class Binding
  4098. @namespace Ember
  4099. @since Ember 0.9
  4100. */
  4101. Ember.Binding = Binding;
  4102. /**
  4103. Global helper method to create a new binding. Just pass the root object
  4104. along with a `to` and `from` path to create and connect the binding.
  4105. @method bind
  4106. @for Ember
  4107. @param {Object} obj The root object of the transform.
  4108. @param {String} to The path to the 'to' side of the binding.
  4109. Must be relative to obj.
  4110. @param {String} from The path to the 'from' side of the binding.
  4111. Must be relative to obj or a global path.
  4112. @return {Ember.Binding} binding instance
  4113. */
  4114. Ember.bind = function(obj, to, from) {
  4115. return new Ember.Binding(to, from).connect(obj);
  4116. };
  4117. /**
  4118. @method oneWay
  4119. @for Ember
  4120. @param {Object} obj The root object of the transform.
  4121. @param {String} to The path to the 'to' side of the binding.
  4122. Must be relative to obj.
  4123. @param {String} from The path to the 'from' side of the binding.
  4124. Must be relative to obj or a global path.
  4125. @return {Ember.Binding} binding instance
  4126. */
  4127. Ember.oneWay = function(obj, to, from) {
  4128. return new Ember.Binding(to, from).oneWay().connect(obj);
  4129. };
  4130. })();
  4131. (function() {
  4132. /**
  4133. @module ember-metal
  4134. */
  4135. var Mixin, REQUIRED, Alias,
  4136. a_map = Ember.ArrayPolyfills.map,
  4137. a_indexOf = Ember.ArrayPolyfills.indexOf,
  4138. a_forEach = Ember.ArrayPolyfills.forEach,
  4139. a_slice = [].slice,
  4140. EMPTY_META = {}, // dummy for non-writable meta
  4141. o_create = Ember.create,
  4142. defineProperty = Ember.defineProperty,
  4143. guidFor = Ember.guidFor;
  4144. function mixinsMeta(obj) {
  4145. var m = Ember.meta(obj, true), ret = m.mixins;
  4146. if (!ret) {
  4147. ret = m.mixins = {};
  4148. } else if (!m.hasOwnProperty('mixins')) {
  4149. ret = m.mixins = o_create(ret);
  4150. }
  4151. return ret;
  4152. }
  4153. function initMixin(mixin, args) {
  4154. if (args && args.length > 0) {
  4155. mixin.mixins = a_map.call(args, function(x) {
  4156. if (x instanceof Mixin) { return x; }
  4157. // Note: Manually setup a primitive mixin here. This is the only
  4158. // way to actually get a primitive mixin. This way normal creation
  4159. // of mixins will give you combined mixins...
  4160. var mixin = new Mixin();
  4161. mixin.properties = x;
  4162. return mixin;
  4163. });
  4164. }
  4165. return mixin;
  4166. }
  4167. function isMethod(obj) {
  4168. return 'function' === typeof obj &&
  4169. obj.isMethod !== false &&
  4170. obj !== Boolean && obj !== Object && obj !== Number && obj !== Array && obj !== Date && obj !== String;
  4171. }
  4172. var CONTINUE = {};
  4173. function mixinProperties(mixinsMeta, mixin) {
  4174. var guid;
  4175. if (mixin instanceof Mixin) {
  4176. guid = guidFor(mixin);
  4177. if (mixinsMeta[guid]) { return CONTINUE; }
  4178. mixinsMeta[guid] = mixin;
  4179. return mixin.properties;
  4180. } else {
  4181. return mixin; // apply anonymous mixin properties
  4182. }
  4183. }
  4184. function concatenatedProperties(props, values, base) {
  4185. var concats;
  4186. // reset before adding each new mixin to pickup concats from previous
  4187. concats = values.concatenatedProperties || base.concatenatedProperties;
  4188. if (props.concatenatedProperties) {
  4189. concats = concats ? concats.concat(props.concatenatedProperties) : props.concatenatedProperties;
  4190. }
  4191. return concats;
  4192. }
  4193. function giveDescriptorSuper(meta, key, property, values, descs) {
  4194. var superProperty;
  4195. // Computed properties override methods, and do not call super to them
  4196. if (values[key] === undefined) {
  4197. // Find the original descriptor in a parent mixin
  4198. superProperty = descs[key];
  4199. }
  4200. // If we didn't find the original descriptor in a parent mixin, find
  4201. // it on the original object.
  4202. superProperty = superProperty || meta.descs[key];
  4203. if (!superProperty || !(superProperty instanceof Ember.ComputedProperty)) {
  4204. return property;
  4205. }
  4206. // Since multiple mixins may inherit from the same parent, we need
  4207. // to clone the computed property so that other mixins do not receive
  4208. // the wrapped version.
  4209. property = o_create(property);
  4210. property.func = Ember.wrap(property.func, superProperty.func);
  4211. return property;
  4212. }
  4213. function giveMethodSuper(obj, key, method, values, descs) {
  4214. var superMethod;
  4215. // Methods overwrite computed properties, and do not call super to them.
  4216. if (descs[key] === undefined) {
  4217. // Find the original method in a parent mixin
  4218. superMethod = values[key];
  4219. }
  4220. // If we didn't find the original value in a parent mixin, find it in
  4221. // the original object
  4222. superMethod = superMethod || obj[key];
  4223. // Only wrap the new method if the original method was a function
  4224. if ('function' !== typeof superMethod) {
  4225. return method;
  4226. }
  4227. return Ember.wrap(method, superMethod);
  4228. }
  4229. function applyConcatenatedProperties(obj, key, value, values) {
  4230. var baseValue = values[key] || obj[key];
  4231. if (baseValue) {
  4232. if ('function' === typeof baseValue.concat) {
  4233. return baseValue.concat(value);
  4234. } else {
  4235. return Ember.makeArray(baseValue).concat(value);
  4236. }
  4237. } else {
  4238. return Ember.makeArray(value);
  4239. }
  4240. }
  4241. function addNormalizedProperty(base, key, value, meta, descs, values, concats) {
  4242. if (value instanceof Ember.Descriptor) {
  4243. if (value === REQUIRED && descs[key]) { return CONTINUE; }
  4244. // Wrap descriptor function to implement
  4245. // _super() if needed
  4246. if (value.func) {
  4247. value = giveDescriptorSuper(meta, key, value, values, descs);
  4248. }
  4249. descs[key] = value;
  4250. values[key] = undefined;
  4251. } else {
  4252. // impl super if needed...
  4253. if (isMethod(value)) {
  4254. value = giveMethodSuper(base, key, value, values, descs);
  4255. } else if ((concats && a_indexOf.call(concats, key) >= 0) || key === 'concatenatedProperties') {
  4256. value = applyConcatenatedProperties(base, key, value, values);
  4257. }
  4258. descs[key] = undefined;
  4259. values[key] = value;
  4260. }
  4261. }
  4262. function mergeMixins(mixins, m, descs, values, base) {
  4263. var mixin, props, key, concats, meta;
  4264. function removeKeys(keyName) {
  4265. delete descs[keyName];
  4266. delete values[keyName];
  4267. }
  4268. for(var i=0, l=mixins.length; i<l; i++) {
  4269. mixin = mixins[i];
  4270. Ember.assert('Expected hash or Mixin instance, got ' + Object.prototype.toString.call(mixin), typeof mixin === 'object' && mixin !== null && Object.prototype.toString.call(mixin) !== '[object Array]');
  4271. props = mixinProperties(m, mixin);
  4272. if (props === CONTINUE) { continue; }
  4273. if (props) {
  4274. meta = Ember.meta(base);
  4275. concats = concatenatedProperties(props, values, base);
  4276. for (key in props) {
  4277. if (!props.hasOwnProperty(key)) { continue; }
  4278. addNormalizedProperty(base, key, props[key], meta, descs, values, concats);
  4279. }
  4280. // manually copy toString() because some JS engines do not enumerate it
  4281. if (props.hasOwnProperty('toString')) { base.toString = props.toString; }
  4282. } else if (mixin.mixins) {
  4283. mergeMixins(mixin.mixins, m, descs, values, base);
  4284. if (mixin._without) { a_forEach.call(mixin._without, removeKeys); }
  4285. }
  4286. }
  4287. }
  4288. function writableReq(obj) {
  4289. var m = Ember.meta(obj), req = m.required;
  4290. if (!req || !m.hasOwnProperty('required')) {
  4291. req = m.required = req ? o_create(req) : {};
  4292. }
  4293. return req;
  4294. }
  4295. var IS_BINDING = Ember.IS_BINDING = /^.+Binding$/;
  4296. function detectBinding(obj, key, value, m) {
  4297. if (IS_BINDING.test(key)) {
  4298. var bindings = m.bindings;
  4299. if (!bindings) {
  4300. bindings = m.bindings = {};
  4301. } else if (!m.hasOwnProperty('bindings')) {
  4302. bindings = m.bindings = o_create(m.bindings);
  4303. }
  4304. bindings[key] = value;
  4305. }
  4306. }
  4307. function connectBindings(obj, m) {
  4308. // TODO Mixin.apply(instance) should disconnect binding if exists
  4309. var bindings = m.bindings, key, binding, to;
  4310. if (bindings) {
  4311. for (key in bindings) {
  4312. binding = bindings[key];
  4313. if (binding) {
  4314. to = key.slice(0, -7); // strip Binding off end
  4315. if (binding instanceof Ember.Binding) {
  4316. binding = binding.copy(); // copy prototypes' instance
  4317. binding.to(to);
  4318. } else { // binding is string path
  4319. binding = new Ember.Binding(to, binding);
  4320. }
  4321. binding.connect(obj);
  4322. obj[key] = binding;
  4323. }
  4324. }
  4325. // mark as applied
  4326. m.bindings = {};
  4327. }
  4328. }
  4329. function finishPartial(obj, m) {
  4330. connectBindings(obj, m || Ember.meta(obj));
  4331. return obj;
  4332. }
  4333. function followAlias(obj, desc, m, descs, values) {
  4334. var altKey = desc.methodName, value;
  4335. if (descs[altKey] || values[altKey]) {
  4336. value = values[altKey];
  4337. desc = descs[altKey];
  4338. } else if (m.descs[altKey]) {
  4339. desc = m.descs[altKey];
  4340. value = undefined;
  4341. } else {
  4342. desc = undefined;
  4343. value = obj[altKey];
  4344. }
  4345. return { desc: desc, value: value };
  4346. }
  4347. function updateObservers(obj, key, observer, observerKey, method) {
  4348. if ('function' !== typeof observer) { return; }
  4349. var paths = observer[observerKey];
  4350. if (paths) {
  4351. for (var i=0, l=paths.length; i<l; i++) {
  4352. Ember[method](obj, paths[i], null, key);
  4353. }
  4354. }
  4355. }
  4356. function replaceObservers(obj, key, observer) {
  4357. var prevObserver = obj[key];
  4358. updateObservers(obj, key, prevObserver, '__ember_observesBefore__', 'removeBeforeObserver');
  4359. updateObservers(obj, key, prevObserver, '__ember_observes__', 'removeObserver');
  4360. updateObservers(obj, key, observer, '__ember_observesBefore__', 'addBeforeObserver');
  4361. updateObservers(obj, key, observer, '__ember_observes__', 'addObserver');
  4362. }
  4363. function applyMixin(obj, mixins, partial) {
  4364. var descs = {}, values = {}, m = Ember.meta(obj),
  4365. key, value, desc;
  4366. // Go through all mixins and hashes passed in, and:
  4367. //
  4368. // * Handle concatenated properties
  4369. // * Set up _super wrapping if necessary
  4370. // * Set up computed property descriptors
  4371. // * Copying `toString` in broken browsers
  4372. mergeMixins(mixins, mixinsMeta(obj), descs, values, obj);
  4373. for(key in values) {
  4374. if (key === 'contructor' || !values.hasOwnProperty(key)) { continue; }
  4375. desc = descs[key];
  4376. value = values[key];
  4377. if (desc === REQUIRED) { continue; }
  4378. while (desc && desc instanceof Alias) {
  4379. var followed = followAlias(obj, desc, m, descs, values);
  4380. desc = followed.desc;
  4381. value = followed.value;
  4382. }
  4383. if (desc === undefined && value === undefined) { continue; }
  4384. replaceObservers(obj, key, value);
  4385. detectBinding(obj, key, value, m);
  4386. defineProperty(obj, key, desc, value, m);
  4387. }
  4388. if (!partial) { // don't apply to prototype
  4389. finishPartial(obj, m);
  4390. }
  4391. return obj;
  4392. }
  4393. /**
  4394. @method mixin
  4395. @for Ember
  4396. @param obj
  4397. @param mixins*
  4398. @return obj
  4399. */
  4400. Ember.mixin = function(obj) {
  4401. var args = a_slice.call(arguments, 1);
  4402. applyMixin(obj, args, false);
  4403. return obj;
  4404. };
  4405. /**
  4406. The `Ember.Mixin` class allows you to create mixins, whose properties can be
  4407. added to other classes. For instance,
  4408. ```javascript
  4409. App.Editable = Ember.Mixin.create({
  4410. edit: function() {
  4411. console.log('starting to edit');
  4412. this.set('isEditing', true);
  4413. },
  4414. isEditing: false
  4415. });
  4416. // Mix mixins into classes by passing them as the first arguments to
  4417. // .extend or .create.
  4418. App.CommentView = Ember.View.extend(App.Editable, {
  4419. template: Ember.Handlebars.compile('{{#if isEditing}}...{{else}}...{{/if}}')
  4420. });
  4421. commentView = App.CommentView.create();
  4422. commentView.edit(); // outputs 'starting to edit'
  4423. ```
  4424. Note that Mixins are created with `Ember.Mixin.create`, not
  4425. `Ember.Mixin.extend`.
  4426. @class Mixin
  4427. @namespace Ember
  4428. */
  4429. Ember.Mixin = function() { return initMixin(this, arguments); };
  4430. Mixin = Ember.Mixin;
  4431. Mixin._apply = applyMixin;
  4432. Mixin.applyPartial = function(obj) {
  4433. var args = a_slice.call(arguments, 1);
  4434. return applyMixin(obj, args, true);
  4435. };
  4436. Mixin.finishPartial = finishPartial;
  4437. Ember.anyUnprocessedMixins = false;
  4438. /**
  4439. @method create
  4440. @static
  4441. @param arguments*
  4442. */
  4443. Mixin.create = function() {
  4444. Ember.anyUnprocessedMixins = true;
  4445. var M = this;
  4446. return initMixin(new M(), arguments);
  4447. };
  4448. var MixinPrototype = Mixin.prototype;
  4449. /**
  4450. @method reopen
  4451. @param arguments*
  4452. */
  4453. MixinPrototype.reopen = function() {
  4454. var mixin, tmp;
  4455. if (this.properties) {
  4456. mixin = Mixin.create();
  4457. mixin.properties = this.properties;
  4458. delete this.properties;
  4459. this.mixins = [mixin];
  4460. } else if (!this.mixins) {
  4461. this.mixins = [];
  4462. }
  4463. var len = arguments.length, mixins = this.mixins, idx;
  4464. for(idx=0; idx < len; idx++) {
  4465. mixin = arguments[idx];
  4466. Ember.assert('Expected hash or Mixin instance, got ' + Object.prototype.toString.call(mixin), typeof mixin === 'object' && mixin !== null && Object.prototype.toString.call(mixin) !== '[object Array]');
  4467. if (mixin instanceof Mixin) {
  4468. mixins.push(mixin);
  4469. } else {
  4470. tmp = Mixin.create();
  4471. tmp.properties = mixin;
  4472. mixins.push(tmp);
  4473. }
  4474. }
  4475. return this;
  4476. };
  4477. /**
  4478. @method apply
  4479. @param obj
  4480. @return applied object
  4481. */
  4482. MixinPrototype.apply = function(obj) {
  4483. return applyMixin(obj, [this], false);
  4484. };
  4485. MixinPrototype.applyPartial = function(obj) {
  4486. return applyMixin(obj, [this], true);
  4487. };
  4488. function _detect(curMixin, targetMixin, seen) {
  4489. var guid = guidFor(curMixin);
  4490. if (seen[guid]) { return false; }
  4491. seen[guid] = true;
  4492. if (curMixin === targetMixin) { return true; }
  4493. var mixins = curMixin.mixins, loc = mixins ? mixins.length : 0;
  4494. while (--loc >= 0) {
  4495. if (_detect(mixins[loc], targetMixin, seen)) { return true; }
  4496. }
  4497. return false;
  4498. }
  4499. /**
  4500. @method detect
  4501. @param obj
  4502. @return {Boolean}
  4503. */
  4504. MixinPrototype.detect = function(obj) {
  4505. if (!obj) { return false; }
  4506. if (obj instanceof Mixin) { return _detect(obj, this, {}); }
  4507. var mixins = Ember.meta(obj, false).mixins;
  4508. if (mixins) {
  4509. return !!mixins[guidFor(this)];
  4510. }
  4511. return false;
  4512. };
  4513. MixinPrototype.without = function() {
  4514. var ret = new Mixin(this);
  4515. ret._without = a_slice.call(arguments);
  4516. return ret;
  4517. };
  4518. function _keys(ret, mixin, seen) {
  4519. if (seen[guidFor(mixin)]) { return; }
  4520. seen[guidFor(mixin)] = true;
  4521. if (mixin.properties) {
  4522. var props = mixin.properties;
  4523. for (var key in props) {
  4524. if (props.hasOwnProperty(key)) { ret[key] = true; }
  4525. }
  4526. } else if (mixin.mixins) {
  4527. a_forEach.call(mixin.mixins, function(x) { _keys(ret, x, seen); });
  4528. }
  4529. }
  4530. MixinPrototype.keys = function() {
  4531. var keys = {}, seen = {}, ret = [];
  4532. _keys(keys, this, seen);
  4533. for(var key in keys) {
  4534. if (keys.hasOwnProperty(key)) { ret.push(key); }
  4535. }
  4536. return ret;
  4537. };
  4538. // returns the mixins currently applied to the specified object
  4539. // TODO: Make Ember.mixin
  4540. Mixin.mixins = function(obj) {
  4541. var mixins = Ember.meta(obj, false).mixins, ret = [];
  4542. if (!mixins) { return ret; }
  4543. for (var key in mixins) {
  4544. var mixin = mixins[key];
  4545. // skip primitive mixins since these are always anonymous
  4546. if (!mixin.properties) { ret.push(mixin); }
  4547. }
  4548. return ret;
  4549. };
  4550. REQUIRED = new Ember.Descriptor();
  4551. REQUIRED.toString = function() { return '(Required Property)'; };
  4552. /**
  4553. Denotes a required property for a mixin
  4554. @method required
  4555. @for Ember
  4556. */
  4557. Ember.required = function() {
  4558. return REQUIRED;
  4559. };
  4560. Alias = function(methodName) {
  4561. this.methodName = methodName;
  4562. };
  4563. Alias.prototype = new Ember.Descriptor();
  4564. /**
  4565. Makes a property or method available via an additional name.
  4566. ```javascript
  4567. App.PaintSample = Ember.Object.extend({
  4568. color: 'red',
  4569. colour: Ember.alias('color'),
  4570. name: function(){
  4571. return "Zed";
  4572. },
  4573. moniker: Ember.alias("name")
  4574. });
  4575. var paintSample = App.PaintSample.create()
  4576. paintSample.get('colour'); // 'red'
  4577. paintSample.moniker(); // 'Zed'
  4578. ```
  4579. @method alias
  4580. @for Ember
  4581. @param {String} methodName name of the method or property to alias
  4582. @return {Ember.Descriptor}
  4583. @deprecated Use `Ember.aliasMethod` or `Ember.computed.alias` instead
  4584. */
  4585. Ember.alias = function(methodName) {
  4586. return new Alias(methodName);
  4587. };
  4588. Ember.deprecateFunc("Ember.alias is deprecated. Please use Ember.aliasMethod or Ember.computed.alias instead.", Ember.alias);
  4589. /**
  4590. Makes a method available via an additional name.
  4591. ```javascript
  4592. App.Person = Ember.Object.extend({
  4593. name: function(){
  4594. return 'Tomhuda Katzdale';
  4595. },
  4596. moniker: Ember.aliasMethod('name')
  4597. });
  4598. var goodGuy = App.Person.create()
  4599. ```
  4600. @method aliasMethod
  4601. @for Ember
  4602. @param {String} methodName name of the method to alias
  4603. @return {Ember.Descriptor}
  4604. */
  4605. Ember.aliasMethod = function(methodName) {
  4606. return new Alias(methodName);
  4607. };
  4608. // ..........................................................
  4609. // OBSERVER HELPER
  4610. //
  4611. /**
  4612. @method observer
  4613. @for Ember
  4614. @param {Function} func
  4615. @param {String} propertyNames*
  4616. @return func
  4617. */
  4618. Ember.observer = function(func) {
  4619. var paths = a_slice.call(arguments, 1);
  4620. func.__ember_observes__ = paths;
  4621. return func;
  4622. };
  4623. // If observers ever become asynchronous, Ember.immediateObserver
  4624. // must remain synchronous.
  4625. /**
  4626. @method immediateObserver
  4627. @for Ember
  4628. @param {Function} func
  4629. @param {String} propertyNames*
  4630. @return func
  4631. */
  4632. Ember.immediateObserver = function() {
  4633. for (var i=0, l=arguments.length; i<l; i++) {
  4634. var arg = arguments[i];
  4635. Ember.assert("Immediate observers must observe internal properties only, not properties on other objects.", typeof arg !== "string" || arg.indexOf('.') === -1);
  4636. }
  4637. return Ember.observer.apply(this, arguments);
  4638. };
  4639. /**
  4640. @method beforeObserver
  4641. @for Ember
  4642. @param {Function} func
  4643. @param {String} propertyNames*
  4644. @return func
  4645. */
  4646. Ember.beforeObserver = function(func) {
  4647. var paths = a_slice.call(arguments, 1);
  4648. func.__ember_observesBefore__ = paths;
  4649. return func;
  4650. };
  4651. })();
  4652. (function() {
  4653. /**
  4654. Ember Metal
  4655. @module ember
  4656. @submodule ember-metal
  4657. */
  4658. })();
  4659. (function() {
  4660. define("rsvp",
  4661. [],
  4662. function() {
  4663. "use strict";
  4664. var browserGlobal = (typeof window !== 'undefined') ? window : {};
  4665. var MutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
  4666. var RSVP, async;
  4667. if (typeof process !== 'undefined' &&
  4668. {}.toString.call(process) === '[object process]') {
  4669. async = function(callback, binding) {
  4670. process.nextTick(function() {
  4671. callback.call(binding);
  4672. });
  4673. };
  4674. } else if (MutationObserver) {
  4675. var queue = [];
  4676. var observer = new MutationObserver(function() {
  4677. var toProcess = queue.slice();
  4678. queue = [];
  4679. toProcess.forEach(function(tuple) {
  4680. var callback = tuple[0], binding = tuple[1];
  4681. callback.call(binding);
  4682. });
  4683. });
  4684. var element = document.createElement('div');
  4685. observer.observe(element, { attributes: true });
  4686. // Chrome Memory Leak: https://bugs.webkit.org/show_bug.cgi?id=93661
  4687. window.addEventListener('unload', function(){
  4688. observer.disconnect();
  4689. observer = null;
  4690. });
  4691. async = function(callback, binding) {
  4692. queue.push([callback, binding]);
  4693. element.setAttribute('drainQueue', 'drainQueue');
  4694. };
  4695. } else {
  4696. async = function(callback, binding) {
  4697. setTimeout(function() {
  4698. callback.call(binding);
  4699. }, 1);
  4700. };
  4701. }
  4702. var Event = function(type, options) {
  4703. this.type = type;
  4704. for (var option in options) {
  4705. if (!options.hasOwnProperty(option)) { continue; }
  4706. this[option] = options[option];
  4707. }
  4708. };
  4709. var indexOf = function(callbacks, callback) {
  4710. for (var i=0, l=callbacks.length; i<l; i++) {
  4711. if (callbacks[i][0] === callback) { return i; }
  4712. }
  4713. return -1;
  4714. };
  4715. var callbacksFor = function(object) {
  4716. var callbacks = object._promiseCallbacks;
  4717. if (!callbacks) {
  4718. callbacks = object._promiseCallbacks = {};
  4719. }
  4720. return callbacks;
  4721. };
  4722. var EventTarget = {
  4723. mixin: function(object) {
  4724. object.on = this.on;
  4725. object.off = this.off;
  4726. object.trigger = this.trigger;
  4727. return object;
  4728. },
  4729. on: function(eventNames, callback, binding) {
  4730. var allCallbacks = callbacksFor(this), callbacks, eventName;
  4731. eventNames = eventNames.split(/\s+/);
  4732. binding = binding || this;
  4733. while (eventName = eventNames.shift()) {
  4734. callbacks = allCallbacks[eventName];
  4735. if (!callbacks) {
  4736. callbacks = allCallbacks[eventName] = [];
  4737. }
  4738. if (indexOf(callbacks, callback) === -1) {
  4739. callbacks.push([callback, binding]);
  4740. }
  4741. }
  4742. },
  4743. off: function(eventNames, callback) {
  4744. var allCallbacks = callbacksFor(this), callbacks, eventName, index;
  4745. eventNames = eventNames.split(/\s+/);
  4746. while (eventName = eventNames.shift()) {
  4747. if (!callback) {
  4748. allCallbacks[eventName] = [];
  4749. continue;
  4750. }
  4751. callbacks = allCallbacks[eventName];
  4752. index = indexOf(callbacks, callback);
  4753. if (index !== -1) { callbacks.splice(index, 1); }
  4754. }
  4755. },
  4756. trigger: function(eventName, options) {
  4757. var allCallbacks = callbacksFor(this),
  4758. callbacks, callbackTuple, callback, binding, event;
  4759. if (callbacks = allCallbacks[eventName]) {
  4760. // Don't cache the callbacks.length since it may grow
  4761. for (var i=0; i<callbacks.length; i++) {
  4762. callbackTuple = callbacks[i];
  4763. callback = callbackTuple[0];
  4764. binding = callbackTuple[1];
  4765. if (typeof options !== 'object') {
  4766. options = { detail: options };
  4767. }
  4768. event = new Event(eventName, options);
  4769. callback.call(binding, event);
  4770. }
  4771. }
  4772. }
  4773. };
  4774. var Promise = function() {
  4775. this.on('promise:resolved', function(event) {
  4776. this.trigger('success', { detail: event.detail });
  4777. }, this);
  4778. this.on('promise:failed', function(event) {
  4779. this.trigger('error', { detail: event.detail });
  4780. }, this);
  4781. };
  4782. var noop = function() {};
  4783. var invokeCallback = function(type, promise, callback, event) {
  4784. var hasCallback = typeof callback === 'function',
  4785. value, error, succeeded, failed;
  4786. if (hasCallback) {
  4787. try {
  4788. value = callback(event.detail);
  4789. succeeded = true;
  4790. } catch(e) {
  4791. failed = true;
  4792. error = e;
  4793. }
  4794. } else {
  4795. value = event.detail;
  4796. succeeded = true;
  4797. }
  4798. if (value && typeof value.then === 'function') {
  4799. value.then(function(value) {
  4800. promise.resolve(value);
  4801. }, function(error) {
  4802. promise.reject(error);
  4803. });
  4804. } else if (hasCallback && succeeded) {
  4805. promise.resolve(value);
  4806. } else if (failed) {
  4807. promise.reject(error);
  4808. } else {
  4809. promise[type](value);
  4810. }
  4811. };
  4812. Promise.prototype = {
  4813. then: function(done, fail) {
  4814. var thenPromise = new Promise();
  4815. if (this.isResolved) {
  4816. RSVP.async(function() {
  4817. invokeCallback('resolve', thenPromise, done, { detail: this.resolvedValue });
  4818. }, this);
  4819. }
  4820. if (this.isRejected) {
  4821. RSVP.async(function() {
  4822. invokeCallback('reject', thenPromise, fail, { detail: this.rejectedValue });
  4823. }, this);
  4824. }
  4825. this.on('promise:resolved', function(event) {
  4826. invokeCallback('resolve', thenPromise, done, event);
  4827. });
  4828. this.on('promise:failed', function(event) {
  4829. invokeCallback('reject', thenPromise, fail, event);
  4830. });
  4831. return thenPromise;
  4832. },
  4833. resolve: function(value) {
  4834. resolve(this, value);
  4835. this.resolve = noop;
  4836. this.reject = noop;
  4837. },
  4838. reject: function(value) {
  4839. reject(this, value);
  4840. this.resolve = noop;
  4841. this.reject = noop;
  4842. }
  4843. };
  4844. function resolve(promise, value) {
  4845. RSVP.async(function() {
  4846. promise.trigger('promise:resolved', { detail: value });
  4847. promise.isResolved = true;
  4848. promise.resolvedValue = value;
  4849. });
  4850. }
  4851. function reject(promise, value) {
  4852. RSVP.async(function() {
  4853. promise.trigger('promise:failed', { detail: value });
  4854. promise.isRejected = true;
  4855. promise.rejectedValue = value;
  4856. });
  4857. }
  4858. function all(promises) {
  4859. var i, results = [];
  4860. var allPromise = new Promise();
  4861. var remaining = promises.length;
  4862. if (remaining === 0) {
  4863. allPromise.resolve([]);
  4864. }
  4865. var resolver = function(index) {
  4866. return function(value) {
  4867. resolve(index, value);
  4868. };
  4869. };
  4870. var resolve = function(index, value) {
  4871. results[index] = value;
  4872. if (--remaining === 0) {
  4873. allPromise.resolve(results);
  4874. }
  4875. };
  4876. var reject = function(error) {
  4877. allPromise.reject(error);
  4878. };
  4879. for (i = 0; i < remaining; i++) {
  4880. promises[i].then(resolver(i), reject);
  4881. }
  4882. return allPromise;
  4883. }
  4884. EventTarget.mixin(Promise.prototype);
  4885. RSVP = { async: async, Promise: Promise, Event: Event, EventTarget: EventTarget, all: all, raiseOnUncaughtExceptions: true };
  4886. return RSVP;
  4887. });
  4888. })();
  4889. (function() {
  4890. define("container",
  4891. [],
  4892. function() {
  4893. var objectCreate = Object.create || function(parent) {
  4894. function F() {}
  4895. F.prototype = parent;
  4896. return new F();
  4897. };
  4898. function InheritingDict(parent) {
  4899. this.parent = parent;
  4900. this.dict = {};
  4901. }
  4902. InheritingDict.prototype = {
  4903. get: function(key) {
  4904. var dict = this.dict;
  4905. if (dict.hasOwnProperty(key)) {
  4906. return dict[key];
  4907. }
  4908. if (this.parent) {
  4909. return this.parent.get(key);
  4910. }
  4911. },
  4912. set: function(key, value) {
  4913. this.dict[key] = value;
  4914. },
  4915. has: function(key) {
  4916. var dict = this.dict;
  4917. if (dict.hasOwnProperty(key)) {
  4918. return true;
  4919. }
  4920. if (this.parent) {
  4921. return this.parent.has(key);
  4922. }
  4923. return false;
  4924. },
  4925. eachLocal: function(callback, binding) {
  4926. var dict = this.dict;
  4927. for (var prop in dict) {
  4928. if (dict.hasOwnProperty(prop)) {
  4929. callback.call(binding, prop, dict[prop]);
  4930. }
  4931. }
  4932. }
  4933. };
  4934. function Container(parent) {
  4935. this.parent = parent;
  4936. this.children = [];
  4937. this.resolver = parent && parent.resolver || function() {};
  4938. this.registry = new InheritingDict(parent && parent.registry);
  4939. this.cache = new InheritingDict(parent && parent.cache);
  4940. this.typeInjections = new InheritingDict(parent && parent.typeInjections);
  4941. this.injections = {};
  4942. this._options = new InheritingDict(parent && parent._options);
  4943. this._typeOptions = new InheritingDict(parent && parent._typeOptions);
  4944. }
  4945. Container.prototype = {
  4946. child: function() {
  4947. var container = new Container(this);
  4948. this.children.push(container);
  4949. return container;
  4950. },
  4951. set: function(object, key, value) {
  4952. object[key] = value;
  4953. },
  4954. register: function(type, name, factory, options) {
  4955. var fullName;
  4956. if (type.indexOf(':') !== -1){
  4957. options = factory;
  4958. factory = name;
  4959. fullName = type;
  4960. } else {
  4961. Ember.deprecate('register("'+type +'", "'+ name+'") is now deprecated in-favour of register("'+type+':'+name+'");', true);
  4962. fullName = type + ":" + name;
  4963. }
  4964. this.registry.set(fullName, factory);
  4965. this._options.set(fullName, options || {});
  4966. },
  4967. resolve: function(fullName) {
  4968. return this.resolver(fullName) || this.registry.get(fullName);
  4969. },
  4970. lookup: function(fullName) {
  4971. if (this.cache.has(fullName)) {
  4972. return this.cache.get(fullName);
  4973. }
  4974. var value = instantiate(this, fullName);
  4975. if (!value) { return; }
  4976. if (isSingleton(this, fullName)) {
  4977. this.cache.set(fullName, value);
  4978. }
  4979. return value;
  4980. },
  4981. has: function(fullName) {
  4982. if (this.cache.has(fullName)) {
  4983. return true;
  4984. }
  4985. return !!factoryFor(this, fullName);
  4986. },
  4987. optionsForType: function(type, options) {
  4988. if (this.parent) { illegalChildOperation('optionsForType'); }
  4989. this._typeOptions.set(type, options);
  4990. },
  4991. options: function(type, options) {
  4992. this.optionsForType(type, options);
  4993. },
  4994. typeInjection: function(type, property, fullName) {
  4995. if (this.parent) { illegalChildOperation('typeInjection'); }
  4996. var injections = this.typeInjections.get(type);
  4997. if (!injections) {
  4998. injections = [];
  4999. this.typeInjections.set(type, injections);
  5000. }
  5001. injections.push({ property: property, fullName: fullName });
  5002. },
  5003. injection: function(factoryName, property, injectionName) {
  5004. if (this.parent) { illegalChildOperation('injection'); }
  5005. if (factoryName.indexOf(':') === -1) {
  5006. return this.typeInjection(factoryName, property, injectionName);
  5007. }
  5008. var injections = this.injections[factoryName] = this.injections[factoryName] || [];
  5009. injections.push({ property: property, fullName: injectionName });
  5010. },
  5011. destroy: function() {
  5012. this.isDestroyed = true;
  5013. for (var i=0, l=this.children.length; i<l; i++) {
  5014. this.children[i].destroy();
  5015. }
  5016. this.children = [];
  5017. eachDestroyable(this, function(item) {
  5018. item.isDestroying = true;
  5019. });
  5020. eachDestroyable(this, function(item) {
  5021. item.destroy();
  5022. });
  5023. delete this.parent;
  5024. this.isDestroyed = true;
  5025. },
  5026. reset: function() {
  5027. for (var i=0, l=this.children.length; i<l; i++) {
  5028. resetCache(this.children[i]);
  5029. }
  5030. resetCache(this);
  5031. }
  5032. };
  5033. function illegalChildOperation(operation) {
  5034. throw new Error(operation + " is not currently supported on child containers");
  5035. }
  5036. function isSingleton(container, fullName) {
  5037. var singleton = option(container, fullName, 'singleton');
  5038. return singleton !== false;
  5039. }
  5040. function buildInjections(container, injections) {
  5041. var hash = {};
  5042. if (!injections) { return hash; }
  5043. var injection, lookup;
  5044. for (var i=0, l=injections.length; i<l; i++) {
  5045. injection = injections[i];
  5046. lookup = container.lookup(injection.fullName);
  5047. hash[injection.property] = lookup;
  5048. }
  5049. return hash;
  5050. }
  5051. function option(container, fullName, optionName) {
  5052. var options = container._options.get(fullName);
  5053. if (options && options[optionName] !== undefined) {
  5054. return options[optionName];
  5055. }
  5056. var type = fullName.split(":")[0];
  5057. options = container._typeOptions.get(type);
  5058. if (options) {
  5059. return options[optionName];
  5060. }
  5061. }
  5062. function factoryFor(container, fullName) {
  5063. return container.resolve(fullName);
  5064. }
  5065. function instantiate(container, fullName) {
  5066. var factory = factoryFor(container, fullName);
  5067. var splitName = fullName.split(":"),
  5068. type = splitName[0], name = splitName[1],
  5069. value;
  5070. if (option(container, fullName, 'instantiate') === false) {
  5071. return factory;
  5072. }
  5073. if (factory) { console.log(factory)
  5074. var injections = [];
  5075. injections = injections.concat(container.typeInjections.get(type) || []);
  5076. injections = injections.concat(container.injections[fullName] || []);
  5077. var hash = buildInjections(container, injections);
  5078. hash.container = container;
  5079. hash._debugContainerKey = fullName;
  5080. value = factory.create(hash);
  5081. return value;
  5082. }
  5083. }
  5084. function eachDestroyable(container, callback) {
  5085. container.cache.eachLocal(function(key, value) {
  5086. if (option(container, key, 'instantiate') === false) { return; }
  5087. callback(value);
  5088. });
  5089. }
  5090. function resetCache(container) {
  5091. container.cache.eachLocal(function(key, value) {
  5092. if (option(container, key, 'instantiate') === false) { return; }
  5093. value.destroy();
  5094. });
  5095. container.cache.dict = {};
  5096. }
  5097. return Container;
  5098. });
  5099. })();
  5100. (function() {
  5101. /*globals ENV */
  5102. /**
  5103. @module ember
  5104. @submodule ember-runtime
  5105. */
  5106. var indexOf = Ember.EnumerableUtils.indexOf;
  5107. // ........................................
  5108. // TYPING & ARRAY MESSAGING
  5109. //
  5110. var TYPE_MAP = {};
  5111. var t = "Boolean Number String Function Array Date RegExp Object".split(" ");
  5112. Ember.ArrayPolyfills.forEach.call(t, function(name) {
  5113. TYPE_MAP[ "[object " + name + "]" ] = name.toLowerCase();
  5114. });
  5115. var toString = Object.prototype.toString;
  5116. /**
  5117. Returns a consistent type for the passed item.
  5118. Use this instead of the built-in `typeof` to get the type of an item.
  5119. It will return the same result across all browsers and includes a bit
  5120. more detail. Here is what will be returned:
  5121. | Return Value | Meaning |
  5122. |---------------|------------------------------------------------------|
  5123. | 'string' | String primitive |
  5124. | 'number' | Number primitive |
  5125. | 'boolean' | Boolean primitive |
  5126. | 'null' | Null value |
  5127. | 'undefined' | Undefined value |
  5128. | 'function' | A function |
  5129. | 'array' | An instance of Array |
  5130. | 'class' | A Ember class (created using Ember.Object.extend()) |
  5131. | 'instance' | A Ember object instance |
  5132. | 'error' | An instance of the Error object |
  5133. | 'object' | A JavaScript object not inheriting from Ember.Object |
  5134. Examples:
  5135. ```javascript
  5136. Ember.typeOf(); // 'undefined'
  5137. Ember.typeOf(null); // 'null'
  5138. Ember.typeOf(undefined); // 'undefined'
  5139. Ember.typeOf('michael'); // 'string'
  5140. Ember.typeOf(101); // 'number'
  5141. Ember.typeOf(true); // 'boolean'
  5142. Ember.typeOf(Ember.makeArray); // 'function'
  5143. Ember.typeOf([1,2,90]); // 'array'
  5144. Ember.typeOf(Ember.Object.extend()); // 'class'
  5145. Ember.typeOf(Ember.Object.create()); // 'instance'
  5146. Ember.typeOf(new Error('teamocil')); // 'error'
  5147. // "normal" JavaScript object
  5148. Ember.typeOf({a: 'b'}); // 'object'
  5149. ```
  5150. @method typeOf
  5151. @for Ember
  5152. @param item {Object} the item to check
  5153. @return {String} the type
  5154. */
  5155. Ember.typeOf = function(item) {
  5156. var ret;
  5157. ret = (item === null || item === undefined) ? String(item) : TYPE_MAP[toString.call(item)] || 'object';
  5158. if (ret === 'function') {
  5159. if (Ember.Object && Ember.Object.detect(item)) ret = 'class';
  5160. } else if (ret === 'object') {
  5161. if (item instanceof Error) ret = 'error';
  5162. else if (Ember.Object && item instanceof Ember.Object) ret = 'instance';
  5163. else ret = 'object';
  5164. }
  5165. return ret;
  5166. };
  5167. /**
  5168. Returns true if the passed value is null or undefined. This avoids errors
  5169. from JSLint complaining about use of ==, which can be technically
  5170. confusing.
  5171. ```javascript
  5172. Ember.isNone(); // true
  5173. Ember.isNone(null); // true
  5174. Ember.isNone(undefined); // true
  5175. Ember.isNone(''); // false
  5176. Ember.isNone([]); // false
  5177. Ember.isNone(function(){}); // false
  5178. ```
  5179. @method isNone
  5180. @for Ember
  5181. @param {Object} obj Value to test
  5182. @return {Boolean}
  5183. */
  5184. Ember.isNone = function(obj) {
  5185. return obj === null || obj === undefined;
  5186. };
  5187. Ember.none = Ember.deprecateFunc("Ember.none is deprecated. Please use Ember.isNone instead.", Ember.isNone);
  5188. /**
  5189. Verifies that a value is `null` or an empty string, empty array,
  5190. or empty function.
  5191. Constrains the rules on `Ember.isNone` by returning false for empty
  5192. string and empty arrays.
  5193. ```javascript
  5194. Ember.isEmpty(); // true
  5195. Ember.isEmpty(null); // true
  5196. Ember.isEmpty(undefined); // true
  5197. Ember.isEmpty(''); // true
  5198. Ember.isEmpty([]); // true
  5199. Ember.isEmpty('Adam Hawkins'); // false
  5200. Ember.isEmpty([0,1,2]); // false
  5201. ```
  5202. @method isEmpty
  5203. @for Ember
  5204. @param {Object} obj Value to test
  5205. @return {Boolean}
  5206. */
  5207. Ember.isEmpty = function(obj) {
  5208. return obj === null || obj === undefined || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && Ember.get(obj, 'length') === 0);
  5209. };
  5210. Ember.empty = Ember.deprecateFunc("Ember.empty is deprecated. Please use Ember.isEmpty instead.", Ember.isEmpty) ;
  5211. /**
  5212. This will compare two javascript values of possibly different types.
  5213. It will tell you which one is greater than the other by returning:
  5214. - -1 if the first is smaller than the second,
  5215. - 0 if both are equal,
  5216. - 1 if the first is greater than the second.
  5217. The order is calculated based on `Ember.ORDER_DEFINITION`, if types are different.
  5218. In case they have the same type an appropriate comparison for this type is made.
  5219. ```javascript
  5220. Ember.compare('hello', 'hello'); // 0
  5221. Ember.compare('abc', 'dfg'); // -1
  5222. Ember.compare(2, 1); // 1
  5223. ```
  5224. @method compare
  5225. @for Ember
  5226. @param {Object} v First value to compare
  5227. @param {Object} w Second value to compare
  5228. @return {Number} -1 if v < w, 0 if v = w and 1 if v > w.
  5229. */
  5230. Ember.compare = function compare(v, w) {
  5231. if (v === w) { return 0; }
  5232. var type1 = Ember.typeOf(v);
  5233. var type2 = Ember.typeOf(w);
  5234. var Comparable = Ember.Comparable;
  5235. if (Comparable) {
  5236. if (type1==='instance' && Comparable.detect(v.constructor)) {
  5237. return v.constructor.compare(v, w);
  5238. }
  5239. if (type2 === 'instance' && Comparable.detect(w.constructor)) {
  5240. return 1-w.constructor.compare(w, v);
  5241. }
  5242. }
  5243. // If we haven't yet generated a reverse-mapping of Ember.ORDER_DEFINITION,
  5244. // do so now.
  5245. var mapping = Ember.ORDER_DEFINITION_MAPPING;
  5246. if (!mapping) {
  5247. var order = Ember.ORDER_DEFINITION;
  5248. mapping = Ember.ORDER_DEFINITION_MAPPING = {};
  5249. var idx, len;
  5250. for (idx = 0, len = order.length; idx < len; ++idx) {
  5251. mapping[order[idx]] = idx;
  5252. }
  5253. // We no longer need Ember.ORDER_DEFINITION.
  5254. delete Ember.ORDER_DEFINITION;
  5255. }
  5256. var type1Index = mapping[type1];
  5257. var type2Index = mapping[type2];
  5258. if (type1Index < type2Index) { return -1; }
  5259. if (type1Index > type2Index) { return 1; }
  5260. // types are equal - so we have to check values now
  5261. switch (type1) {
  5262. case 'boolean':
  5263. case 'number':
  5264. if (v < w) { return -1; }
  5265. if (v > w) { return 1; }
  5266. return 0;
  5267. case 'string':
  5268. var comp = v.localeCompare(w);
  5269. if (comp < 0) { return -1; }
  5270. if (comp > 0) { return 1; }
  5271. return 0;
  5272. case 'array':
  5273. var vLen = v.length;
  5274. var wLen = w.length;
  5275. var l = Math.min(vLen, wLen);
  5276. var r = 0;
  5277. var i = 0;
  5278. while (r === 0 && i < l) {
  5279. r = compare(v[i],w[i]);
  5280. i++;
  5281. }
  5282. if (r !== 0) { return r; }
  5283. // all elements are equal now
  5284. // shorter array should be ordered first
  5285. if (vLen < wLen) { return -1; }
  5286. if (vLen > wLen) { return 1; }
  5287. // arrays are equal now
  5288. return 0;
  5289. case 'instance':
  5290. if (Ember.Comparable && Ember.Comparable.detect(v)) {
  5291. return v.compare(v, w);
  5292. }
  5293. return 0;
  5294. case 'date':
  5295. var vNum = v.getTime();
  5296. var wNum = w.getTime();
  5297. if (vNum < wNum) { return -1; }
  5298. if (vNum > wNum) { return 1; }
  5299. return 0;
  5300. default:
  5301. return 0;
  5302. }
  5303. };
  5304. function _copy(obj, deep, seen, copies) {
  5305. var ret, loc, key;
  5306. // primitive data types are immutable, just return them.
  5307. if ('object' !== typeof obj || obj===null) return obj;
  5308. // avoid cyclical loops
  5309. if (deep && (loc=indexOf(seen, obj))>=0) return copies[loc];
  5310. Ember.assert('Cannot clone an Ember.Object that does not implement Ember.Copyable', !(obj instanceof Ember.Object) || (Ember.Copyable && Ember.Copyable.detect(obj)));
  5311. // IMPORTANT: this specific test will detect a native array only. Any other
  5312. // object will need to implement Copyable.
  5313. if (Ember.typeOf(obj) === 'array') {
  5314. ret = obj.slice();
  5315. if (deep) {
  5316. loc = ret.length;
  5317. while(--loc>=0) ret[loc] = _copy(ret[loc], deep, seen, copies);
  5318. }
  5319. } else if (Ember.Copyable && Ember.Copyable.detect(obj)) {
  5320. ret = obj.copy(deep, seen, copies);
  5321. } else {
  5322. ret = {};
  5323. for(key in obj) {
  5324. if (!obj.hasOwnProperty(key)) continue;
  5325. // Prevents browsers that don't respect non-enumerability from
  5326. // copying internal Ember properties
  5327. if (key.substring(0,2) === '__') continue;
  5328. ret[key] = deep ? _copy(obj[key], deep, seen, copies) : obj[key];
  5329. }
  5330. }
  5331. if (deep) {
  5332. seen.push(obj);
  5333. copies.push(ret);
  5334. }
  5335. return ret;
  5336. }
  5337. /**
  5338. Creates a clone of the passed object. This function can take just about
  5339. any type of object and create a clone of it, including primitive values
  5340. (which are not actually cloned because they are immutable).
  5341. If the passed object implements the `clone()` method, then this function
  5342. will simply call that method and return the result.
  5343. @method copy
  5344. @for Ember
  5345. @param {Object} object The object to clone
  5346. @param {Boolean} deep If true, a deep copy of the object is made
  5347. @return {Object} The cloned object
  5348. */
  5349. Ember.copy = function(obj, deep) {
  5350. // fast paths
  5351. if ('object' !== typeof obj || obj===null) return obj; // can't copy primitives
  5352. if (Ember.Copyable && Ember.Copyable.detect(obj)) return obj.copy(deep);
  5353. return _copy(obj, deep, deep ? [] : null, deep ? [] : null);
  5354. };
  5355. /**
  5356. Convenience method to inspect an object. This method will attempt to
  5357. convert the object into a useful string description.
  5358. It is a pretty simple implementation. If you want something more robust,
  5359. use something like JSDump: https://github.com/NV/jsDump
  5360. @method inspect
  5361. @for Ember
  5362. @param {Object} obj The object you want to inspect.
  5363. @return {String} A description of the object
  5364. */
  5365. Ember.inspect = function(obj) {
  5366. if (typeof obj !== 'object' || obj === null) {
  5367. return obj + '';
  5368. }
  5369. var v, ret = [];
  5370. for(var key in obj) {
  5371. if (obj.hasOwnProperty(key)) {
  5372. v = obj[key];
  5373. if (v === 'toString') { continue; } // ignore useless items
  5374. if (Ember.typeOf(v) === 'function') { v = "function() { ... }"; }
  5375. ret.push(key + ": " + v);
  5376. }
  5377. }
  5378. return "{" + ret.join(", ") + "}";
  5379. };
  5380. /**
  5381. Compares two objects, returning true if they are logically equal. This is
  5382. a deeper comparison than a simple triple equal. For sets it will compare the
  5383. internal objects. For any other object that implements `isEqual()` it will
  5384. respect that method.
  5385. ```javascript
  5386. Ember.isEqual('hello', 'hello'); // true
  5387. Ember.isEqual(1, 2); // false
  5388. Ember.isEqual([4,2], [4,2]); // false
  5389. ```
  5390. @method isEqual
  5391. @for Ember
  5392. @param {Object} a first object to compare
  5393. @param {Object} b second object to compare
  5394. @return {Boolean}
  5395. */
  5396. Ember.isEqual = function(a, b) {
  5397. if (a && 'function'===typeof a.isEqual) return a.isEqual(b);
  5398. return a === b;
  5399. };
  5400. // Used by Ember.compare
  5401. Ember.ORDER_DEFINITION = Ember.ENV.ORDER_DEFINITION || [
  5402. 'undefined',
  5403. 'null',
  5404. 'boolean',
  5405. 'number',
  5406. 'string',
  5407. 'array',
  5408. 'object',
  5409. 'instance',
  5410. 'function',
  5411. 'class',
  5412. 'date'
  5413. ];
  5414. /**
  5415. Returns all of the keys defined on an object or hash. This is useful
  5416. when inspecting objects for debugging. On browsers that support it, this
  5417. uses the native `Object.keys` implementation.
  5418. @method keys
  5419. @for Ember
  5420. @param {Object} obj
  5421. @return {Array} Array containing keys of obj
  5422. */
  5423. Ember.keys = Object.keys;
  5424. if (!Ember.keys) {
  5425. Ember.keys = function(obj) {
  5426. var ret = [];
  5427. for(var key in obj) {
  5428. if (obj.hasOwnProperty(key)) { ret.push(key); }
  5429. }
  5430. return ret;
  5431. };
  5432. }
  5433. // ..........................................................
  5434. // ERROR
  5435. //
  5436. var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
  5437. /**
  5438. A subclass of the JavaScript Error object for use in Ember.
  5439. @class Error
  5440. @namespace Ember
  5441. @extends Error
  5442. @constructor
  5443. */
  5444. Ember.Error = function() {
  5445. var tmp = Error.prototype.constructor.apply(this, arguments);
  5446. // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
  5447. for (var idx = 0; idx < errorProps.length; idx++) {
  5448. this[errorProps[idx]] = tmp[errorProps[idx]];
  5449. }
  5450. };
  5451. Ember.Error.prototype = Ember.create(Error.prototype);
  5452. })();
  5453. (function() {
  5454. /**
  5455. @module ember
  5456. @submodule ember-runtime
  5457. */
  5458. var STRING_DASHERIZE_REGEXP = (/[ _]/g);
  5459. var STRING_DASHERIZE_CACHE = {};
  5460. var STRING_DECAMELIZE_REGEXP = (/([a-z])([A-Z])/g);
  5461. var STRING_CAMELIZE_REGEXP = (/(\-|_|\.|\s)+(.)?/g);
  5462. var STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g);
  5463. var STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g);
  5464. /**
  5465. Defines the hash of localized strings for the current language. Used by
  5466. the `Ember.String.loc()` helper. To localize, add string values to this
  5467. hash.
  5468. @property STRINGS
  5469. @for Ember
  5470. @type Hash
  5471. */
  5472. Ember.STRINGS = {};
  5473. /**
  5474. Defines string helper methods including string formatting and localization.
  5475. Unless `Ember.EXTEND_PROTOTYPES.String` is `false` these methods will also be
  5476. added to the `String.prototype` as well.
  5477. @class String
  5478. @namespace Ember
  5479. @static
  5480. */
  5481. Ember.String = {
  5482. /**
  5483. Apply formatting options to the string. This will look for occurrences
  5484. of "%@" in your string and substitute them with the arguments you pass into
  5485. this method. If you want to control the specific order of replacement,
  5486. you can add a number after the key as well to indicate which argument
  5487. you want to insert.
  5488. Ordered insertions are most useful when building loc strings where values
  5489. you need to insert may appear in different orders.
  5490. ```javascript
  5491. "Hello %@ %@".fmt('John', 'Doe'); // "Hello John Doe"
  5492. "Hello %@2, %@1".fmt('John', 'Doe'); // "Hello Doe, John"
  5493. ```
  5494. @method fmt
  5495. @param {Object...} [args]
  5496. @return {String} formatted string
  5497. */
  5498. fmt: function(str, formats) {
  5499. // first, replace any ORDERED replacements.
  5500. var idx = 0; // the current index for non-numerical replacements
  5501. return str.replace(/%@([0-9]+)?/g, function(s, argIndex) {
  5502. argIndex = (argIndex) ? parseInt(argIndex,0) - 1 : idx++ ;
  5503. s = formats[argIndex];
  5504. return ((s === null) ? '(null)' : (s === undefined) ? '' : s).toString();
  5505. }) ;
  5506. },
  5507. /**
  5508. Formats the passed string, but first looks up the string in the localized
  5509. strings hash. This is a convenient way to localize text. See
  5510. `Ember.String.fmt()` for more information on formatting.
  5511. Note that it is traditional but not required to prefix localized string
  5512. keys with an underscore or other character so you can easily identify
  5513. localized strings.
  5514. ```javascript
  5515. Ember.STRINGS = {
  5516. '_Hello World': 'Bonjour le monde',
  5517. '_Hello %@ %@': 'Bonjour %@ %@'
  5518. };
  5519. Ember.String.loc("_Hello World"); // 'Bonjour le monde';
  5520. Ember.String.loc("_Hello %@ %@", ["John", "Smith"]); // "Bonjour John Smith";
  5521. ```
  5522. @method loc
  5523. @param {String} str The string to format
  5524. @param {Array} formats Optional array of parameters to interpolate into string.
  5525. @return {String} formatted string
  5526. */
  5527. loc: function(str, formats) {
  5528. str = Ember.STRINGS[str] || str;
  5529. return Ember.String.fmt(str, formats) ;
  5530. },
  5531. /**
  5532. Splits a string into separate units separated by spaces, eliminating any
  5533. empty strings in the process. This is a convenience method for split that
  5534. is mostly useful when applied to the `String.prototype`.
  5535. ```javascript
  5536. Ember.String.w("alpha beta gamma").forEach(function(key) {
  5537. console.log(key);
  5538. });
  5539. // > alpha
  5540. // > beta
  5541. // > gamma
  5542. ```
  5543. @method w
  5544. @param {String} str The string to split
  5545. @return {String} split string
  5546. */
  5547. w: function(str) { return str.split(/\s+/); },
  5548. /**
  5549. Converts a camelized string into all lower case separated by underscores.
  5550. ```javascript
  5551. 'innerHTML'.decamelize(); // 'inner_html'
  5552. 'action_name'.decamelize(); // 'action_name'
  5553. 'css-class-name'.decamelize(); // 'css-class-name'
  5554. 'my favorite items'.decamelize(); // 'my favorite items'
  5555. ```
  5556. @method decamelize
  5557. @param {String} str The string to decamelize.
  5558. @return {String} the decamelized string.
  5559. */
  5560. decamelize: function(str) {
  5561. return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase();
  5562. },
  5563. /**
  5564. Replaces underscores or spaces with dashes.
  5565. ```javascript
  5566. 'innerHTML'.dasherize(); // 'inner-html'
  5567. 'action_name'.dasherize(); // 'action-name'
  5568. 'css-class-name'.dasherize(); // 'css-class-name'
  5569. 'my favorite items'.dasherize(); // 'my-favorite-items'
  5570. ```
  5571. @method dasherize
  5572. @param {String} str The string to dasherize.
  5573. @return {String} the dasherized string.
  5574. */
  5575. dasherize: function(str) {
  5576. var cache = STRING_DASHERIZE_CACHE,
  5577. ret = cache[str];
  5578. if (ret) {
  5579. return ret;
  5580. } else {
  5581. ret = Ember.String.decamelize(str).replace(STRING_DASHERIZE_REGEXP,'-');
  5582. cache[str] = ret;
  5583. }
  5584. return ret;
  5585. },
  5586. /**
  5587. Returns the lowerCaseCamel form of a string.
  5588. ```javascript
  5589. 'innerHTML'.camelize(); // 'innerHTML'
  5590. 'action_name'.camelize(); // 'actionName'
  5591. 'css-class-name'.camelize(); // 'cssClassName'
  5592. 'my favorite items'.camelize(); // 'myFavoriteItems'
  5593. ```
  5594. @method camelize
  5595. @param {String} str The string to camelize.
  5596. @return {String} the camelized string.
  5597. */
  5598. camelize: function(str) {
  5599. return str.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) {
  5600. return chr ? chr.toUpperCase() : '';
  5601. });
  5602. },
  5603. /**
  5604. Returns the UpperCamelCase form of a string.
  5605. ```javascript
  5606. 'innerHTML'.classify(); // 'InnerHTML'
  5607. 'action_name'.classify(); // 'ActionName'
  5608. 'css-class-name'.classify(); // 'CssClassName'
  5609. 'my favorite items'.classify(); // 'MyFavoriteItems'
  5610. ```
  5611. @method classify
  5612. @param {String} str the string to classify
  5613. @return {String} the classified string
  5614. */
  5615. classify: function(str) {
  5616. var parts = str.split("."),
  5617. out = [];
  5618. for (var i=0, l=parts.length; i<l; i++) {
  5619. var camelized = Ember.String.camelize(parts[i]);
  5620. out.push(camelized.charAt(0).toUpperCase() + camelized.substr(1));
  5621. }
  5622. return out.join(".");
  5623. },
  5624. /**
  5625. More general than decamelize. Returns the lower\_case\_and\_underscored
  5626. form of a string.
  5627. ```javascript
  5628. 'innerHTML'.underscore(); // 'inner_html'
  5629. 'action_name'.underscore(); // 'action_name'
  5630. 'css-class-name'.underscore(); // 'css_class_name'
  5631. 'my favorite items'.underscore(); // 'my_favorite_items'
  5632. ```
  5633. @method underscore
  5634. @param {String} str The string to underscore.
  5635. @return {String} the underscored string.
  5636. */
  5637. underscore: function(str) {
  5638. return str.replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2').
  5639. replace(STRING_UNDERSCORE_REGEXP_2, '_').toLowerCase();
  5640. },
  5641. /**
  5642. Returns the Capitalized form of a string
  5643. 'innerHTML'.capitalize() => 'InnerHTML'
  5644. 'action_name'.capitalize() => 'Action_name'
  5645. 'css-class-name'.capitalize() => 'Css-class-name'
  5646. 'my favorite items'.capitalize() => 'My favorite items'
  5647. @method capitalize
  5648. @param {String} str
  5649. @return {String}
  5650. */
  5651. capitalize: function(str) {
  5652. return str.charAt(0).toUpperCase() + str.substr(1);
  5653. }
  5654. };
  5655. })();
  5656. (function() {
  5657. /**
  5658. @module ember
  5659. @submodule ember-runtime
  5660. */
  5661. var fmt = Ember.String.fmt,
  5662. w = Ember.String.w,
  5663. loc = Ember.String.loc,
  5664. camelize = Ember.String.camelize,
  5665. decamelize = Ember.String.decamelize,
  5666. dasherize = Ember.String.dasherize,
  5667. underscore = Ember.String.underscore,
  5668. capitalize = Ember.String.capitalize,
  5669. classify = Ember.String.classify;
  5670. if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
  5671. /**
  5672. See {{#crossLink "Ember.String/fmt"}}{{/crossLink}}
  5673. @method fmt
  5674. @for String
  5675. */
  5676. String.prototype.fmt = function() {
  5677. return fmt(this, arguments);
  5678. };
  5679. /**
  5680. See {{#crossLink "Ember.String/w"}}{{/crossLink}}
  5681. @method w
  5682. @for String
  5683. */
  5684. String.prototype.w = function() {
  5685. return w(this);
  5686. };
  5687. /**
  5688. See {{#crossLink "Ember.String/loc"}}{{/crossLink}}
  5689. @method loc
  5690. @for String
  5691. */
  5692. String.prototype.loc = function() {
  5693. return loc(this, arguments);
  5694. };
  5695. /**
  5696. See {{#crossLink "Ember.String/camelize"}}{{/crossLink}}
  5697. @method camelize
  5698. @for String
  5699. */
  5700. String.prototype.camelize = function() {
  5701. return camelize(this);
  5702. };
  5703. /**
  5704. See {{#crossLink "Ember.String/decamelize"}}{{/crossLink}}
  5705. @method decamelize
  5706. @for String
  5707. */
  5708. String.prototype.decamelize = function() {
  5709. return decamelize(this);
  5710. };
  5711. /**
  5712. See {{#crossLink "Ember.String/dasherize"}}{{/crossLink}}
  5713. @method dasherize
  5714. @for String
  5715. */
  5716. String.prototype.dasherize = function() {
  5717. return dasherize(this);
  5718. };
  5719. /**
  5720. See {{#crossLink "Ember.String/underscore"}}{{/crossLink}}
  5721. @method underscore
  5722. @for String
  5723. */
  5724. String.prototype.underscore = function() {
  5725. return underscore(this);
  5726. };
  5727. /**
  5728. See {{#crossLink "Ember.String/classify"}}{{/crossLink}}
  5729. @method classify
  5730. @for String
  5731. */
  5732. String.prototype.classify = function() {
  5733. return classify(this);
  5734. };
  5735. /**
  5736. See {{#crossLink "Ember.String/capitalize"}}{{/crossLink}}
  5737. @method capitalize
  5738. @for String
  5739. */
  5740. String.prototype.capitalize = function() {
  5741. return capitalize(this);
  5742. };
  5743. }
  5744. })();
  5745. (function() {
  5746. /**
  5747. @module ember
  5748. @submodule ember-runtime
  5749. */
  5750. var a_slice = Array.prototype.slice;
  5751. if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
  5752. /**
  5753. The `property` extension of Javascript's Function prototype is available
  5754. when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is
  5755. `true`, which is the default.
  5756. Computed properties allow you to treat a function like a property:
  5757. ```javascript
  5758. MyApp.president = Ember.Object.create({
  5759. firstName: "Barack",
  5760. lastName: "Obama",
  5761. fullName: function() {
  5762. return this.get('firstName') + ' ' + this.get('lastName');
  5763. // Call this flag to mark the function as a property
  5764. }.property()
  5765. });
  5766. MyApp.president.get('fullName'); // "Barack Obama"
  5767. ```
  5768. Treating a function like a property is useful because they can work with
  5769. bindings, just like any other property.
  5770. Many computed properties have dependencies on other properties. For
  5771. example, in the above example, the `fullName` property depends on
  5772. `firstName` and `lastName` to determine its value. You can tell Ember
  5773. about these dependencies like this:
  5774. ```javascript
  5775. MyApp.president = Ember.Object.create({
  5776. firstName: "Barack",
  5777. lastName: "Obama",
  5778. fullName: function() {
  5779. return this.get('firstName') + ' ' + this.get('lastName');
  5780. // Tell Ember.js that this computed property depends on firstName
  5781. // and lastName
  5782. }.property('firstName', 'lastName')
  5783. });
  5784. ```
  5785. Make sure you list these dependencies so Ember knows when to update
  5786. bindings that connect to a computed property. Changing a dependency
  5787. will not immediately trigger an update of the computed property, but
  5788. will instead clear the cache so that it is updated when the next `get`
  5789. is called on the property.
  5790. See {{#crossLink "Ember.ComputedProperty"}}{{/crossLink}},
  5791. {{#crossLink "Ember/computed"}}{{/crossLink}}
  5792. @method property
  5793. @for Function
  5794. */
  5795. Function.prototype.property = function() {
  5796. var ret = Ember.computed(this);
  5797. return ret.property.apply(ret, arguments);
  5798. };
  5799. /**
  5800. The `observes` extension of Javascript's Function prototype is available
  5801. when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is
  5802. true, which is the default.
  5803. You can observe property changes simply by adding the `observes`
  5804. call to the end of your method declarations in classes that you write.
  5805. For example:
  5806. ```javascript
  5807. Ember.Object.create({
  5808. valueObserver: function() {
  5809. // Executes whenever the "value" property changes
  5810. }.observes('value')
  5811. });
  5812. ```
  5813. See {{#crossLink "Ember.Observable/observes"}}{{/crossLink}}
  5814. @method observes
  5815. @for Function
  5816. */
  5817. Function.prototype.observes = function() {
  5818. this.__ember_observes__ = a_slice.call(arguments);
  5819. return this;
  5820. };
  5821. /**
  5822. The `observesBefore` extension of Javascript's Function prototype is
  5823. available when `Ember.EXTEND_PROTOTYPES` or
  5824. `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default.
  5825. You can get notified when a property changes is about to happen by
  5826. by adding the `observesBefore` call to the end of your method
  5827. declarations in classes that you write. For example:
  5828. ```javascript
  5829. Ember.Object.create({
  5830. valueObserver: function() {
  5831. // Executes whenever the "value" property is about to change
  5832. }.observesBefore('value')
  5833. });
  5834. ```
  5835. See {{#crossLink "Ember.Observable/observesBefore"}}{{/crossLink}}
  5836. @method observesBefore
  5837. @for Function
  5838. */
  5839. Function.prototype.observesBefore = function() {
  5840. this.__ember_observesBefore__ = a_slice.call(arguments);
  5841. return this;
  5842. };
  5843. }
  5844. })();
  5845. (function() {
  5846. })();
  5847. (function() {
  5848. /**
  5849. @module ember
  5850. @submodule ember-runtime
  5851. */
  5852. // ..........................................................
  5853. // HELPERS
  5854. //
  5855. var get = Ember.get, set = Ember.set;
  5856. var a_slice = Array.prototype.slice;
  5857. var a_indexOf = Ember.EnumerableUtils.indexOf;
  5858. var contexts = [];
  5859. function popCtx() {
  5860. return contexts.length===0 ? {} : contexts.pop();
  5861. }
  5862. function pushCtx(ctx) {
  5863. contexts.push(ctx);
  5864. return null;
  5865. }
  5866. function iter(key, value) {
  5867. var valueProvided = arguments.length === 2;
  5868. function i(item) {
  5869. var cur = get(item, key);
  5870. return valueProvided ? value===cur : !!cur;
  5871. }
  5872. return i ;
  5873. }
  5874. /**
  5875. This mixin defines the common interface implemented by enumerable objects
  5876. in Ember. Most of these methods follow the standard Array iteration
  5877. API defined up to JavaScript 1.8 (excluding language-specific features that
  5878. cannot be emulated in older versions of JavaScript).
  5879. This mixin is applied automatically to the Array class on page load, so you
  5880. can use any of these methods on simple arrays. If Array already implements
  5881. one of these methods, the mixin will not override them.
  5882. ## Writing Your Own Enumerable
  5883. To make your own custom class enumerable, you need two items:
  5884. 1. You must have a length property. This property should change whenever
  5885. the number of items in your enumerable object changes. If you using this
  5886. with an `Ember.Object` subclass, you should be sure to change the length
  5887. property using `set().`
  5888. 2. If you must implement `nextObject().` See documentation.
  5889. Once you have these two methods implement, apply the `Ember.Enumerable` mixin
  5890. to your class and you will be able to enumerate the contents of your object
  5891. like any other collection.
  5892. ## Using Ember Enumeration with Other Libraries
  5893. Many other libraries provide some kind of iterator or enumeration like
  5894. facility. This is often where the most common API conflicts occur.
  5895. Ember's API is designed to be as friendly as possible with other
  5896. libraries by implementing only methods that mostly correspond to the
  5897. JavaScript 1.8 API.
  5898. @class Enumerable
  5899. @namespace Ember
  5900. @extends Ember.Mixin
  5901. @since Ember 0.9
  5902. */
  5903. Ember.Enumerable = Ember.Mixin.create(
  5904. /** @scope Ember.Enumerable.prototype */ {
  5905. // compatibility
  5906. isEnumerable: true,
  5907. /**
  5908. Implement this method to make your class enumerable.
  5909. This method will be call repeatedly during enumeration. The index value
  5910. will always begin with 0 and increment monotonically. You don't have to
  5911. rely on the index value to determine what object to return, but you should
  5912. always check the value and start from the beginning when you see the
  5913. requested index is 0.
  5914. The `previousObject` is the object that was returned from the last call
  5915. to `nextObject` for the current iteration. This is a useful way to
  5916. manage iteration if you are tracing a linked list, for example.
  5917. Finally the context parameter will always contain a hash you can use as
  5918. a "scratchpad" to maintain any other state you need in order to iterate
  5919. properly. The context object is reused and is not reset between
  5920. iterations so make sure you setup the context with a fresh state whenever
  5921. the index parameter is 0.
  5922. Generally iterators will continue to call `nextObject` until the index
  5923. reaches the your current length-1. If you run out of data before this
  5924. time for some reason, you should simply return undefined.
  5925. The default implementation of this method simply looks up the index.
  5926. This works great on any Array-like objects.
  5927. @method nextObject
  5928. @param {Number} index the current index of the iteration
  5929. @param {Object} previousObject the value returned by the last call to
  5930. `nextObject`.
  5931. @param {Object} context a context object you can use to maintain state.
  5932. @return {Object} the next object in the iteration or undefined
  5933. */
  5934. nextObject: Ember.required(Function),
  5935. /**
  5936. Helper method returns the first object from a collection. This is usually
  5937. used by bindings and other parts of the framework to extract a single
  5938. object if the enumerable contains only one item.
  5939. If you override this method, you should implement it so that it will
  5940. always return the same value each time it is called. If your enumerable
  5941. contains only one object, this method should always return that object.
  5942. If your enumerable is empty, this method should return `undefined`.
  5943. ```javascript
  5944. var arr = ["a", "b", "c"];
  5945. arr.firstObject(); // "a"
  5946. var arr = [];
  5947. arr.firstObject(); // undefined
  5948. ```
  5949. @property firstObject
  5950. @return {Object} the object or undefined
  5951. */
  5952. firstObject: Ember.computed(function() {
  5953. if (get(this, 'length')===0) return undefined ;
  5954. // handle generic enumerables
  5955. var context = popCtx(), ret;
  5956. ret = this.nextObject(0, null, context);
  5957. pushCtx(context);
  5958. return ret ;
  5959. }).property('[]'),
  5960. /**
  5961. Helper method returns the last object from a collection. If your enumerable
  5962. contains only one object, this method should always return that object.
  5963. If your enumerable is empty, this method should return `undefined`.
  5964. ```javascript
  5965. var arr = ["a", "b", "c"];
  5966. arr.lastObject(); // "c"
  5967. var arr = [];
  5968. arr.lastObject(); // undefined
  5969. ```
  5970. @property lastObject
  5971. @return {Object} the last object or undefined
  5972. */
  5973. lastObject: Ember.computed(function() {
  5974. var len = get(this, 'length');
  5975. if (len===0) return undefined ;
  5976. var context = popCtx(), idx=0, cur, last = null;
  5977. do {
  5978. last = cur;
  5979. cur = this.nextObject(idx++, last, context);
  5980. } while (cur !== undefined);
  5981. pushCtx(context);
  5982. return last;
  5983. }).property('[]'),
  5984. /**
  5985. Returns `true` if the passed object can be found in the receiver. The
  5986. default version will iterate through the enumerable until the object
  5987. is found. You may want to override this with a more efficient version.
  5988. ```javascript
  5989. var arr = ["a", "b", "c"];
  5990. arr.contains("a"); // true
  5991. arr.contains("z"); // false
  5992. ```
  5993. @method contains
  5994. @param {Object} obj The object to search for.
  5995. @return {Boolean} `true` if object is found in enumerable.
  5996. */
  5997. contains: function(obj) {
  5998. return this.find(function(item) { return item===obj; }) !== undefined;
  5999. },
  6000. /**
  6001. Iterates through the enumerable, calling the passed function on each
  6002. item. This method corresponds to the `forEach()` method defined in
  6003. JavaScript 1.6.
  6004. The callback method you provide should have the following signature (all
  6005. parameters are optional):
  6006. ```javascript
  6007. function(item, index, enumerable);
  6008. ```
  6009. - `item` is the current item in the iteration.
  6010. - `index` is the current index in the iteration.
  6011. - `enumerable` is the enumerable object itself.
  6012. Note that in addition to a callback, you can also pass an optional target
  6013. object that will be set as `this` on the context. This is a good way
  6014. to give your iterator function access to the current object.
  6015. @method forEach
  6016. @param {Function} callback The callback to execute
  6017. @param {Object} [target] The target object to use
  6018. @return {Object} receiver
  6019. */
  6020. forEach: function(callback, target) {
  6021. if (typeof callback !== "function") throw new TypeError() ;
  6022. var len = get(this, 'length'), last = null, context = popCtx();
  6023. if (target === undefined) target = null;
  6024. for(var idx=0;idx<len;idx++) {
  6025. var next = this.nextObject(idx, last, context) ;
  6026. callback.call(target, next, idx, this);
  6027. last = next ;
  6028. }
  6029. last = null ;
  6030. context = pushCtx(context);
  6031. return this ;
  6032. },
  6033. /**
  6034. Alias for `mapProperty`
  6035. @method getEach
  6036. @param {String} key name of the property
  6037. @return {Array} The mapped array.
  6038. */
  6039. getEach: function(key) {
  6040. return this.mapProperty(key);
  6041. },
  6042. /**
  6043. Sets the value on the named property for each member. This is more
  6044. efficient than using other methods defined on this helper. If the object
  6045. implements Ember.Observable, the value will be changed to `set(),` otherwise
  6046. it will be set directly. `null` objects are skipped.
  6047. @method setEach
  6048. @param {String} key The key to set
  6049. @param {Object} value The object to set
  6050. @return {Object} receiver
  6051. */
  6052. setEach: function(key, value) {
  6053. return this.forEach(function(item) {
  6054. set(item, key, value);
  6055. });
  6056. },
  6057. /**
  6058. Maps all of the items in the enumeration to another value, returning
  6059. a new array. This method corresponds to `map()` defined in JavaScript 1.6.
  6060. The callback method you provide should have the following signature (all
  6061. parameters are optional):
  6062. ```javascript
  6063. function(item, index, enumerable);
  6064. ```
  6065. - `item` is the current item in the iteration.
  6066. - `index` is the current index in the iteration.
  6067. - `enumerable` is the enumerable object itself.
  6068. It should return the mapped value.
  6069. Note that in addition to a callback, you can also pass an optional target
  6070. object that will be set as `this` on the context. This is a good way
  6071. to give your iterator function access to the current object.
  6072. @method map
  6073. @param {Function} callback The callback to execute
  6074. @param {Object} [target] The target object to use
  6075. @return {Array} The mapped array.
  6076. */
  6077. map: function(callback, target) {
  6078. var ret = [];
  6079. this.forEach(function(x, idx, i) {
  6080. ret[idx] = callback.call(target, x, idx,i);
  6081. });
  6082. return ret ;
  6083. },
  6084. /**
  6085. Similar to map, this specialized function returns the value of the named
  6086. property on all items in the enumeration.
  6087. @method mapProperty
  6088. @param {String} key name of the property
  6089. @return {Array} The mapped array.
  6090. */
  6091. mapProperty: function(key) {
  6092. return this.map(function(next) {
  6093. return get(next, key);
  6094. });
  6095. },
  6096. /**
  6097. Returns an array with all of the items in the enumeration that the passed
  6098. function returns true for. This method corresponds to `filter()` defined in
  6099. JavaScript 1.6.
  6100. The callback method you provide should have the following signature (all
  6101. parameters are optional):
  6102. ```javascript
  6103. function(item, index, enumerable);
  6104. ```
  6105. - `item` is the current item in the iteration.
  6106. - `index` is the current index in the iteration.
  6107. - `enumerable` is the enumerable object itself.
  6108. It should return the `true` to include the item in the results, `false`
  6109. otherwise.
  6110. Note that in addition to a callback, you can also pass an optional target
  6111. object that will be set as `this` on the context. This is a good way
  6112. to give your iterator function access to the current object.
  6113. @method filter
  6114. @param {Function} callback The callback to execute
  6115. @param {Object} [target] The target object to use
  6116. @return {Array} A filtered array.
  6117. */
  6118. filter: function(callback, target) {
  6119. var ret = [];
  6120. this.forEach(function(x, idx, i) {
  6121. if (callback.call(target, x, idx, i)) ret.push(x);
  6122. });
  6123. return ret ;
  6124. },
  6125. /**
  6126. Returns an array with all of the items in the enumeration where the passed
  6127. function returns false for. This method is the inverse of filter().
  6128. The callback method you provide should have the following signature (all
  6129. parameters are optional):
  6130. function(item, index, enumerable);
  6131. - *item* is the current item in the iteration.
  6132. - *index* is the current index in the iteration
  6133. - *enumerable* is the enumerable object itself.
  6134. It should return the a falsey value to include the item in the results.
  6135. Note that in addition to a callback, you can also pass an optional target
  6136. object that will be set as "this" on the context. This is a good way
  6137. to give your iterator function access to the current object.
  6138. @method reject
  6139. @param {Function} callback The callback to execute
  6140. @param {Object} [target] The target object to use
  6141. @return {Array} A rejected array.
  6142. */
  6143. reject: function(callback, target) {
  6144. return this.filter(function() {
  6145. return !(callback.apply(target, arguments));
  6146. });
  6147. },
  6148. /**
  6149. Returns an array with just the items with the matched property. You
  6150. can pass an optional second argument with the target value. Otherwise
  6151. this will match any property that evaluates to `true`.
  6152. @method filterProperty
  6153. @param {String} key the property to test
  6154. @param {String} [value] optional value to test against.
  6155. @return {Array} filtered array
  6156. */
  6157. filterProperty: function(key, value) {
  6158. return this.filter(iter.apply(this, arguments));
  6159. },
  6160. /**
  6161. Returns an array with the items that do not have truthy values for
  6162. key. You can pass an optional second argument with the target value. Otherwise
  6163. this will match any property that evaluates to false.
  6164. @method rejectProperty
  6165. @param {String} key the property to test
  6166. @param {String} [value] optional value to test against.
  6167. @return {Array} rejected array
  6168. */
  6169. rejectProperty: function(key, value) {
  6170. var exactValue = function(item) { return get(item, key) === value; },
  6171. hasValue = function(item) { return !!get(item, key); },
  6172. use = (arguments.length === 2 ? exactValue : hasValue);
  6173. return this.reject(use);
  6174. },
  6175. /**
  6176. Returns the first item in the array for which the callback returns true.
  6177. This method works similar to the `filter()` method defined in JavaScript 1.6
  6178. except that it will stop working on the array once a match is found.
  6179. The callback method you provide should have the following signature (all
  6180. parameters are optional):
  6181. ```javascript
  6182. function(item, index, enumerable);
  6183. ```
  6184. - `item` is the current item in the iteration.
  6185. - `index` is the current index in the iteration.
  6186. - `enumerable` is the enumerable object itself.
  6187. It should return the `true` to include the item in the results, `false`
  6188. otherwise.
  6189. Note that in addition to a callback, you can also pass an optional target
  6190. object that will be set as `this` on the context. This is a good way
  6191. to give your iterator function access to the current object.
  6192. @method find
  6193. @param {Function} callback The callback to execute
  6194. @param {Object} [target] The target object to use
  6195. @return {Object} Found item or `undefined`.
  6196. */
  6197. find: function(callback, target) {
  6198. var len = get(this, 'length') ;
  6199. if (target === undefined) target = null;
  6200. var last = null, next, found = false, ret ;
  6201. var context = popCtx();
  6202. for(var idx=0;idx<len && !found;idx++) {
  6203. next = this.nextObject(idx, last, context) ;
  6204. if (found = callback.call(target, next, idx, this)) ret = next ;
  6205. last = next ;
  6206. }
  6207. next = last = null ;
  6208. context = pushCtx(context);
  6209. return ret ;
  6210. },
  6211. /**
  6212. Returns the first item with a property matching the passed value. You
  6213. can pass an optional second argument with the target value. Otherwise
  6214. this will match any property that evaluates to `true`.
  6215. This method works much like the more generic `find()` method.
  6216. @method findProperty
  6217. @param {String} key the property to test
  6218. @param {String} [value] optional value to test against.
  6219. @return {Object} found item or `undefined`
  6220. */
  6221. findProperty: function(key, value) {
  6222. return this.find(iter.apply(this, arguments));
  6223. },
  6224. /**
  6225. Returns `true` if the passed function returns true for every item in the
  6226. enumeration. This corresponds with the `every()` method in JavaScript 1.6.
  6227. The callback method you provide should have the following signature (all
  6228. parameters are optional):
  6229. ```javascript
  6230. function(item, index, enumerable);
  6231. ```
  6232. - `item` is the current item in the iteration.
  6233. - `index` is the current index in the iteration.
  6234. - `enumerable` is the enumerable object itself.
  6235. It should return the `true` or `false`.
  6236. Note that in addition to a callback, you can also pass an optional target
  6237. object that will be set as `this` on the context. This is a good way
  6238. to give your iterator function access to the current object.
  6239. Example Usage:
  6240. ```javascript
  6241. if (people.every(isEngineer)) { Paychecks.addBigBonus(); }
  6242. ```
  6243. @method every
  6244. @param {Function} callback The callback to execute
  6245. @param {Object} [target] The target object to use
  6246. @return {Boolean}
  6247. */
  6248. every: function(callback, target) {
  6249. return !this.find(function(x, idx, i) {
  6250. return !callback.call(target, x, idx, i);
  6251. });
  6252. },
  6253. /**
  6254. Returns `true` if the passed property resolves to `true` for all items in
  6255. the enumerable. This method is often simpler/faster than using a callback.
  6256. @method everyProperty
  6257. @param {String} key the property to test
  6258. @param {String} [value] optional value to test against.
  6259. @return {Boolean}
  6260. */
  6261. everyProperty: function(key, value) {
  6262. return this.every(iter.apply(this, arguments));
  6263. },
  6264. /**
  6265. Returns `true` if the passed function returns true for any item in the
  6266. enumeration. This corresponds with the `some()` method in JavaScript 1.6.
  6267. The callback method you provide should have the following signature (all
  6268. parameters are optional):
  6269. ```javascript
  6270. function(item, index, enumerable);
  6271. ```
  6272. - `item` is the current item in the iteration.
  6273. - `index` is the current index in the iteration.
  6274. - `enumerable` is the enumerable object itself.
  6275. It should return the `true` to include the item in the results, `false`
  6276. otherwise.
  6277. Note that in addition to a callback, you can also pass an optional target
  6278. object that will be set as `this` on the context. This is a good way
  6279. to give your iterator function access to the current object.
  6280. Usage Example:
  6281. ```javascript
  6282. if (people.some(isManager)) { Paychecks.addBiggerBonus(); }
  6283. ```
  6284. @method some
  6285. @param {Function} callback The callback to execute
  6286. @param {Object} [target] The target object to use
  6287. @return {Array} A filtered array.
  6288. */
  6289. some: function(callback, target) {
  6290. return !!this.find(function(x, idx, i) {
  6291. return !!callback.call(target, x, idx, i);
  6292. });
  6293. },
  6294. /**
  6295. Returns `true` if the passed property resolves to `true` for any item in
  6296. the enumerable. This method is often simpler/faster than using a callback.
  6297. @method someProperty
  6298. @param {String} key the property to test
  6299. @param {String} [value] optional value to test against.
  6300. @return {Boolean} `true`
  6301. */
  6302. someProperty: function(key, value) {
  6303. return this.some(iter.apply(this, arguments));
  6304. },
  6305. /**
  6306. This will combine the values of the enumerator into a single value. It
  6307. is a useful way to collect a summary value from an enumeration. This
  6308. corresponds to the `reduce()` method defined in JavaScript 1.8.
  6309. The callback method you provide should have the following signature (all
  6310. parameters are optional):
  6311. ```javascript
  6312. function(previousValue, item, index, enumerable);
  6313. ```
  6314. - `previousValue` is the value returned by the last call to the iterator.
  6315. - `item` is the current item in the iteration.
  6316. - `index` is the current index in the iteration.
  6317. - `enumerable` is the enumerable object itself.
  6318. Return the new cumulative value.
  6319. In addition to the callback you can also pass an `initialValue`. An error
  6320. will be raised if you do not pass an initial value and the enumerator is
  6321. empty.
  6322. Note that unlike the other methods, this method does not allow you to
  6323. pass a target object to set as this for the callback. It's part of the
  6324. spec. Sorry.
  6325. @method reduce
  6326. @param {Function} callback The callback to execute
  6327. @param {Object} initialValue Initial value for the reduce
  6328. @param {String} reducerProperty internal use only.
  6329. @return {Object} The reduced value.
  6330. */
  6331. reduce: function(callback, initialValue, reducerProperty) {
  6332. if (typeof callback !== "function") { throw new TypeError(); }
  6333. var ret = initialValue;
  6334. this.forEach(function(item, i) {
  6335. ret = callback.call(null, ret, item, i, this, reducerProperty);
  6336. }, this);
  6337. return ret;
  6338. },
  6339. /**
  6340. Invokes the named method on every object in the receiver that
  6341. implements it. This method corresponds to the implementation in
  6342. Prototype 1.6.
  6343. @method invoke
  6344. @param {String} methodName the name of the method
  6345. @param {Object...} args optional arguments to pass as well.
  6346. @return {Array} return values from calling invoke.
  6347. */
  6348. invoke: function(methodName) {
  6349. var args, ret = [];
  6350. if (arguments.length>1) args = a_slice.call(arguments, 1);
  6351. this.forEach(function(x, idx) {
  6352. var method = x && x[methodName];
  6353. if ('function' === typeof method) {
  6354. ret[idx] = args ? method.apply(x, args) : method.call(x);
  6355. }
  6356. }, this);
  6357. return ret;
  6358. },
  6359. /**
  6360. Simply converts the enumerable into a genuine array. The order is not
  6361. guaranteed. Corresponds to the method implemented by Prototype.
  6362. @method toArray
  6363. @return {Array} the enumerable as an array.
  6364. */
  6365. toArray: function() {
  6366. var ret = [];
  6367. this.forEach(function(o, idx) { ret[idx] = o; });
  6368. return ret ;
  6369. },
  6370. /**
  6371. Returns a copy of the array with all null elements removed.
  6372. ```javascript
  6373. var arr = ["a", null, "c", null];
  6374. arr.compact(); // ["a", "c"]
  6375. ```
  6376. @method compact
  6377. @return {Array} the array without null elements.
  6378. */
  6379. compact: function() { return this.without(null); },
  6380. /**
  6381. Returns a new enumerable that excludes the passed value. The default
  6382. implementation returns an array regardless of the receiver type unless
  6383. the receiver does not contain the value.
  6384. ```javascript
  6385. var arr = ["a", "b", "a", "c"];
  6386. arr.without("a"); // ["b", "c"]
  6387. ```
  6388. @method without
  6389. @param {Object} value
  6390. @return {Ember.Enumerable}
  6391. */
  6392. without: function(value) {
  6393. if (!this.contains(value)) return this; // nothing to do
  6394. var ret = [] ;
  6395. this.forEach(function(k) {
  6396. if (k !== value) ret[ret.length] = k;
  6397. }) ;
  6398. return ret ;
  6399. },
  6400. /**
  6401. Returns a new enumerable that contains only unique values. The default
  6402. implementation returns an array regardless of the receiver type.
  6403. ```javascript
  6404. var arr = ["a", "a", "b", "b"];
  6405. arr.uniq(); // ["a", "b"]
  6406. ```
  6407. @method uniq
  6408. @return {Ember.Enumerable}
  6409. */
  6410. uniq: function() {
  6411. var ret = [];
  6412. this.forEach(function(k){
  6413. if (a_indexOf(ret, k)<0) ret.push(k);
  6414. });
  6415. return ret;
  6416. },
  6417. /**
  6418. This property will trigger anytime the enumerable's content changes.
  6419. You can observe this property to be notified of changes to the enumerables
  6420. content.
  6421. For plain enumerables, this property is read only. `Ember.Array` overrides
  6422. this method.
  6423. @property []
  6424. @type Ember.Array
  6425. */
  6426. '[]': Ember.computed(function(key, value) {
  6427. return this;
  6428. }),
  6429. // ..........................................................
  6430. // ENUMERABLE OBSERVERS
  6431. //
  6432. /**
  6433. Registers an enumerable observer. Must implement `Ember.EnumerableObserver`
  6434. mixin.
  6435. @method addEnumerableObserver
  6436. @param target {Object}
  6437. @param opts {Hash}
  6438. */
  6439. addEnumerableObserver: function(target, opts) {
  6440. var willChange = (opts && opts.willChange) || 'enumerableWillChange',
  6441. didChange = (opts && opts.didChange) || 'enumerableDidChange';
  6442. var hasObservers = get(this, 'hasEnumerableObservers');
  6443. if (!hasObservers) Ember.propertyWillChange(this, 'hasEnumerableObservers');
  6444. Ember.addListener(this, '@enumerable:before', target, willChange);
  6445. Ember.addListener(this, '@enumerable:change', target, didChange);
  6446. if (!hasObservers) Ember.propertyDidChange(this, 'hasEnumerableObservers');
  6447. return this;
  6448. },
  6449. /**
  6450. Removes a registered enumerable observer.
  6451. @method removeEnumerableObserver
  6452. @param target {Object}
  6453. @param [opts] {Hash}
  6454. */
  6455. removeEnumerableObserver: function(target, opts) {
  6456. var willChange = (opts && opts.willChange) || 'enumerableWillChange',
  6457. didChange = (opts && opts.didChange) || 'enumerableDidChange';
  6458. var hasObservers = get(this, 'hasEnumerableObservers');
  6459. if (hasObservers) Ember.propertyWillChange(this, 'hasEnumerableObservers');
  6460. Ember.removeListener(this, '@enumerable:before', target, willChange);
  6461. Ember.removeListener(this, '@enumerable:change', target, didChange);
  6462. if (hasObservers) Ember.propertyDidChange(this, 'hasEnumerableObservers');
  6463. return this;
  6464. },
  6465. /**
  6466. Becomes true whenever the array currently has observers watching changes
  6467. on the array.
  6468. @property hasEnumerableObservers
  6469. @type Boolean
  6470. */
  6471. hasEnumerableObservers: Ember.computed(function() {
  6472. return Ember.hasListeners(this, '@enumerable:change') || Ember.hasListeners(this, '@enumerable:before');
  6473. }),
  6474. /**
  6475. Invoke this method just before the contents of your enumerable will
  6476. change. You can either omit the parameters completely or pass the objects
  6477. to be removed or added if available or just a count.
  6478. @method enumerableContentWillChange
  6479. @param {Ember.Enumerable|Number} removing An enumerable of the objects to
  6480. be removed or the number of items to be removed.
  6481. @param {Ember.Enumerable|Number} adding An enumerable of the objects to be
  6482. added or the number of items to be added.
  6483. @chainable
  6484. */
  6485. enumerableContentWillChange: function(removing, adding) {
  6486. var removeCnt, addCnt, hasDelta;
  6487. if ('number' === typeof removing) removeCnt = removing;
  6488. else if (removing) removeCnt = get(removing, 'length');
  6489. else removeCnt = removing = -1;
  6490. if ('number' === typeof adding) addCnt = adding;
  6491. else if (adding) addCnt = get(adding,'length');
  6492. else addCnt = adding = -1;
  6493. hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0;
  6494. if (removing === -1) removing = null;
  6495. if (adding === -1) adding = null;
  6496. Ember.propertyWillChange(this, '[]');
  6497. if (hasDelta) Ember.propertyWillChange(this, 'length');
  6498. Ember.sendEvent(this, '@enumerable:before', [this, removing, adding]);
  6499. return this;
  6500. },
  6501. /**
  6502. Invoke this method when the contents of your enumerable has changed.
  6503. This will notify any observers watching for content changes. If your are
  6504. implementing an ordered enumerable (such as an array), also pass the
  6505. start and end values where the content changed so that it can be used to
  6506. notify range observers.
  6507. @method enumerableContentDidChange
  6508. @param {Number} [start] optional start offset for the content change.
  6509. For unordered enumerables, you should always pass -1.
  6510. @param {Ember.Enumerable|Number} removing An enumerable of the objects to
  6511. be removed or the number of items to be removed.
  6512. @param {Ember.Enumerable|Number} adding An enumerable of the objects to
  6513. be added or the number of items to be added.
  6514. @chainable
  6515. */
  6516. enumerableContentDidChange: function(removing, adding) {
  6517. var notify = this.propertyDidChange, removeCnt, addCnt, hasDelta;
  6518. if ('number' === typeof removing) removeCnt = removing;
  6519. else if (removing) removeCnt = get(removing, 'length');
  6520. else removeCnt = removing = -1;
  6521. if ('number' === typeof adding) addCnt = adding;
  6522. else if (adding) addCnt = get(adding, 'length');
  6523. else addCnt = adding = -1;
  6524. hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0;
  6525. if (removing === -1) removing = null;
  6526. if (adding === -1) adding = null;
  6527. Ember.sendEvent(this, '@enumerable:change', [this, removing, adding]);
  6528. if (hasDelta) Ember.propertyDidChange(this, 'length');
  6529. Ember.propertyDidChange(this, '[]');
  6530. return this ;
  6531. }
  6532. }) ;
  6533. })();
  6534. (function() {
  6535. /**
  6536. @module ember
  6537. @submodule ember-runtime
  6538. */
  6539. // ..........................................................
  6540. // HELPERS
  6541. //
  6542. var get = Ember.get, set = Ember.set, meta = Ember.meta, map = Ember.EnumerableUtils.map, cacheFor = Ember.cacheFor;
  6543. function none(obj) { return obj===null || obj===undefined; }
  6544. // ..........................................................
  6545. // ARRAY
  6546. //
  6547. /**
  6548. This module implements Observer-friendly Array-like behavior. This mixin is
  6549. picked up by the Array class as well as other controllers, etc. that want to
  6550. appear to be arrays.
  6551. Unlike `Ember.Enumerable,` this mixin defines methods specifically for
  6552. collections that provide index-ordered access to their contents. When you
  6553. are designing code that needs to accept any kind of Array-like object, you
  6554. should use these methods instead of Array primitives because these will
  6555. properly notify observers of changes to the array.
  6556. Although these methods are efficient, they do add a layer of indirection to
  6557. your application so it is a good idea to use them only when you need the
  6558. flexibility of using both true JavaScript arrays and "virtual" arrays such
  6559. as controllers and collections.
  6560. You can use the methods defined in this module to access and modify array
  6561. contents in a KVO-friendly way. You can also be notified whenever the
  6562. membership if an array changes by changing the syntax of the property to
  6563. `.observes('*myProperty.[]')`.
  6564. To support `Ember.Array` in your own class, you must override two
  6565. primitives to use it: `replace()` and `objectAt()`.
  6566. Note that the Ember.Array mixin also incorporates the `Ember.Enumerable`
  6567. mixin. All `Ember.Array`-like objects are also enumerable.
  6568. @class Array
  6569. @namespace Ember
  6570. @extends Ember.Mixin
  6571. @uses Ember.Enumerable
  6572. @since Ember 0.9.0
  6573. */
  6574. Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.prototype */ {
  6575. // compatibility
  6576. isSCArray: true,
  6577. /**
  6578. Your array must support the `length` property. Your replace methods should
  6579. set this property whenever it changes.
  6580. @property {Number} length
  6581. */
  6582. length: Ember.required(),
  6583. /**
  6584. Returns the object at the given `index`. If the given `index` is negative
  6585. or is greater or equal than the array length, returns `undefined`.
  6586. This is one of the primitives you must implement to support `Ember.Array`.
  6587. If your object supports retrieving the value of an array item using `get()`
  6588. (i.e. `myArray.get(0)`), then you do not need to implement this method
  6589. yourself.
  6590. ```javascript
  6591. var arr = ['a', 'b', 'c', 'd'];
  6592. arr.objectAt(0); // "a"
  6593. arr.objectAt(3); // "d"
  6594. arr.objectAt(-1); // undefined
  6595. arr.objectAt(4); // undefined
  6596. arr.objectAt(5); // undefined
  6597. ```
  6598. @method objectAt
  6599. @param {Number} idx The index of the item to return.
  6600. */
  6601. objectAt: function(idx) {
  6602. if ((idx < 0) || (idx>=get(this, 'length'))) return undefined ;
  6603. return get(this, idx);
  6604. },
  6605. /**
  6606. This returns the objects at the specified indexes, using `objectAt`.
  6607. ```javascript
  6608. var arr = ['a', 'b', 'c', 'd'];
  6609. arr.objectsAt([0, 1, 2]); // ["a", "b", "c"]
  6610. arr.objectsAt([2, 3, 4]); // ["c", "d", undefined]
  6611. ```
  6612. @method objectsAt
  6613. @param {Array} indexes An array of indexes of items to return.
  6614. */
  6615. objectsAt: function(indexes) {
  6616. var self = this;
  6617. return map(indexes, function(idx){ return self.objectAt(idx); });
  6618. },
  6619. // overrides Ember.Enumerable version
  6620. nextObject: function(idx) {
  6621. return this.objectAt(idx);
  6622. },
  6623. /**
  6624. This is the handler for the special array content property. If you get
  6625. this property, it will return this. If you set this property it a new
  6626. array, it will replace the current content.
  6627. This property overrides the default property defined in `Ember.Enumerable`.
  6628. @property []
  6629. */
  6630. '[]': Ember.computed(function(key, value) {
  6631. if (value !== undefined) this.replace(0, get(this, 'length'), value) ;
  6632. return this ;
  6633. }),
  6634. firstObject: Ember.computed(function() {
  6635. return this.objectAt(0);
  6636. }),
  6637. lastObject: Ember.computed(function() {
  6638. return this.objectAt(get(this, 'length')-1);
  6639. }),
  6640. // optimized version from Enumerable
  6641. contains: function(obj){
  6642. return this.indexOf(obj) >= 0;
  6643. },
  6644. // Add any extra methods to Ember.Array that are native to the built-in Array.
  6645. /**
  6646. Returns a new array that is a slice of the receiver. This implementation
  6647. uses the observable array methods to retrieve the objects for the new
  6648. slice.
  6649. ```javascript
  6650. var arr = ['red', 'green', 'blue'];
  6651. arr.slice(0); // ['red', 'green', 'blue']
  6652. arr.slice(0, 2); // ['red', 'green']
  6653. arr.slice(1, 100); // ['green', 'blue']
  6654. ```
  6655. @method slice
  6656. @param beginIndex {Integer} (Optional) index to begin slicing from.
  6657. @param endIndex {Integer} (Optional) index to end the slice at.
  6658. @return {Array} New array with specified slice
  6659. */
  6660. slice: function(beginIndex, endIndex) {
  6661. var ret = [];
  6662. var length = get(this, 'length') ;
  6663. if (none(beginIndex)) beginIndex = 0 ;
  6664. if (none(endIndex) || (endIndex > length)) endIndex = length ;
  6665. while(beginIndex < endIndex) {
  6666. ret[ret.length] = this.objectAt(beginIndex++) ;
  6667. }
  6668. return ret ;
  6669. },
  6670. /**
  6671. Returns the index of the given object's first occurrence.
  6672. If no `startAt` argument is given, the starting location to
  6673. search is 0. If it's negative, will count backward from
  6674. the end of the array. Returns -1 if no match is found.
  6675. ```javascript
  6676. var arr = ["a", "b", "c", "d", "a"];
  6677. arr.indexOf("a"); // 0
  6678. arr.indexOf("z"); // -1
  6679. arr.indexOf("a", 2); // 4
  6680. arr.indexOf("a", -1); // 4
  6681. arr.indexOf("b", 3); // -1
  6682. arr.indexOf("a", 100); // -1
  6683. ```
  6684. @method indexOf
  6685. @param {Object} object the item to search for
  6686. @param {Number} startAt optional starting location to search, default 0
  6687. @return {Number} index or -1 if not found
  6688. */
  6689. indexOf: function(object, startAt) {
  6690. var idx, len = get(this, 'length');
  6691. if (startAt === undefined) startAt = 0;
  6692. if (startAt < 0) startAt += len;
  6693. for(idx=startAt;idx<len;idx++) {
  6694. if (this.objectAt(idx, true) === object) return idx ;
  6695. }
  6696. return -1;
  6697. },
  6698. /**
  6699. Returns the index of the given object's last occurrence.
  6700. If no `startAt` argument is given, the search starts from
  6701. the last position. If it's negative, will count backward
  6702. from the end of the array. Returns -1 if no match is found.
  6703. ```javascript
  6704. var arr = ["a", "b", "c", "d", "a"];
  6705. arr.lastIndexOf("a"); // 4
  6706. arr.lastIndexOf("z"); // -1
  6707. arr.lastIndexOf("a", 2); // 0
  6708. arr.lastIndexOf("a", -1); // 4
  6709. arr.lastIndexOf("b", 3); // 1
  6710. arr.lastIndexOf("a", 100); // 4
  6711. ```
  6712. @method lastIndexOf
  6713. @param {Object} object the item to search for
  6714. @param {Number} startAt optional starting location to search, default 0
  6715. @return {Number} index or -1 if not found
  6716. */
  6717. lastIndexOf: function(object, startAt) {
  6718. var idx, len = get(this, 'length');
  6719. if (startAt === undefined || startAt >= len) startAt = len-1;
  6720. if (startAt < 0) startAt += len;
  6721. for(idx=startAt;idx>=0;idx--) {
  6722. if (this.objectAt(idx) === object) return idx ;
  6723. }
  6724. return -1;
  6725. },
  6726. // ..........................................................
  6727. // ARRAY OBSERVERS
  6728. //
  6729. /**
  6730. Adds an array observer to the receiving array. The array observer object
  6731. normally must implement two methods:
  6732. * `arrayWillChange(start, removeCount, addCount)` - This method will be
  6733. called just before the array is modified.
  6734. * `arrayDidChange(start, removeCount, addCount)` - This method will be
  6735. called just after the array is modified.
  6736. Both callbacks will be passed the starting index of the change as well a
  6737. a count of the items to be removed and added. You can use these callbacks
  6738. to optionally inspect the array during the change, clear caches, or do
  6739. any other bookkeeping necessary.
  6740. In addition to passing a target, you can also include an options hash
  6741. which you can use to override the method names that will be invoked on the
  6742. target.
  6743. @method addArrayObserver
  6744. @param {Object} target The observer object.
  6745. @param {Hash} opts Optional hash of configuration options including
  6746. `willChange`, `didChange`, and a `context` option.
  6747. @return {Ember.Array} receiver
  6748. */
  6749. addArrayObserver: function(target, opts) {
  6750. var willChange = (opts && opts.willChange) || 'arrayWillChange',
  6751. didChange = (opts && opts.didChange) || 'arrayDidChange';
  6752. var hasObservers = get(this, 'hasArrayObservers');
  6753. if (!hasObservers) Ember.propertyWillChange(this, 'hasArrayObservers');
  6754. Ember.addListener(this, '@array:before', target, willChange);
  6755. Ember.addListener(this, '@array:change', target, didChange);
  6756. if (!hasObservers) Ember.propertyDidChange(this, 'hasArrayObservers');
  6757. return this;
  6758. },
  6759. /**
  6760. Removes an array observer from the object if the observer is current
  6761. registered. Calling this method multiple times with the same object will
  6762. have no effect.
  6763. @method removeArrayObserver
  6764. @param {Object} target The object observing the array.
  6765. @return {Ember.Array} receiver
  6766. */
  6767. removeArrayObserver: function(target, opts) {
  6768. var willChange = (opts && opts.willChange) || 'arrayWillChange',
  6769. didChange = (opts && opts.didChange) || 'arrayDidChange';
  6770. var hasObservers = get(this, 'hasArrayObservers');
  6771. if (hasObservers) Ember.propertyWillChange(this, 'hasArrayObservers');
  6772. Ember.removeListener(this, '@array:before', target, willChange);
  6773. Ember.removeListener(this, '@array:change', target, didChange);
  6774. if (hasObservers) Ember.propertyDidChange(this, 'hasArrayObservers');
  6775. return this;
  6776. },
  6777. /**
  6778. Becomes true whenever the array currently has observers watching changes
  6779. on the array.
  6780. @property Boolean
  6781. */
  6782. hasArrayObservers: Ember.computed(function() {
  6783. return Ember.hasListeners(this, '@array:change') || Ember.hasListeners(this, '@array:before');
  6784. }),
  6785. /**
  6786. If you are implementing an object that supports `Ember.Array`, call this
  6787. method just before the array content changes to notify any observers and
  6788. invalidate any related properties. Pass the starting index of the change
  6789. as well as a delta of the amounts to change.
  6790. @method arrayContentWillChange
  6791. @param {Number} startIdx The starting index in the array that will change.
  6792. @param {Number} removeAmt The number of items that will be removed. If you
  6793. pass `null` assumes 0
  6794. @param {Number} addAmt The number of items that will be added If you
  6795. pass `null` assumes 0.
  6796. @return {Ember.Array} receiver
  6797. */
  6798. arrayContentWillChange: function(startIdx, removeAmt, addAmt) {
  6799. // if no args are passed assume everything changes
  6800. if (startIdx===undefined) {
  6801. startIdx = 0;
  6802. removeAmt = addAmt = -1;
  6803. } else {
  6804. if (removeAmt === undefined) removeAmt=-1;
  6805. if (addAmt === undefined) addAmt=-1;
  6806. }
  6807. // Make sure the @each proxy is set up if anyone is observing @each
  6808. if (Ember.isWatching(this, '@each')) { get(this, '@each'); }
  6809. Ember.sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]);
  6810. var removing, lim;
  6811. if (startIdx>=0 && removeAmt>=0 && get(this, 'hasEnumerableObservers')) {
  6812. removing = [];
  6813. lim = startIdx+removeAmt;
  6814. for(var idx=startIdx;idx<lim;idx++) removing.push(this.objectAt(idx));
  6815. } else {
  6816. removing = removeAmt;
  6817. }
  6818. this.enumerableContentWillChange(removing, addAmt);
  6819. return this;
  6820. },
  6821. arrayContentDidChange: function(startIdx, removeAmt, addAmt) {
  6822. // if no args are passed assume everything changes
  6823. if (startIdx===undefined) {
  6824. startIdx = 0;
  6825. removeAmt = addAmt = -1;
  6826. } else {
  6827. if (removeAmt === undefined) removeAmt=-1;
  6828. if (addAmt === undefined) addAmt=-1;
  6829. }
  6830. var adding, lim;
  6831. if (startIdx>=0 && addAmt>=0 && get(this, 'hasEnumerableObservers')) {
  6832. adding = [];
  6833. lim = startIdx+addAmt;
  6834. for(var idx=startIdx;idx<lim;idx++) adding.push(this.objectAt(idx));
  6835. } else {
  6836. adding = addAmt;
  6837. }
  6838. this.enumerableContentDidChange(removeAmt, adding);
  6839. Ember.sendEvent(this, '@array:change', [this, startIdx, removeAmt, addAmt]);
  6840. var length = get(this, 'length'),
  6841. cachedFirst = cacheFor(this, 'firstObject'),
  6842. cachedLast = cacheFor(this, 'lastObject');
  6843. if (this.objectAt(0) !== cachedFirst) {
  6844. Ember.propertyWillChange(this, 'firstObject');
  6845. Ember.propertyDidChange(this, 'firstObject');
  6846. }
  6847. if (this.objectAt(length-1) !== cachedLast) {
  6848. Ember.propertyWillChange(this, 'lastObject');
  6849. Ember.propertyDidChange(this, 'lastObject');
  6850. }
  6851. return this;
  6852. },
  6853. // ..........................................................
  6854. // ENUMERATED PROPERTIES
  6855. //
  6856. /**
  6857. Returns a special object that can be used to observe individual properties
  6858. on the array. Just get an equivalent property on this object and it will
  6859. return an enumerable that maps automatically to the named key on the
  6860. member objects.
  6861. @property @each
  6862. */
  6863. '@each': Ember.computed(function() {
  6864. if (!this.__each) this.__each = new Ember.EachProxy(this);
  6865. return this.__each;
  6866. })
  6867. }) ;
  6868. })();
  6869. (function() {
  6870. /**
  6871. @module ember
  6872. @submodule ember-runtime
  6873. */
  6874. /**
  6875. Implements some standard methods for comparing objects. Add this mixin to
  6876. any class you create that can compare its instances.
  6877. You should implement the `compare()` method.
  6878. @class Comparable
  6879. @namespace Ember
  6880. @extends Ember.Mixin
  6881. @since Ember 0.9
  6882. */
  6883. Ember.Comparable = Ember.Mixin.create( /** @scope Ember.Comparable.prototype */{
  6884. /**
  6885. walk like a duck. Indicates that the object can be compared.
  6886. @property isComparable
  6887. @type Boolean
  6888. @default true
  6889. */
  6890. isComparable: true,
  6891. /**
  6892. Override to return the result of the comparison of the two parameters. The
  6893. compare method should return:
  6894. - `-1` if `a < b`
  6895. - `0` if `a == b`
  6896. - `1` if `a > b`
  6897. Default implementation raises an exception.
  6898. @method compare
  6899. @param a {Object} the first object to compare
  6900. @param b {Object} the second object to compare
  6901. @return {Integer} the result of the comparison
  6902. */
  6903. compare: Ember.required(Function)
  6904. });
  6905. })();
  6906. (function() {
  6907. /**
  6908. @module ember
  6909. @submodule ember-runtime
  6910. */
  6911. var get = Ember.get, set = Ember.set;
  6912. /**
  6913. Implements some standard methods for copying an object. Add this mixin to
  6914. any object you create that can create a copy of itself. This mixin is
  6915. added automatically to the built-in array.
  6916. You should generally implement the `copy()` method to return a copy of the
  6917. receiver.
  6918. Note that `frozenCopy()` will only work if you also implement
  6919. `Ember.Freezable`.
  6920. @class Copyable
  6921. @namespace Ember
  6922. @extends Ember.Mixin
  6923. @since Ember 0.9
  6924. */
  6925. Ember.Copyable = Ember.Mixin.create(
  6926. /** @scope Ember.Copyable.prototype */ {
  6927. /**
  6928. Override to return a copy of the receiver. Default implementation raises
  6929. an exception.
  6930. @method copy
  6931. @param deep {Boolean} if `true`, a deep copy of the object should be made
  6932. @return {Object} copy of receiver
  6933. */
  6934. copy: Ember.required(Function),
  6935. /**
  6936. If the object implements `Ember.Freezable`, then this will return a new
  6937. copy if the object is not frozen and the receiver if the object is frozen.
  6938. Raises an exception if you try to call this method on a object that does
  6939. not support freezing.
  6940. You should use this method whenever you want a copy of a freezable object
  6941. since a freezable object can simply return itself without actually
  6942. consuming more memory.
  6943. @method frozenCopy
  6944. @return {Object} copy of receiver or receiver
  6945. */
  6946. frozenCopy: function() {
  6947. if (Ember.Freezable && Ember.Freezable.detect(this)) {
  6948. return get(this, 'isFrozen') ? this : this.copy().freeze();
  6949. } else {
  6950. throw new Error(Ember.String.fmt("%@ does not support freezing", [this]));
  6951. }
  6952. }
  6953. });
  6954. })();
  6955. (function() {
  6956. /**
  6957. @module ember
  6958. @submodule ember-runtime
  6959. */
  6960. var get = Ember.get, set = Ember.set;
  6961. /**
  6962. The `Ember.Freezable` mixin implements some basic methods for marking an
  6963. object as frozen. Once an object is frozen it should be read only. No changes
  6964. may be made the internal state of the object.
  6965. ## Enforcement
  6966. To fully support freezing in your subclass, you must include this mixin and
  6967. override any method that might alter any property on the object to instead
  6968. raise an exception. You can check the state of an object by checking the
  6969. `isFrozen` property.
  6970. Although future versions of JavaScript may support language-level freezing
  6971. object objects, that is not the case today. Even if an object is freezable,
  6972. it is still technically possible to modify the object, even though it could
  6973. break other parts of your application that do not expect a frozen object to
  6974. change. It is, therefore, very important that you always respect the
  6975. `isFrozen` property on all freezable objects.
  6976. ## Example Usage
  6977. The example below shows a simple object that implement the `Ember.Freezable`
  6978. protocol.
  6979. ```javascript
  6980. Contact = Ember.Object.extend(Ember.Freezable, {
  6981. firstName: null,
  6982. lastName: null,
  6983. // swaps the names
  6984. swapNames: function() {
  6985. if (this.get('isFrozen')) throw Ember.FROZEN_ERROR;
  6986. var tmp = this.get('firstName');
  6987. this.set('firstName', this.get('lastName'));
  6988. this.set('lastName', tmp);
  6989. return this;
  6990. }
  6991. });
  6992. c = Context.create({ firstName: "John", lastName: "Doe" });
  6993. c.swapNames(); // returns c
  6994. c.freeze();
  6995. c.swapNames(); // EXCEPTION
  6996. ```
  6997. ## Copying
  6998. Usually the `Ember.Freezable` protocol is implemented in cooperation with the
  6999. `Ember.Copyable` protocol, which defines a `frozenCopy()` method that will
  7000. return a frozen object, if the object implements this method as well.
  7001. @class Freezable
  7002. @namespace Ember
  7003. @extends Ember.Mixin
  7004. @since Ember 0.9
  7005. */
  7006. Ember.Freezable = Ember.Mixin.create(
  7007. /** @scope Ember.Freezable.prototype */ {
  7008. /**
  7009. Set to `true` when the object is frozen. Use this property to detect
  7010. whether your object is frozen or not.
  7011. @property isFrozen
  7012. @type Boolean
  7013. */
  7014. isFrozen: false,
  7015. /**
  7016. Freezes the object. Once this method has been called the object should
  7017. no longer allow any properties to be edited.
  7018. @method freeze
  7019. @return {Object} receiver
  7020. */
  7021. freeze: function() {
  7022. if (get(this, 'isFrozen')) return this;
  7023. set(this, 'isFrozen', true);
  7024. return this;
  7025. }
  7026. });
  7027. Ember.FROZEN_ERROR = "Frozen object cannot be modified.";
  7028. })();
  7029. (function() {
  7030. /**
  7031. @module ember
  7032. @submodule ember-runtime
  7033. */
  7034. var forEach = Ember.EnumerableUtils.forEach;
  7035. /**
  7036. This mixin defines the API for modifying generic enumerables. These methods
  7037. can be applied to an object regardless of whether it is ordered or
  7038. unordered.
  7039. Note that an Enumerable can change even if it does not implement this mixin.
  7040. For example, a MappedEnumerable cannot be directly modified but if its
  7041. underlying enumerable changes, it will change also.
  7042. ## Adding Objects
  7043. To add an object to an enumerable, use the `addObject()` method. This
  7044. method will only add the object to the enumerable if the object is not
  7045. already present and the object if of a type supported by the enumerable.
  7046. ```javascript
  7047. set.addObject(contact);
  7048. ```
  7049. ## Removing Objects
  7050. To remove an object form an enumerable, use the `removeObject()` method. This
  7051. will only remove the object if it is already in the enumerable, otherwise
  7052. this method has no effect.
  7053. ```javascript
  7054. set.removeObject(contact);
  7055. ```
  7056. ## Implementing In Your Own Code
  7057. If you are implementing an object and want to support this API, just include
  7058. this mixin in your class and implement the required methods. In your unit
  7059. tests, be sure to apply the Ember.MutableEnumerableTests to your object.
  7060. @class MutableEnumerable
  7061. @namespace Ember
  7062. @extends Ember.Mixin
  7063. @uses Ember.Enumerable
  7064. */
  7065. Ember.MutableEnumerable = Ember.Mixin.create(Ember.Enumerable,
  7066. /** @scope Ember.MutableEnumerable.prototype */ {
  7067. /**
  7068. __Required.__ You must implement this method to apply this mixin.
  7069. Attempts to add the passed object to the receiver if the object is not
  7070. already present in the collection. If the object is present, this method
  7071. has no effect.
  7072. If the passed object is of a type not supported by the receiver
  7073. then this method should raise an exception.
  7074. @method addObject
  7075. @param {Object} object The object to add to the enumerable.
  7076. @return {Object} the passed object
  7077. */
  7078. addObject: Ember.required(Function),
  7079. /**
  7080. Adds each object in the passed enumerable to the receiver.
  7081. @method addObjects
  7082. @param {Ember.Enumerable} objects the objects to add.
  7083. @return {Object} receiver
  7084. */
  7085. addObjects: function(objects) {
  7086. Ember.beginPropertyChanges(this);
  7087. forEach(objects, function(obj) { this.addObject(obj); }, this);
  7088. Ember.endPropertyChanges(this);
  7089. return this;
  7090. },
  7091. /**
  7092. __Required.__ You must implement this method to apply this mixin.
  7093. Attempts to remove the passed object from the receiver collection if the
  7094. object is in present in the collection. If the object is not present,
  7095. this method has no effect.
  7096. If the passed object is of a type not supported by the receiver
  7097. then this method should raise an exception.
  7098. @method removeObject
  7099. @param {Object} object The object to remove from the enumerable.
  7100. @return {Object} the passed object
  7101. */
  7102. removeObject: Ember.required(Function),
  7103. /**
  7104. Removes each objects in the passed enumerable from the receiver.
  7105. @method removeObjects
  7106. @param {Ember.Enumerable} objects the objects to remove
  7107. @return {Object} receiver
  7108. */
  7109. removeObjects: function(objects) {
  7110. Ember.beginPropertyChanges(this);
  7111. forEach(objects, function(obj) { this.removeObject(obj); }, this);
  7112. Ember.endPropertyChanges(this);
  7113. return this;
  7114. }
  7115. });
  7116. })();
  7117. (function() {
  7118. /**
  7119. @module ember
  7120. @submodule ember-runtime
  7121. */
  7122. // ..........................................................
  7123. // CONSTANTS
  7124. //
  7125. var OUT_OF_RANGE_EXCEPTION = "Index out of range" ;
  7126. var EMPTY = [];
  7127. // ..........................................................
  7128. // HELPERS
  7129. //
  7130. var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach;
  7131. /**
  7132. This mixin defines the API for modifying array-like objects. These methods
  7133. can be applied only to a collection that keeps its items in an ordered set.
  7134. Note that an Array can change even if it does not implement this mixin.
  7135. For example, one might implement a SparseArray that cannot be directly
  7136. modified, but if its underlying enumerable changes, it will change also.
  7137. @class MutableArray
  7138. @namespace Ember
  7139. @extends Ember.Mixin
  7140. @uses Ember.Array
  7141. @uses Ember.MutableEnumerable
  7142. */
  7143. Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
  7144. /** @scope Ember.MutableArray.prototype */ {
  7145. /**
  7146. __Required.__ You must implement this method to apply this mixin.
  7147. This is one of the primitives you must implement to support `Ember.Array`.
  7148. You should replace amt objects started at idx with the objects in the
  7149. passed array. You should also call `this.enumerableContentDidChange()`
  7150. @method replace
  7151. @param {Number} idx Starting index in the array to replace. If
  7152. idx >= length, then append to the end of the array.
  7153. @param {Number} amt Number of elements that should be removed from
  7154. the array, starting at *idx*.
  7155. @param {Array} objects An array of zero or more objects that should be
  7156. inserted into the array at *idx*
  7157. */
  7158. replace: Ember.required(),
  7159. /**
  7160. Remove all elements from self. This is useful if you
  7161. want to reuse an existing array without having to recreate it.
  7162. ```javascript
  7163. var colors = ["red", "green", "blue"];
  7164. color.length(); // 3
  7165. colors.clear(); // []
  7166. colors.length(); // 0
  7167. ```
  7168. @method clear
  7169. @return {Ember.Array} An empty Array.
  7170. */
  7171. clear: function () {
  7172. var len = get(this, 'length');
  7173. if (len === 0) return this;
  7174. this.replace(0, len, EMPTY);
  7175. return this;
  7176. },
  7177. /**
  7178. This will use the primitive `replace()` method to insert an object at the
  7179. specified index.
  7180. ```javascript
  7181. var colors = ["red", "green", "blue"];
  7182. colors.insertAt(2, "yellow"); // ["red", "green", "yellow", "blue"]
  7183. colors.insertAt(5, "orange"); // Error: Index out of range
  7184. ```
  7185. @method insertAt
  7186. @param {Number} idx index of insert the object at.
  7187. @param {Object} object object to insert
  7188. */
  7189. insertAt: function(idx, object) {
  7190. if (idx > get(this, 'length')) throw new Error(OUT_OF_RANGE_EXCEPTION) ;
  7191. this.replace(idx, 0, [object]) ;
  7192. return this ;
  7193. },
  7194. /**
  7195. Remove an object at the specified index using the `replace()` primitive
  7196. method. You can pass either a single index, or a start and a length.
  7197. If you pass a start and length that is beyond the
  7198. length this method will throw an `Ember.OUT_OF_RANGE_EXCEPTION`
  7199. ```javascript
  7200. var colors = ["red", "green", "blue", "yellow", "orange"];
  7201. colors.removeAt(0); // ["green", "blue", "yellow", "orange"]
  7202. colors.removeAt(2, 2); // ["green", "blue"]
  7203. colors.removeAt(4, 2); // Error: Index out of range
  7204. ```
  7205. @method removeAt
  7206. @param {Number} start index, start of range
  7207. @param {Number} len length of passing range
  7208. @return {Object} receiver
  7209. */
  7210. removeAt: function(start, len) {
  7211. if ('number' === typeof start) {
  7212. if ((start < 0) || (start >= get(this, 'length'))) {
  7213. throw new Error(OUT_OF_RANGE_EXCEPTION);
  7214. }
  7215. // fast case
  7216. if (len === undefined) len = 1;
  7217. this.replace(start, len, EMPTY);
  7218. }
  7219. return this ;
  7220. },
  7221. /**
  7222. Push the object onto the end of the array. Works just like `push()` but it
  7223. is KVO-compliant.
  7224. ```javascript
  7225. var colors = ["red", "green", "blue"];
  7226. colors.pushObject("black"); // ["red", "green", "blue", "black"]
  7227. colors.pushObject(["yellow", "orange"]); // ["red", "green", "blue", "black", ["yellow", "orange"]]
  7228. ```
  7229. @method pushObject
  7230. @param {anything} obj object to push
  7231. */
  7232. pushObject: function(obj) {
  7233. this.insertAt(get(this, 'length'), obj) ;
  7234. return obj ;
  7235. },
  7236. /**
  7237. Add the objects in the passed numerable to the end of the array. Defers
  7238. notifying observers of the change until all objects are added.
  7239. ```javascript
  7240. var colors = ["red", "green", "blue"];
  7241. colors.pushObjects("black"); // ["red", "green", "blue", "black"]
  7242. colors.pushObjects(["yellow", "orange"]); // ["red", "green", "blue", "black", "yellow", "orange"]
  7243. ```
  7244. @method pushObjects
  7245. @param {Ember.Enumerable} objects the objects to add
  7246. @return {Ember.Array} receiver
  7247. */
  7248. pushObjects: function(objects) {
  7249. this.replace(get(this, 'length'), 0, objects);
  7250. return this;
  7251. },
  7252. /**
  7253. Pop object from array or nil if none are left. Works just like `pop()` but
  7254. it is KVO-compliant.
  7255. ```javascript
  7256. var colors = ["red", "green", "blue"];
  7257. colors.popObject(); // "blue"
  7258. console.log(colors); // ["red", "green"]
  7259. ```
  7260. @method popObject
  7261. @return object
  7262. */
  7263. popObject: function() {
  7264. var len = get(this, 'length') ;
  7265. if (len === 0) return null ;
  7266. var ret = this.objectAt(len-1) ;
  7267. this.removeAt(len-1, 1) ;
  7268. return ret ;
  7269. },
  7270. /**
  7271. Shift an object from start of array or nil if none are left. Works just
  7272. like `shift()` but it is KVO-compliant.
  7273. ```javascript
  7274. var colors = ["red", "green", "blue"];
  7275. colors.shiftObject(); // "red"
  7276. console.log(colors); // ["green", "blue"]
  7277. ```
  7278. @method shiftObject
  7279. @return object
  7280. */
  7281. shiftObject: function() {
  7282. if (get(this, 'length') === 0) return null ;
  7283. var ret = this.objectAt(0) ;
  7284. this.removeAt(0) ;
  7285. return ret ;
  7286. },
  7287. /**
  7288. Unshift an object to start of array. Works just like `unshift()` but it is
  7289. KVO-compliant.
  7290. ```javascript
  7291. var colors = ["red", "green", "blue"];
  7292. colors.unshiftObject("yellow"); // ["yellow", "red", "green", "blue"]
  7293. colors.unshiftObject(["black", "white"]); // [["black", "white"], "yellow", "red", "green", "blue"]
  7294. ```
  7295. @method unshiftObject
  7296. @param {anything} obj object to unshift
  7297. */
  7298. unshiftObject: function(obj) {
  7299. this.insertAt(0, obj) ;
  7300. return obj ;
  7301. },
  7302. /**
  7303. Adds the named objects to the beginning of the array. Defers notifying
  7304. observers until all objects have been added.
  7305. ```javascript
  7306. var colors = ["red", "green", "blue"];
  7307. colors.unshiftObjects(["black", "white"]); // ["black", "white", "red", "green", "blue"]
  7308. colors.unshiftObjects("yellow"); // Type Error: 'undefined' is not a function
  7309. ```
  7310. @method unshiftObjects
  7311. @param {Ember.Enumerable} objects the objects to add
  7312. @return {Ember.Array} receiver
  7313. */
  7314. unshiftObjects: function(objects) {
  7315. this.replace(0, 0, objects);
  7316. return this;
  7317. },
  7318. /**
  7319. Reverse objects in the array. Works just like `reverse()` but it is
  7320. KVO-compliant.
  7321. @method reverseObjects
  7322. @return {Ember.Array} receiver
  7323. */
  7324. reverseObjects: function() {
  7325. var len = get(this, 'length');
  7326. if (len === 0) return this;
  7327. var objects = this.toArray().reverse();
  7328. this.replace(0, len, objects);
  7329. return this;
  7330. },
  7331. /**
  7332. Replace all the the receiver's content with content of the argument.
  7333. If argument is an empty array receiver will be cleared.
  7334. ```javascript
  7335. var colors = ["red", "green", "blue"];
  7336. colors.setObjects(["black", "white"]); // ["black", "white"]
  7337. colors.setObjects([]); // []
  7338. ```
  7339. @method setObjects
  7340. @param {Ember.Array} objects array whose content will be used for replacing
  7341. the content of the receiver
  7342. @return {Ember.Array} receiver with the new content
  7343. */
  7344. setObjects: function(objects) {
  7345. if (objects.length === 0) return this.clear();
  7346. var len = get(this, 'length');
  7347. this.replace(0, len, objects);
  7348. return this;
  7349. },
  7350. // ..........................................................
  7351. // IMPLEMENT Ember.MutableEnumerable
  7352. //
  7353. removeObject: function(obj) {
  7354. var loc = get(this, 'length') || 0;
  7355. while(--loc >= 0) {
  7356. var curObject = this.objectAt(loc) ;
  7357. if (curObject === obj) this.removeAt(loc) ;
  7358. }
  7359. return this ;
  7360. },
  7361. addObject: function(obj) {
  7362. if (!this.contains(obj)) this.pushObject(obj);
  7363. return this ;
  7364. }
  7365. });
  7366. })();
  7367. (function() {
  7368. /**
  7369. @module ember
  7370. @submodule ember-runtime
  7371. */
  7372. var get = Ember.get, set = Ember.set, defineProperty = Ember.defineProperty;
  7373. /**
  7374. ## Overview
  7375. This mixin provides properties and property observing functionality, core
  7376. features of the Ember object model.
  7377. Properties and observers allow one object to observe changes to a
  7378. property on another object. This is one of the fundamental ways that
  7379. models, controllers and views communicate with each other in an Ember
  7380. application.
  7381. Any object that has this mixin applied can be used in observer
  7382. operations. That includes `Ember.Object` and most objects you will
  7383. interact with as you write your Ember application.
  7384. Note that you will not generally apply this mixin to classes yourself,
  7385. but you will use the features provided by this module frequently, so it
  7386. is important to understand how to use it.
  7387. ## Using `get()` and `set()`
  7388. Because of Ember's support for bindings and observers, you will always
  7389. access properties using the get method, and set properties using the
  7390. set method. This allows the observing objects to be notified and
  7391. computed properties to be handled properly.
  7392. More documentation about `get` and `set` are below.
  7393. ## Observing Property Changes
  7394. You typically observe property changes simply by adding the `observes`
  7395. call to the end of your method declarations in classes that you write.
  7396. For example:
  7397. ```javascript
  7398. Ember.Object.create({
  7399. valueObserver: function() {
  7400. // Executes whenever the "value" property changes
  7401. }.observes('value')
  7402. });
  7403. ```
  7404. Although this is the most common way to add an observer, this capability
  7405. is actually built into the `Ember.Object` class on top of two methods
  7406. defined in this mixin: `addObserver` and `removeObserver`. You can use
  7407. these two methods to add and remove observers yourself if you need to
  7408. do so at runtime.
  7409. To add an observer for a property, call:
  7410. ```javascript
  7411. object.addObserver('propertyKey', targetObject, targetAction)
  7412. ```
  7413. This will call the `targetAction` method on the `targetObject` to be called
  7414. whenever the value of the `propertyKey` changes.
  7415. Note that if `propertyKey` is a computed property, the observer will be
  7416. called when any of the property dependencies are changed, even if the
  7417. resulting value of the computed property is unchanged. This is necessary
  7418. because computed properties are not computed until `get` is called.
  7419. @class Observable
  7420. @namespace Ember
  7421. @extends Ember.Mixin
  7422. */
  7423. Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
  7424. /**
  7425. Retrieves the value of a property from the object.
  7426. This method is usually similar to using `object[keyName]` or `object.keyName`,
  7427. however it supports both computed properties and the unknownProperty
  7428. handler.
  7429. Because `get` unifies the syntax for accessing all these kinds
  7430. of properties, it can make many refactorings easier, such as replacing a
  7431. simple property with a computed property, or vice versa.
  7432. ### Computed Properties
  7433. Computed properties are methods defined with the `property` modifier
  7434. declared at the end, such as:
  7435. ```javascript
  7436. fullName: function() {
  7437. return this.getEach('firstName', 'lastName').compact().join(' ');
  7438. }.property('firstName', 'lastName')
  7439. ```
  7440. When you call `get` on a computed property, the function will be
  7441. called and the return value will be returned instead of the function
  7442. itself.
  7443. ### Unknown Properties
  7444. Likewise, if you try to call `get` on a property whose value is
  7445. `undefined`, the `unknownProperty()` method will be called on the object.
  7446. If this method returns any value other than `undefined`, it will be returned
  7447. instead. This allows you to implement "virtual" properties that are
  7448. not defined upfront.
  7449. @method get
  7450. @param {String} key The property to retrieve
  7451. @return {Object} The property value or undefined.
  7452. */
  7453. get: function(keyName) {
  7454. return get(this, keyName);
  7455. },
  7456. /**
  7457. To get multiple properties at once, call `getProperties`
  7458. with a list of strings or an array:
  7459. ```javascript
  7460. record.getProperties('firstName', 'lastName', 'zipCode'); // { firstName: 'John', lastName: 'Doe', zipCode: '10011' }
  7461. ```
  7462. is equivalent to:
  7463. ```javascript
  7464. record.getProperties(['firstName', 'lastName', 'zipCode']); // { firstName: 'John', lastName: 'Doe', zipCode: '10011' }
  7465. ```
  7466. @method getProperties
  7467. @param {String...|Array} list of keys to get
  7468. @return {Hash}
  7469. */
  7470. getProperties: function() {
  7471. var ret = {};
  7472. var propertyNames = arguments;
  7473. if (arguments.length === 1 && Ember.typeOf(arguments[0]) === 'array') {
  7474. propertyNames = arguments[0];
  7475. }
  7476. for(var i = 0; i < propertyNames.length; i++) {
  7477. ret[propertyNames[i]] = get(this, propertyNames[i]);
  7478. }
  7479. return ret;
  7480. },
  7481. /**
  7482. Sets the provided key or path to the value.
  7483. This method is generally very similar to calling `object[key] = value` or
  7484. `object.key = value`, except that it provides support for computed
  7485. properties, the `unknownProperty()` method and property observers.
  7486. ### Computed Properties
  7487. If you try to set a value on a key that has a computed property handler
  7488. defined (see the `get()` method for an example), then `set()` will call
  7489. that method, passing both the value and key instead of simply changing
  7490. the value itself. This is useful for those times when you need to
  7491. implement a property that is composed of one or more member
  7492. properties.
  7493. ### Unknown Properties
  7494. If you try to set a value on a key that is undefined in the target
  7495. object, then the `unknownProperty()` handler will be called instead. This
  7496. gives you an opportunity to implement complex "virtual" properties that
  7497. are not predefined on the object. If `unknownProperty()` returns
  7498. undefined, then `set()` will simply set the value on the object.
  7499. ### Property Observers
  7500. In addition to changing the property, `set()` will also register a property
  7501. change with the object. Unless you have placed this call inside of a
  7502. `beginPropertyChanges()` and `endPropertyChanges(),` any "local" observers
  7503. (i.e. observer methods declared on the same object), will be called
  7504. immediately. Any "remote" observers (i.e. observer methods declared on
  7505. another object) will be placed in a queue and called at a later time in a
  7506. coalesced manner.
  7507. ### Chaining
  7508. In addition to property changes, `set()` returns the value of the object
  7509. itself so you can do chaining like this:
  7510. ```javascript
  7511. record.set('firstName', 'Charles').set('lastName', 'Jolley');
  7512. ```
  7513. @method set
  7514. @param {String} key The property to set
  7515. @param {Object} value The value to set or `null`.
  7516. @return {Ember.Observable}
  7517. */
  7518. set: function(keyName, value) {
  7519. set(this, keyName, value);
  7520. return this;
  7521. },
  7522. /**
  7523. To set multiple properties at once, call `setProperties`
  7524. with a Hash:
  7525. ```javascript
  7526. record.setProperties({ firstName: 'Charles', lastName: 'Jolley' });
  7527. ```
  7528. @method setProperties
  7529. @param {Hash} hash the hash of keys and values to set
  7530. @return {Ember.Observable}
  7531. */
  7532. setProperties: function(hash) {
  7533. return Ember.setProperties(this, hash);
  7534. },
  7535. /**
  7536. Begins a grouping of property changes.
  7537. You can use this method to group property changes so that notifications
  7538. will not be sent until the changes are finished. If you plan to make a
  7539. large number of changes to an object at one time, you should call this
  7540. method at the beginning of the changes to begin deferring change
  7541. notifications. When you are done making changes, call
  7542. `endPropertyChanges()` to deliver the deferred change notifications and end
  7543. deferring.
  7544. @method beginPropertyChanges
  7545. @return {Ember.Observable}
  7546. */
  7547. beginPropertyChanges: function() {
  7548. Ember.beginPropertyChanges();
  7549. return this;
  7550. },
  7551. /**
  7552. Ends a grouping of property changes.
  7553. You can use this method to group property changes so that notifications
  7554. will not be sent until the changes are finished. If you plan to make a
  7555. large number of changes to an object at one time, you should call
  7556. `beginPropertyChanges()` at the beginning of the changes to defer change
  7557. notifications. When you are done making changes, call this method to
  7558. deliver the deferred change notifications and end deferring.
  7559. @method endPropertyChanges
  7560. @return {Ember.Observable}
  7561. */
  7562. endPropertyChanges: function() {
  7563. Ember.endPropertyChanges();
  7564. return this;
  7565. },
  7566. /**
  7567. Notify the observer system that a property is about to change.
  7568. Sometimes you need to change a value directly or indirectly without
  7569. actually calling `get()` or `set()` on it. In this case, you can use this
  7570. method and `propertyDidChange()` instead. Calling these two methods
  7571. together will notify all observers that the property has potentially
  7572. changed value.
  7573. Note that you must always call `propertyWillChange` and `propertyDidChange`
  7574. as a pair. If you do not, it may get the property change groups out of
  7575. order and cause notifications to be delivered more often than you would
  7576. like.
  7577. @method propertyWillChange
  7578. @param {String} key The property key that is about to change.
  7579. @return {Ember.Observable}
  7580. */
  7581. propertyWillChange: function(keyName){
  7582. Ember.propertyWillChange(this, keyName);
  7583. return this;
  7584. },
  7585. /**
  7586. Notify the observer system that a property has just changed.
  7587. Sometimes you need to change a value directly or indirectly without
  7588. actually calling `get()` or `set()` on it. In this case, you can use this
  7589. method and `propertyWillChange()` instead. Calling these two methods
  7590. together will notify all observers that the property has potentially
  7591. changed value.
  7592. Note that you must always call `propertyWillChange` and `propertyDidChange`
  7593. as a pair. If you do not, it may get the property change groups out of
  7594. order and cause notifications to be delivered more often than you would
  7595. like.
  7596. @method propertyDidChange
  7597. @param {String} keyName The property key that has just changed.
  7598. @return {Ember.Observable}
  7599. */
  7600. propertyDidChange: function(keyName) {
  7601. Ember.propertyDidChange(this, keyName);
  7602. return this;
  7603. },
  7604. /**
  7605. Convenience method to call `propertyWillChange` and `propertyDidChange` in
  7606. succession.
  7607. @method notifyPropertyChange
  7608. @param {String} keyName The property key to be notified about.
  7609. @return {Ember.Observable}
  7610. */
  7611. notifyPropertyChange: function(keyName) {
  7612. this.propertyWillChange(keyName);
  7613. this.propertyDidChange(keyName);
  7614. return this;
  7615. },
  7616. addBeforeObserver: function(key, target, method) {
  7617. Ember.addBeforeObserver(this, key, target, method);
  7618. },
  7619. /**
  7620. Adds an observer on a property.
  7621. This is the core method used to register an observer for a property.
  7622. Once you call this method, anytime the key's value is set, your observer
  7623. will be notified. Note that the observers are triggered anytime the
  7624. value is set, regardless of whether it has actually changed. Your
  7625. observer should be prepared to handle that.
  7626. You can also pass an optional context parameter to this method. The
  7627. context will be passed to your observer method whenever it is triggered.
  7628. Note that if you add the same target/method pair on a key multiple times
  7629. with different context parameters, your observer will only be called once
  7630. with the last context you passed.
  7631. ### Observer Methods
  7632. Observer methods you pass should generally have the following signature if
  7633. you do not pass a `context` parameter:
  7634. ```javascript
  7635. fooDidChange: function(sender, key, value, rev) { };
  7636. ```
  7637. The sender is the object that changed. The key is the property that
  7638. changes. The value property is currently reserved and unused. The rev
  7639. is the last property revision of the object when it changed, which you can
  7640. use to detect if the key value has really changed or not.
  7641. If you pass a `context` parameter, the context will be passed before the
  7642. revision like so:
  7643. ```javascript
  7644. fooDidChange: function(sender, key, value, context, rev) { };
  7645. ```
  7646. Usually you will not need the value, context or revision parameters at
  7647. the end. In this case, it is common to write observer methods that take
  7648. only a sender and key value as parameters or, if you aren't interested in
  7649. any of these values, to write an observer that has no parameters at all.
  7650. @method addObserver
  7651. @param {String} key The key to observer
  7652. @param {Object} target The target object to invoke
  7653. @param {String|Function} method The method to invoke.
  7654. @return {Ember.Object} self
  7655. */
  7656. addObserver: function(key, target, method) {
  7657. Ember.addObserver(this, key, target, method);
  7658. },
  7659. /**
  7660. Remove an observer you have previously registered on this object. Pass
  7661. the same key, target, and method you passed to `addObserver()` and your
  7662. target will no longer receive notifications.
  7663. @method removeObserver
  7664. @param {String} key The key to observer
  7665. @param {Object} target The target object to invoke
  7666. @param {String|Function} method The method to invoke.
  7667. @return {Ember.Observable} receiver
  7668. */
  7669. removeObserver: function(key, target, method) {
  7670. Ember.removeObserver(this, key, target, method);
  7671. },
  7672. /**
  7673. Returns `true` if the object currently has observers registered for a
  7674. particular key. You can use this method to potentially defer performing
  7675. an expensive action until someone begins observing a particular property
  7676. on the object.
  7677. @method hasObserverFor
  7678. @param {String} key Key to check
  7679. @return {Boolean}
  7680. */
  7681. hasObserverFor: function(key) {
  7682. return Ember.hasListeners(this, key+':change');
  7683. },
  7684. /**
  7685. @deprecated
  7686. @method getPath
  7687. @param {String} path The property path to retrieve
  7688. @return {Object} The property value or undefined.
  7689. */
  7690. getPath: function(path) {
  7691. Ember.deprecate("getPath is deprecated since get now supports paths");
  7692. return this.get(path);
  7693. },
  7694. /**
  7695. @deprecated
  7696. @method setPath
  7697. @param {String} path The path to the property that will be set
  7698. @param {Object} value The value to set or `null`.
  7699. @return {Ember.Observable}
  7700. */
  7701. setPath: function(path, value) {
  7702. Ember.deprecate("setPath is deprecated since set now supports paths");
  7703. return this.set(path, value);
  7704. },
  7705. /**
  7706. Retrieves the value of a property, or a default value in the case that the
  7707. property returns `undefined`.
  7708. ```javascript
  7709. person.getWithDefault('lastName', 'Doe');
  7710. ```
  7711. @method getWithDefault
  7712. @param {String} keyName The name of the property to retrieve
  7713. @param {Object} defaultValue The value to return if the property value is undefined
  7714. @return {Object} The property value or the defaultValue.
  7715. */
  7716. getWithDefault: function(keyName, defaultValue) {
  7717. return Ember.getWithDefault(this, keyName, defaultValue);
  7718. },
  7719. /**
  7720. Set the value of a property to the current value plus some amount.
  7721. ```javascript
  7722. person.incrementProperty('age');
  7723. team.incrementProperty('score', 2);
  7724. ```
  7725. @method incrementProperty
  7726. @param {String} keyName The name of the property to increment
  7727. @param {Object} increment The amount to increment by. Defaults to 1
  7728. @return {Object} The new property value
  7729. */
  7730. incrementProperty: function(keyName, increment) {
  7731. if (!increment) { increment = 1; }
  7732. set(this, keyName, (get(this, keyName) || 0)+increment);
  7733. return get(this, keyName);
  7734. },
  7735. /**
  7736. Set the value of a property to the current value minus some amount.
  7737. ```javascript
  7738. player.decrementProperty('lives');
  7739. orc.decrementProperty('health', 5);
  7740. ```
  7741. @method decrementProperty
  7742. @param {String} keyName The name of the property to decrement
  7743. @param {Object} increment The amount to decrement by. Defaults to 1
  7744. @return {Object} The new property value
  7745. */
  7746. decrementProperty: function(keyName, increment) {
  7747. if (!increment) { increment = 1; }
  7748. set(this, keyName, (get(this, keyName) || 0)-increment);
  7749. return get(this, keyName);
  7750. },
  7751. /**
  7752. Set the value of a boolean property to the opposite of it's
  7753. current value.
  7754. ```javascript
  7755. starship.toggleProperty('warpDriveEnaged');
  7756. ```
  7757. @method toggleProperty
  7758. @param {String} keyName The name of the property to toggle
  7759. @return {Object} The new property value
  7760. */
  7761. toggleProperty: function(keyName) {
  7762. set(this, keyName, !get(this, keyName));
  7763. return get(this, keyName);
  7764. },
  7765. /**
  7766. Returns the cached value of a computed property, if it exists.
  7767. This allows you to inspect the value of a computed property
  7768. without accidentally invoking it if it is intended to be
  7769. generated lazily.
  7770. @method cacheFor
  7771. @param {String} keyName
  7772. @return {Object} The cached value of the computed property, if any
  7773. */
  7774. cacheFor: function(keyName) {
  7775. return Ember.cacheFor(this, keyName);
  7776. },
  7777. // intended for debugging purposes
  7778. observersForKey: function(keyName) {
  7779. return Ember.observersFor(this, keyName);
  7780. }
  7781. });
  7782. })();
  7783. (function() {
  7784. /**
  7785. @module ember
  7786. @submodule ember-runtime
  7787. */
  7788. var get = Ember.get, set = Ember.set;
  7789. /**
  7790. @class TargetActionSupport
  7791. @namespace Ember
  7792. @extends Ember.Mixin
  7793. */
  7794. Ember.TargetActionSupport = Ember.Mixin.create({
  7795. target: null,
  7796. action: null,
  7797. targetObject: Ember.computed(function() {
  7798. var target = get(this, 'target');
  7799. if (Ember.typeOf(target) === "string") {
  7800. var value = get(this, target);
  7801. if (value === undefined) { value = get(Ember.lookup, target); }
  7802. return value;
  7803. } else {
  7804. return target;
  7805. }
  7806. }).property('target'),
  7807. triggerAction: function() {
  7808. var action = get(this, 'action'),
  7809. target = get(this, 'targetObject');
  7810. if (target && action) {
  7811. var ret;
  7812. if (typeof target.send === 'function') {
  7813. ret = target.send(action, this);
  7814. } else {
  7815. if (typeof action === 'string') {
  7816. action = target[action];
  7817. }
  7818. ret = action.call(target, this);
  7819. }
  7820. if (ret !== false) ret = true;
  7821. return ret;
  7822. } else {
  7823. return false;
  7824. }
  7825. }
  7826. });
  7827. })();
  7828. (function() {
  7829. /**
  7830. @module ember
  7831. @submodule ember-runtime
  7832. */
  7833. /**
  7834. This mixin allows for Ember objects to subscribe to and emit events.
  7835. ```javascript
  7836. App.Person = Ember.Object.extend(Ember.Evented, {
  7837. greet: function() {
  7838. // ...
  7839. this.trigger('greet');
  7840. }
  7841. });
  7842. var person = App.Person.create();
  7843. person.on('greet', function() {
  7844. console.log('Our person has greeted');
  7845. });
  7846. person.greet();
  7847. // outputs: 'Our person has greeted'
  7848. ```
  7849. @class Evented
  7850. @namespace Ember
  7851. @extends Ember.Mixin
  7852. */
  7853. Ember.Evented = Ember.Mixin.create({
  7854. /**
  7855. Subscribes to a named event with given function.
  7856. ```javascript
  7857. person.on('didLoad', function() {
  7858. // fired once the person has loaded
  7859. });
  7860. ```
  7861. An optional target can be passed in as the 2nd argument that will
  7862. be set as the "this" for the callback. This is a good way to give your
  7863. function access to the object triggering the event. When the target
  7864. parameter is used the callback becomes the third argument.
  7865. @method on
  7866. @param {String} name The name of the event
  7867. @param {Object} [target] The "this" binding for the callback
  7868. @param {Function} method The callback to execute
  7869. */
  7870. on: function(name, target, method) {
  7871. Ember.addListener(this, name, target, method);
  7872. },
  7873. /**
  7874. Subscribes a function to a named event and then cancels the subscription
  7875. after the first time the event is triggered. It is good to use ``one`` when
  7876. you only care about the first time an event has taken place.
  7877. This function takes an optional 2nd argument that will become the "this"
  7878. value for the callback. If this argument is passed then the 3rd argument
  7879. becomes the function.
  7880. @method one
  7881. @param {String} name The name of the event
  7882. @param {Object} [target] The "this" binding for the callback
  7883. @param {Function} method The callback to execute
  7884. */
  7885. one: function(name, target, method) {
  7886. if (!method) {
  7887. method = target;
  7888. target = null;
  7889. }
  7890. Ember.addListener(this, name, target, method, true);
  7891. },
  7892. /**
  7893. Triggers a named event for the object. Any additional arguments
  7894. will be passed as parameters to the functions that are subscribed to the
  7895. event.
  7896. ```javascript
  7897. person.on('didEat', function(food) {
  7898. console.log('person ate some ' + food);
  7899. });
  7900. person.trigger('didEat', 'broccoli');
  7901. // outputs: person ate some broccoli
  7902. ```
  7903. @method trigger
  7904. @param {String} name The name of the event
  7905. @param {Object...} args Optional arguments to pass on
  7906. */
  7907. trigger: function(name) {
  7908. var args = [], i, l;
  7909. for (i = 1, l = arguments.length; i < l; i++) {
  7910. args.push(arguments[i]);
  7911. }
  7912. Ember.sendEvent(this, name, args);
  7913. },
  7914. fire: function(name) {
  7915. Ember.deprecate("Ember.Evented#fire() has been deprecated in favor of trigger() for compatibility with jQuery. It will be removed in 1.0. Please update your code to call trigger() instead.");
  7916. this.trigger.apply(this, arguments);
  7917. },
  7918. /**
  7919. Cancels subscription for give name, target, and method.
  7920. @method off
  7921. @param {String} name The name of the event
  7922. @param {Object} target The target of the subscription
  7923. @param {Function} method The function of the subscription
  7924. */
  7925. off: function(name, target, method) {
  7926. Ember.removeListener(this, name, target, method);
  7927. },
  7928. /**
  7929. Checks to see if object has any subscriptions for named event.
  7930. @method has
  7931. @param {String} name The name of the event
  7932. @return {Boolean} does the object have a subscription for event
  7933. */
  7934. has: function(name) {
  7935. return Ember.hasListeners(this, name);
  7936. }
  7937. });
  7938. })();
  7939. (function() {
  7940. var RSVP = requireModule("rsvp");
  7941. RSVP.async = function(callback, binding) {
  7942. Ember.run.schedule('actions', binding, callback);
  7943. };
  7944. /**
  7945. @module ember
  7946. @submodule ember-runtime
  7947. */
  7948. var get = Ember.get,
  7949. slice = Array.prototype.slice;
  7950. /**
  7951. @class Deferred
  7952. @namespace Ember
  7953. @extends Ember.Mixin
  7954. */
  7955. Ember.DeferredMixin = Ember.Mixin.create({
  7956. /**
  7957. Add handlers to be called when the Deferred object is resolved or rejected.
  7958. @method then
  7959. @param {Function} doneCallback a callback function to be called when done
  7960. @param {Function} failCallback a callback function to be called when failed
  7961. */
  7962. then: function(doneCallback, failCallback) {
  7963. var promise = get(this, 'promise');
  7964. return promise.then.apply(promise, arguments);
  7965. },
  7966. /**
  7967. Resolve a Deferred object and call any `doneCallbacks` with the given args.
  7968. @method resolve
  7969. */
  7970. resolve: function(value) {
  7971. get(this, 'promise').resolve(value);
  7972. },
  7973. /**
  7974. Reject a Deferred object and call any `failCallbacks` with the given args.
  7975. @method reject
  7976. */
  7977. reject: function(value) {
  7978. get(this, 'promise').reject(value);
  7979. },
  7980. promise: Ember.computed(function() {
  7981. return new RSVP.Promise();
  7982. })
  7983. });
  7984. })();
  7985. (function() {
  7986. })();
  7987. (function() {
  7988. Ember.Container = requireModule('container');
  7989. Ember.Container.set = Ember.set;
  7990. })();
  7991. (function() {
  7992. /**
  7993. @module ember
  7994. @submodule ember-runtime
  7995. */
  7996. // NOTE: this object should never be included directly. Instead use Ember.
  7997. // Ember.Object. We only define this separately so that Ember.Set can depend on it
  7998. var set = Ember.set, get = Ember.get,
  7999. o_create = Ember.create,
  8000. o_defineProperty = Ember.platform.defineProperty,
  8001. a_slice = Array.prototype.slice,
  8002. GUID_KEY = Ember.GUID_KEY,
  8003. guidFor = Ember.guidFor,
  8004. generateGuid = Ember.generateGuid,
  8005. meta = Ember.meta,
  8006. rewatch = Ember.rewatch,
  8007. finishChains = Ember.finishChains,
  8008. destroy = Ember.destroy,
  8009. schedule = Ember.run.schedule,
  8010. Mixin = Ember.Mixin,
  8011. applyMixin = Mixin._apply,
  8012. finishPartial = Mixin.finishPartial,
  8013. reopen = Mixin.prototype.reopen,
  8014. MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER,
  8015. indexOf = Ember.EnumerableUtils.indexOf;
  8016. var undefinedDescriptor = {
  8017. configurable: true,
  8018. writable: true,
  8019. enumerable: false,
  8020. value: undefined
  8021. };
  8022. function makeCtor() {
  8023. // Note: avoid accessing any properties on the object since it makes the
  8024. // method a lot faster. This is glue code so we want it to be as fast as
  8025. // possible.
  8026. var wasApplied = false, initMixins, initProperties;
  8027. var Class = function() {
  8028. if (!wasApplied) {
  8029. Class.proto(); // prepare prototype...
  8030. }
  8031. o_defineProperty(this, GUID_KEY, undefinedDescriptor);
  8032. o_defineProperty(this, '_super', undefinedDescriptor);
  8033. var m = meta(this);
  8034. m.proto = this;
  8035. if (initMixins) {
  8036. // capture locally so we can clear the closed over variable
  8037. var mixins = initMixins;
  8038. initMixins = null;
  8039. this.reopen.apply(this, mixins);
  8040. }
  8041. if (initProperties) {
  8042. // capture locally so we can clear the closed over variable
  8043. var props = initProperties;
  8044. initProperties = null;
  8045. var concatenatedProperties = this.concatenatedProperties;
  8046. for (var i = 0, l = props.length; i < l; i++) {
  8047. var properties = props[i];
  8048. for (var keyName in properties) {
  8049. if (!properties.hasOwnProperty(keyName)) { continue; }
  8050. var value = properties[keyName],
  8051. IS_BINDING = Ember.IS_BINDING;
  8052. if (IS_BINDING.test(keyName)) {
  8053. var bindings = m.bindings;
  8054. if (!bindings) {
  8055. bindings = m.bindings = {};
  8056. } else if (!m.hasOwnProperty('bindings')) {
  8057. bindings = m.bindings = o_create(m.bindings);
  8058. }
  8059. bindings[keyName] = value;
  8060. }
  8061. var desc = m.descs[keyName];
  8062. Ember.assert("Ember.Object.create no longer supports defining computed properties.", !(value instanceof Ember.ComputedProperty));
  8063. Ember.assert("Ember.Object.create no longer supports defining methods that call _super.", !(typeof value === 'function' && value.toString().indexOf('._super') !== -1));
  8064. if (concatenatedProperties && indexOf(concatenatedProperties, keyName) >= 0) {
  8065. var baseValue = this[keyName];
  8066. if (baseValue) {
  8067. if ('function' === typeof baseValue.concat) {
  8068. value = baseValue.concat(value);
  8069. } else {
  8070. value = Ember.makeArray(baseValue).concat(value);
  8071. }
  8072. } else {
  8073. value = Ember.makeArray(value);
  8074. }
  8075. }
  8076. if (desc) {
  8077. desc.set(this, keyName, value);
  8078. } else {
  8079. if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) {
  8080. this.setUnknownProperty(keyName, value);
  8081. } else if (MANDATORY_SETTER) {
  8082. Ember.defineProperty(this, keyName, null, value); // setup mandatory setter
  8083. } else {
  8084. this[keyName] = value;
  8085. }
  8086. }
  8087. }
  8088. }
  8089. }
  8090. finishPartial(this, m);
  8091. delete m.proto;
  8092. finishChains(this);
  8093. this.init.apply(this, arguments);
  8094. };
  8095. Class.toString = Mixin.prototype.toString;
  8096. Class.willReopen = function() {
  8097. if (wasApplied) {
  8098. Class.PrototypeMixin = Mixin.create(Class.PrototypeMixin);
  8099. }
  8100. wasApplied = false;
  8101. };
  8102. Class._initMixins = function(args) { initMixins = args; };
  8103. Class._initProperties = function(args) { initProperties = args; };
  8104. Class.proto = function() {
  8105. var superclass = Class.superclass;
  8106. if (superclass) { superclass.proto(); }
  8107. if (!wasApplied) {
  8108. wasApplied = true;
  8109. Class.PrototypeMixin.applyPartial(Class.prototype);
  8110. rewatch(Class.prototype);
  8111. }
  8112. return this.prototype;
  8113. };
  8114. return Class;
  8115. }
  8116. var CoreObject = makeCtor();
  8117. CoreObject.toString = function() { return "Ember.CoreObject"; };
  8118. CoreObject.PrototypeMixin = Mixin.create({
  8119. reopen: function() {
  8120. applyMixin(this, arguments, true);
  8121. return this;
  8122. },
  8123. isInstance: true,
  8124. init: function() {},
  8125. /**
  8126. Defines the properties that will be concatenated from the superclass
  8127. (instead of overridden).
  8128. By default, when you extend an Ember class a property defined in
  8129. the subclass overrides a property with the same name that is defined
  8130. in the superclass. However, there are some cases where it is preferable
  8131. to build up a property's value by combining the superclass' property
  8132. value with the subclass' value. An example of this in use within Ember
  8133. is the `classNames` property of `Ember.View`.
  8134. Here is some sample code showing the difference between a concatenated
  8135. property and a normal one:
  8136. ```javascript
  8137. App.BarView = Ember.View.extend({
  8138. someNonConcatenatedProperty: ['bar'],
  8139. classNames: ['bar']
  8140. });
  8141. App.FooBarView = App.BarView.extend({
  8142. someNonConcatenatedProperty: ['foo'],
  8143. classNames: ['foo'],
  8144. });
  8145. var fooBarView = App.FooBarView.create();
  8146. fooBarView.get('someNonConcatenatedProperty'); // ['foo']
  8147. fooBarView.get('classNames'); // ['ember-view', 'bar', 'foo']
  8148. ```
  8149. This behavior extends to object creation as well. Continuing the
  8150. above example:
  8151. ```javascript
  8152. var view = App.FooBarView.create({
  8153. someNonConcatenatedProperty: ['baz'],
  8154. classNames: ['baz']
  8155. })
  8156. view.get('someNonConcatenatedProperty'); // ['baz']
  8157. view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
  8158. ```
  8159. Adding a single property that is not an array will just add it in the array:
  8160. ```javascript
  8161. var view = App.FooBarView.create({
  8162. classNames: 'baz'
  8163. })
  8164. view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
  8165. ```
  8166. Using the `concatenatedProperties` property, we can tell to Ember that mix
  8167. the content of the properties.
  8168. In `Ember.View` the `classNameBindings` and `attributeBindings` properties
  8169. are also concatenated, in addition to `classNames`.
  8170. This feature is available for you to use throughout the Ember object model,
  8171. although typical app developers are likely to use it infrequently.
  8172. @property concatenatedProperties
  8173. @type Array
  8174. @default null
  8175. */
  8176. concatenatedProperties: null,
  8177. /**
  8178. @property isDestroyed
  8179. @default false
  8180. */
  8181. isDestroyed: false,
  8182. /**
  8183. @property isDestroying
  8184. @default false
  8185. */
  8186. isDestroying: false,
  8187. /**
  8188. Destroys an object by setting the `isDestroyed` flag and removing its
  8189. metadata, which effectively destroys observers and bindings.
  8190. If you try to set a property on a destroyed object, an exception will be
  8191. raised.
  8192. Note that destruction is scheduled for the end of the run loop and does not
  8193. happen immediately.
  8194. @method destroy
  8195. @return {Ember.Object} receiver
  8196. */
  8197. destroy: function() {
  8198. if (this._didCallDestroy) { return; }
  8199. this.isDestroying = true;
  8200. this._didCallDestroy = true;
  8201. if (this.willDestroy) { this.willDestroy(); }
  8202. schedule('destroy', this, this._scheduledDestroy);
  8203. return this;
  8204. },
  8205. /**
  8206. @private
  8207. Invoked by the run loop to actually destroy the object. This is
  8208. scheduled for execution by the `destroy` method.
  8209. @method _scheduledDestroy
  8210. */
  8211. _scheduledDestroy: function() {
  8212. destroy(this);
  8213. set(this, 'isDestroyed', true);
  8214. if (this.didDestroy) { this.didDestroy(); }
  8215. },
  8216. bind: function(to, from) {
  8217. if (!(from instanceof Ember.Binding)) { from = Ember.Binding.from(from); }
  8218. from.to(to).connect(this);
  8219. return from;
  8220. },
  8221. /**
  8222. Returns a string representation which attempts to provide more information
  8223. than Javascript's `toString` typically does, in a generic way for all Ember
  8224. objects.
  8225. App.Person = Em.Object.extend()
  8226. person = App.Person.create()
  8227. person.toString() //=> "<App.Person:ember1024>"
  8228. If the object's class is not defined on an Ember namespace, it will
  8229. indicate it is a subclass of the registered superclass:
  8230. Student = App.Person.extend()
  8231. student = Student.create()
  8232. student.toString() //=> "<(subclass of App.Person):ember1025>"
  8233. If the method `toStringExtension` is defined, its return value will be
  8234. included in the output.
  8235. App.Teacher = App.Person.extend({
  8236. toStringExtension: function(){
  8237. return this.get('fullName');
  8238. }
  8239. });
  8240. teacher = App.Teacher.create()
  8241. teacher.toString(); // #=> "<App.Teacher:ember1026:Tom Dale>"
  8242. @method toString
  8243. @return {String} string representation
  8244. */
  8245. toString: function toString() {
  8246. var hasToStringExtension = typeof this.toStringExtension === 'function',
  8247. extension = hasToStringExtension ? ":" + this.toStringExtension() : '';
  8248. var ret = '<'+this.constructor.toString()+':'+guidFor(this)+extension+'>';
  8249. this.toString = makeToString(ret);
  8250. return ret;
  8251. }
  8252. });
  8253. CoreObject.PrototypeMixin.ownerConstructor = CoreObject;
  8254. function makeToString(ret) {
  8255. return function() { return ret; };
  8256. }
  8257. if (Ember.config.overridePrototypeMixin) {
  8258. Ember.config.overridePrototypeMixin(CoreObject.PrototypeMixin);
  8259. }
  8260. CoreObject.__super__ = null;
  8261. var ClassMixin = Mixin.create({
  8262. ClassMixin: Ember.required(),
  8263. PrototypeMixin: Ember.required(),
  8264. isClass: true,
  8265. isMethod: false,
  8266. extend: function() {
  8267. var Class = makeCtor(), proto;
  8268. Class.ClassMixin = Mixin.create(this.ClassMixin);
  8269. Class.PrototypeMixin = Mixin.create(this.PrototypeMixin);
  8270. Class.ClassMixin.ownerConstructor = Class;
  8271. Class.PrototypeMixin.ownerConstructor = Class;
  8272. reopen.apply(Class.PrototypeMixin, arguments);
  8273. Class.superclass = this;
  8274. Class.__super__ = this.prototype;
  8275. proto = Class.prototype = o_create(this.prototype);
  8276. proto.constructor = Class;
  8277. generateGuid(proto, 'ember');
  8278. meta(proto).proto = proto; // this will disable observers on prototype
  8279. Class.ClassMixin.apply(Class);
  8280. return Class;
  8281. },
  8282. createWithMixins: function() {
  8283. var C = this;
  8284. if (arguments.length>0) { this._initMixins(arguments); }
  8285. return new C();
  8286. },
  8287. create: function() {
  8288. var C = this;
  8289. if (arguments.length>0) { this._initProperties(arguments); }
  8290. return new C();
  8291. },
  8292. reopen: function() {
  8293. this.willReopen();
  8294. reopen.apply(this.PrototypeMixin, arguments);
  8295. return this;
  8296. },
  8297. reopenClass: function() {
  8298. reopen.apply(this.ClassMixin, arguments);
  8299. applyMixin(this, arguments, false);
  8300. return this;
  8301. },
  8302. detect: function(obj) {
  8303. if ('function' !== typeof obj) { return false; }
  8304. while(obj) {
  8305. if (obj===this) { return true; }
  8306. obj = obj.superclass;
  8307. }
  8308. return false;
  8309. },
  8310. detectInstance: function(obj) {
  8311. return obj instanceof this;
  8312. },
  8313. /**
  8314. In some cases, you may want to annotate computed properties with additional
  8315. metadata about how they function or what values they operate on. For
  8316. example, computed property functions may close over variables that are then
  8317. no longer available for introspection.
  8318. You can pass a hash of these values to a computed property like this:
  8319. ```javascript
  8320. person: function() {
  8321. var personId = this.get('personId');
  8322. return App.Person.create({ id: personId });
  8323. }.property().meta({ type: App.Person })
  8324. ```
  8325. Once you've done this, you can retrieve the values saved to the computed
  8326. property from your class like this:
  8327. ```javascript
  8328. MyClass.metaForProperty('person');
  8329. ```
  8330. This will return the original hash that was passed to `meta()`.
  8331. @method metaForProperty
  8332. @param key {String} property name
  8333. */
  8334. metaForProperty: function(key) {
  8335. var desc = meta(this.proto(), false).descs[key];
  8336. Ember.assert("metaForProperty() could not find a computed property with key '"+key+"'.", !!desc && desc instanceof Ember.ComputedProperty);
  8337. return desc._meta || {};
  8338. },
  8339. /**
  8340. Iterate over each computed property for the class, passing its name
  8341. and any associated metadata (see `metaForProperty`) to the callback.
  8342. @method eachComputedProperty
  8343. @param {Function} callback
  8344. @param {Object} binding
  8345. */
  8346. eachComputedProperty: function(callback, binding) {
  8347. var proto = this.proto(),
  8348. descs = meta(proto).descs,
  8349. empty = {},
  8350. property;
  8351. for (var name in descs) {
  8352. property = descs[name];
  8353. if (property instanceof Ember.ComputedProperty) {
  8354. callback.call(binding || this, name, property._meta || empty);
  8355. }
  8356. }
  8357. }
  8358. });
  8359. ClassMixin.ownerConstructor = CoreObject;
  8360. if (Ember.config.overrideClassMixin) {
  8361. Ember.config.overrideClassMixin(ClassMixin);
  8362. }
  8363. CoreObject.ClassMixin = ClassMixin;
  8364. ClassMixin.apply(CoreObject);
  8365. /**
  8366. @class CoreObject
  8367. @namespace Ember
  8368. */
  8369. Ember.CoreObject = CoreObject;
  8370. })();
  8371. (function() {
  8372. /**
  8373. @module ember
  8374. @submodule ember-runtime
  8375. */
  8376. var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor, none = Ember.isNone;
  8377. /**
  8378. An unordered collection of objects.
  8379. A Set works a bit like an array except that its items are not ordered. You
  8380. can create a set to efficiently test for membership for an object. You can
  8381. also iterate through a set just like an array, even accessing objects by
  8382. index, however there is no guarantee as to their order.
  8383. All Sets are observable via the Enumerable Observer API - which works
  8384. on any enumerable object including both Sets and Arrays.
  8385. ## Creating a Set
  8386. You can create a set like you would most objects using
  8387. `new Ember.Set()`. Most new sets you create will be empty, but you can
  8388. also initialize the set with some content by passing an array or other
  8389. enumerable of objects to the constructor.
  8390. Finally, you can pass in an existing set and the set will be copied. You
  8391. can also create a copy of a set by calling `Ember.Set#copy()`.
  8392. ```javascript
  8393. // creates a new empty set
  8394. var foundNames = new Ember.Set();
  8395. // creates a set with four names in it.
  8396. var names = new Ember.Set(["Charles", "Tom", "Juan", "Alex"]); // :P
  8397. // creates a copy of the names set.
  8398. var namesCopy = new Ember.Set(names);
  8399. // same as above.
  8400. var anotherNamesCopy = names.copy();
  8401. ```
  8402. ## Adding/Removing Objects
  8403. You generally add or remove objects from a set using `add()` or
  8404. `remove()`. You can add any type of object including primitives such as
  8405. numbers, strings, and booleans.
  8406. Unlike arrays, objects can only exist one time in a set. If you call `add()`
  8407. on a set with the same object multiple times, the object will only be added
  8408. once. Likewise, calling `remove()` with the same object multiple times will
  8409. remove the object the first time and have no effect on future calls until
  8410. you add the object to the set again.
  8411. NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do
  8412. so will be ignored.
  8413. In addition to add/remove you can also call `push()`/`pop()`. Push behaves
  8414. just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary
  8415. object, remove it and return it. This is a good way to use a set as a job
  8416. queue when you don't care which order the jobs are executed in.
  8417. ## Testing for an Object
  8418. To test for an object's presence in a set you simply call
  8419. `Ember.Set#contains()`.
  8420. ## Observing changes
  8421. When using `Ember.Set`, you can observe the `"[]"` property to be
  8422. alerted whenever the content changes. You can also add an enumerable
  8423. observer to the set to be notified of specific objects that are added and
  8424. removed from the set. See `Ember.Enumerable` for more information on
  8425. enumerables.
  8426. This is often unhelpful. If you are filtering sets of objects, for instance,
  8427. it is very inefficient to re-filter all of the items each time the set
  8428. changes. It would be better if you could just adjust the filtered set based
  8429. on what was changed on the original set. The same issue applies to merging
  8430. sets, as well.
  8431. ## Other Methods
  8432. `Ember.Set` primary implements other mixin APIs. For a complete reference
  8433. on the methods you will use with `Ember.Set`, please consult these mixins.
  8434. The most useful ones will be `Ember.Enumerable` and
  8435. `Ember.MutableEnumerable` which implement most of the common iterator
  8436. methods you are used to on Array.
  8437. Note that you can also use the `Ember.Copyable` and `Ember.Freezable`
  8438. APIs on `Ember.Set` as well. Once a set is frozen it can no longer be
  8439. modified. The benefit of this is that when you call `frozenCopy()` on it,
  8440. Ember will avoid making copies of the set. This allows you to write
  8441. code that can know with certainty when the underlying set data will or
  8442. will not be modified.
  8443. @class Set
  8444. @namespace Ember
  8445. @extends Ember.CoreObject
  8446. @uses Ember.MutableEnumerable
  8447. @uses Ember.Copyable
  8448. @uses Ember.Freezable
  8449. @since Ember 0.9
  8450. */
  8451. Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Ember.Freezable,
  8452. /** @scope Ember.Set.prototype */ {
  8453. // ..........................................................
  8454. // IMPLEMENT ENUMERABLE APIS
  8455. //
  8456. /**
  8457. This property will change as the number of objects in the set changes.
  8458. @property length
  8459. @type number
  8460. @default 0
  8461. */
  8462. length: 0,
  8463. /**
  8464. Clears the set. This is useful if you want to reuse an existing set
  8465. without having to recreate it.
  8466. ```javascript
  8467. var colors = new Ember.Set(["red", "green", "blue"]);
  8468. colors.length; // 3
  8469. colors.clear();
  8470. colors.length; // 0
  8471. ```
  8472. @method clear
  8473. @return {Ember.Set} An empty Set
  8474. */
  8475. clear: function() {
  8476. if (this.isFrozen) { throw new Error(Ember.FROZEN_ERROR); }
  8477. var len = get(this, 'length');
  8478. if (len === 0) { return this; }
  8479. var guid;
  8480. this.enumerableContentWillChange(len, 0);
  8481. Ember.propertyWillChange(this, 'firstObject');
  8482. Ember.propertyWillChange(this, 'lastObject');
  8483. for (var i=0; i < len; i++){
  8484. guid = guidFor(this[i]);
  8485. delete this[guid];
  8486. delete this[i];
  8487. }
  8488. set(this, 'length', 0);
  8489. Ember.propertyDidChange(this, 'firstObject');
  8490. Ember.propertyDidChange(this, 'lastObject');
  8491. this.enumerableContentDidChange(len, 0);
  8492. return this;
  8493. },
  8494. /**
  8495. Returns true if the passed object is also an enumerable that contains the
  8496. same objects as the receiver.
  8497. ```javascript
  8498. var colors = ["red", "green", "blue"],
  8499. same_colors = new Ember.Set(colors);
  8500. same_colors.isEqual(colors); // true
  8501. same_colors.isEqual(["purple", "brown"]); // false
  8502. ```
  8503. @method isEqual
  8504. @param {Ember.Set} obj the other object.
  8505. @return {Boolean}
  8506. */
  8507. isEqual: function(obj) {
  8508. // fail fast
  8509. if (!Ember.Enumerable.detect(obj)) return false;
  8510. var loc = get(this, 'length');
  8511. if (get(obj, 'length') !== loc) return false;
  8512. while(--loc >= 0) {
  8513. if (!obj.contains(this[loc])) return false;
  8514. }
  8515. return true;
  8516. },
  8517. /**
  8518. Adds an object to the set. Only non-`null` objects can be added to a set
  8519. and those can only be added once. If the object is already in the set or
  8520. the passed value is null this method will have no effect.
  8521. This is an alias for `Ember.MutableEnumerable.addObject()`.
  8522. ```javascript
  8523. var colors = new Ember.Set();
  8524. colors.add("blue"); // ["blue"]
  8525. colors.add("blue"); // ["blue"]
  8526. colors.add("red"); // ["blue", "red"]
  8527. colors.add(null); // ["blue", "red"]
  8528. colors.add(undefined); // ["blue", "red"]
  8529. ```
  8530. @method add
  8531. @param {Object} obj The object to add.
  8532. @return {Ember.Set} The set itself.
  8533. */
  8534. add: Ember.aliasMethod('addObject'),
  8535. /**
  8536. Removes the object from the set if it is found. If you pass a `null` value
  8537. or an object that is already not in the set, this method will have no
  8538. effect. This is an alias for `Ember.MutableEnumerable.removeObject()`.
  8539. ```javascript
  8540. var colors = new Ember.Set(["red", "green", "blue"]);
  8541. colors.remove("red"); // ["blue", "green"]
  8542. colors.remove("purple"); // ["blue", "green"]
  8543. colors.remove(null); // ["blue", "green"]
  8544. ```
  8545. @method remove
  8546. @param {Object} obj The object to remove
  8547. @return {Ember.Set} The set itself.
  8548. */
  8549. remove: Ember.aliasMethod('removeObject'),
  8550. /**
  8551. Removes the last element from the set and returns it, or `null` if it's empty.
  8552. ```javascript
  8553. var colors = new Ember.Set(["green", "blue"]);
  8554. colors.pop(); // "blue"
  8555. colors.pop(); // "green"
  8556. colors.pop(); // null
  8557. ```
  8558. @method pop
  8559. @return {Object} The removed object from the set or null.
  8560. */
  8561. pop: function() {
  8562. if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
  8563. var obj = this.length > 0 ? this[this.length-1] : null;
  8564. this.remove(obj);
  8565. return obj;
  8566. },
  8567. /**
  8568. Inserts the given object on to the end of the set. It returns
  8569. the set itself.
  8570. This is an alias for `Ember.MutableEnumerable.addObject()`.
  8571. ```javascript
  8572. var colors = new Ember.Set();
  8573. colors.push("red"); // ["red"]
  8574. colors.push("green"); // ["red", "green"]
  8575. colors.push("blue"); // ["red", "green", "blue"]
  8576. ```
  8577. @method push
  8578. @return {Ember.Set} The set itself.
  8579. */
  8580. push: Ember.aliasMethod('addObject'),
  8581. /**
  8582. Removes the last element from the set and returns it, or `null` if it's empty.
  8583. This is an alias for `Ember.Set.pop()`.
  8584. ```javascript
  8585. var colors = new Ember.Set(["green", "blue"]);
  8586. colors.shift(); // "blue"
  8587. colors.shift(); // "green"
  8588. colors.shift(); // null
  8589. ```
  8590. @method shift
  8591. @return {Object} The removed object from the set or null.
  8592. */
  8593. shift: Ember.aliasMethod('pop'),
  8594. /**
  8595. Inserts the given object on to the end of the set. It returns
  8596. the set itself.
  8597. This is an alias of `Ember.Set.push()`
  8598. ```javascript
  8599. var colors = new Ember.Set();
  8600. colors.unshift("red"); // ["red"]
  8601. colors.unshift("green"); // ["red", "green"]
  8602. colors.unshift("blue"); // ["red", "green", "blue"]
  8603. ```
  8604. @method unshift
  8605. @return {Ember.Set} The set itself.
  8606. */
  8607. unshift: Ember.aliasMethod('push'),
  8608. /**
  8609. Adds each object in the passed enumerable to the set.
  8610. This is an alias of `Ember.MutableEnumerable.addObjects()`
  8611. ```javascript
  8612. var colors = new Ember.Set();
  8613. colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"]
  8614. ```
  8615. @method addEach
  8616. @param {Ember.Enumerable} objects the objects to add.
  8617. @return {Ember.Set} The set itself.
  8618. */
  8619. addEach: Ember.aliasMethod('addObjects'),
  8620. /**
  8621. Removes each object in the passed enumerable to the set.
  8622. This is an alias of `Ember.MutableEnumerable.removeObjects()`
  8623. ```javascript
  8624. var colors = new Ember.Set(["red", "green", "blue"]);
  8625. colors.removeEach(["red", "blue"]); // ["green"]
  8626. ```
  8627. @method removeEach
  8628. @param {Ember.Enumerable} objects the objects to remove.
  8629. @return {Ember.Set} The set itself.
  8630. */
  8631. removeEach: Ember.aliasMethod('removeObjects'),
  8632. // ..........................................................
  8633. // PRIVATE ENUMERABLE SUPPORT
  8634. //
  8635. init: function(items) {
  8636. this._super();
  8637. if (items) this.addObjects(items);
  8638. },
  8639. // implement Ember.Enumerable
  8640. nextObject: function(idx) {
  8641. return this[idx];
  8642. },
  8643. // more optimized version
  8644. firstObject: Ember.computed(function() {
  8645. return this.length > 0 ? this[0] : undefined;
  8646. }),
  8647. // more optimized version
  8648. lastObject: Ember.computed(function() {
  8649. return this.length > 0 ? this[this.length-1] : undefined;
  8650. }),
  8651. // implements Ember.MutableEnumerable
  8652. addObject: function(obj) {
  8653. if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
  8654. if (none(obj)) return this; // nothing to do
  8655. var guid = guidFor(obj),
  8656. idx = this[guid],
  8657. len = get(this, 'length'),
  8658. added ;
  8659. if (idx>=0 && idx<len && (this[idx] === obj)) return this; // added
  8660. added = [obj];
  8661. this.enumerableContentWillChange(null, added);
  8662. Ember.propertyWillChange(this, 'lastObject');
  8663. len = get(this, 'length');
  8664. this[guid] = len;
  8665. this[len] = obj;
  8666. set(this, 'length', len+1);
  8667. Ember.propertyDidChange(this, 'lastObject');
  8668. this.enumerableContentDidChange(null, added);
  8669. return this;
  8670. },
  8671. // implements Ember.MutableEnumerable
  8672. removeObject: function(obj) {
  8673. if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
  8674. if (none(obj)) return this; // nothing to do
  8675. var guid = guidFor(obj),
  8676. idx = this[guid],
  8677. len = get(this, 'length'),
  8678. isFirst = idx === 0,
  8679. isLast = idx === len-1,
  8680. last, removed;
  8681. if (idx>=0 && idx<len && (this[idx] === obj)) {
  8682. removed = [obj];
  8683. this.enumerableContentWillChange(removed, null);
  8684. if (isFirst) { Ember.propertyWillChange(this, 'firstObject'); }
  8685. if (isLast) { Ember.propertyWillChange(this, 'lastObject'); }
  8686. // swap items - basically move the item to the end so it can be removed
  8687. if (idx < len-1) {
  8688. last = this[len-1];
  8689. this[idx] = last;
  8690. this[guidFor(last)] = idx;
  8691. }
  8692. delete this[guid];
  8693. delete this[len-1];
  8694. set(this, 'length', len-1);
  8695. if (isFirst) { Ember.propertyDidChange(this, 'firstObject'); }
  8696. if (isLast) { Ember.propertyDidChange(this, 'lastObject'); }
  8697. this.enumerableContentDidChange(removed, null);
  8698. }
  8699. return this;
  8700. },
  8701. // optimized version
  8702. contains: function(obj) {
  8703. return this[guidFor(obj)]>=0;
  8704. },
  8705. copy: function() {
  8706. var C = this.constructor, ret = new C(), loc = get(this, 'length');
  8707. set(ret, 'length', loc);
  8708. while(--loc>=0) {
  8709. ret[loc] = this[loc];
  8710. ret[guidFor(this[loc])] = loc;
  8711. }
  8712. return ret;
  8713. },
  8714. toString: function() {
  8715. var len = this.length, idx, array = [];
  8716. for(idx = 0; idx < len; idx++) {
  8717. array[idx] = this[idx];
  8718. }
  8719. return "Ember.Set<%@>".fmt(array.join(','));
  8720. }
  8721. });
  8722. })();
  8723. (function() {
  8724. /**
  8725. @module ember
  8726. @submodule ember-runtime
  8727. */
  8728. /**
  8729. `Ember.Object` is the main base class for all Ember objects. It is a subclass
  8730. of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details,
  8731. see the documentation for each of these.
  8732. @class Object
  8733. @namespace Ember
  8734. @extends Ember.CoreObject
  8735. @uses Ember.Observable
  8736. */
  8737. Ember.Object = Ember.CoreObject.extend(Ember.Observable);
  8738. Ember.Object.toString = function() { return "Ember.Object"; };
  8739. })();
  8740. (function() {
  8741. /**
  8742. @module ember
  8743. @submodule ember-runtime
  8744. */
  8745. var get = Ember.get, indexOf = Ember.ArrayPolyfills.indexOf;
  8746. /**
  8747. A Namespace is an object usually used to contain other objects or methods
  8748. such as an application or framework. Create a namespace anytime you want
  8749. to define one of these new containers.
  8750. # Example Usage
  8751. ```javascript
  8752. MyFramework = Ember.Namespace.create({
  8753. VERSION: '1.0.0'
  8754. });
  8755. ```
  8756. @class Namespace
  8757. @namespace Ember
  8758. @extends Ember.Object
  8759. */
  8760. var Namespace = Ember.Namespace = Ember.Object.extend({
  8761. isNamespace: true,
  8762. init: function() {
  8763. Ember.Namespace.NAMESPACES.push(this);
  8764. Ember.Namespace.PROCESSED = false;
  8765. },
  8766. toString: function() {
  8767. var name = get(this, 'name');
  8768. if (name) { return name; }
  8769. findNamespaces();
  8770. return this[Ember.GUID_KEY+'_name'];
  8771. },
  8772. nameClasses: function() {
  8773. processNamespace([this.toString()], this, {});
  8774. },
  8775. destroy: function() {
  8776. var namespaces = Ember.Namespace.NAMESPACES;
  8777. Ember.lookup[this.toString()] = undefined;
  8778. namespaces.splice(indexOf.call(namespaces, this), 1);
  8779. this._super();
  8780. }
  8781. });
  8782. Namespace.reopenClass({
  8783. NAMESPACES: [Ember],
  8784. NAMESPACES_BY_ID: {},
  8785. PROCESSED: false,
  8786. processAll: processAllNamespaces,
  8787. byName: function(name) {
  8788. if (!Ember.BOOTED) {
  8789. processAllNamespaces();
  8790. }
  8791. return NAMESPACES_BY_ID[name];
  8792. }
  8793. });
  8794. var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID;
  8795. var hasOwnProp = ({}).hasOwnProperty,
  8796. guidFor = Ember.guidFor;
  8797. function processNamespace(paths, root, seen) {
  8798. var idx = paths.length;
  8799. NAMESPACES_BY_ID[paths.join('.')] = root;
  8800. // Loop over all of the keys in the namespace, looking for classes
  8801. for(var key in root) {
  8802. if (!hasOwnProp.call(root, key)) { continue; }
  8803. var obj = root[key];
  8804. // If we are processing the `Ember` namespace, for example, the
  8805. // `paths` will start with `["Ember"]`. Every iteration through
  8806. // the loop will update the **second** element of this list with
  8807. // the key, so processing `Ember.View` will make the Array
  8808. // `['Ember', 'View']`.
  8809. paths[idx] = key;
  8810. // If we have found an unprocessed class
  8811. if (obj && obj.toString === classToString) {
  8812. // Replace the class' `toString` with the dot-separated path
  8813. // and set its `NAME_KEY`
  8814. obj.toString = makeToString(paths.join('.'));
  8815. obj[NAME_KEY] = paths.join('.');
  8816. // Support nested namespaces
  8817. } else if (obj && obj.isNamespace) {
  8818. // Skip aliased namespaces
  8819. if (seen[guidFor(obj)]) { continue; }
  8820. seen[guidFor(obj)] = true;
  8821. // Process the child namespace
  8822. processNamespace(paths, obj, seen);
  8823. }
  8824. }
  8825. paths.length = idx; // cut out last item
  8826. }
  8827. function findNamespaces() {
  8828. var Namespace = Ember.Namespace, lookup = Ember.lookup, obj, isNamespace;
  8829. if (Namespace.PROCESSED) { return; }
  8830. for (var prop in lookup) {
  8831. // These don't raise exceptions but can cause warnings
  8832. if (prop === "parent" || prop === "top" || prop === "frameElement") { continue; }
  8833. // get(window.globalStorage, 'isNamespace') would try to read the storage for domain isNamespace and cause exception in Firefox.
  8834. // globalStorage is a storage obsoleted by the WhatWG storage specification. See https://developer.mozilla.org/en/DOM/Storage#globalStorage
  8835. if (prop === "globalStorage" && lookup.StorageList && lookup.globalStorage instanceof lookup.StorageList) { continue; }
  8836. // Unfortunately, some versions of IE don't support window.hasOwnProperty
  8837. if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { continue; }
  8838. // At times we are not allowed to access certain properties for security reasons.
  8839. // There are also times where even if we can access them, we are not allowed to access their properties.
  8840. try {
  8841. obj = Ember.lookup[prop];
  8842. isNamespace = obj && obj.isNamespace;
  8843. } catch (e) {
  8844. continue;
  8845. }
  8846. if (isNamespace) {
  8847. Ember.deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop));
  8848. obj[NAME_KEY] = prop;
  8849. }
  8850. }
  8851. }
  8852. var NAME_KEY = Ember.NAME_KEY = Ember.GUID_KEY + '_name';
  8853. function superClassString(mixin) {
  8854. var superclass = mixin.superclass;
  8855. if (superclass) {
  8856. if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; }
  8857. else { return superClassString(superclass); }
  8858. } else {
  8859. return;
  8860. }
  8861. }
  8862. function classToString() {
  8863. if (!Ember.BOOTED && !this[NAME_KEY]) {
  8864. processAllNamespaces();
  8865. }
  8866. var ret;
  8867. if (this[NAME_KEY]) {
  8868. ret = this[NAME_KEY];
  8869. } else {
  8870. var str = superClassString(this);
  8871. if (str) {
  8872. ret = "(subclass of " + str + ")";
  8873. } else {
  8874. ret = "(unknown mixin)";
  8875. }
  8876. this.toString = makeToString(ret);
  8877. }
  8878. return ret;
  8879. }
  8880. function processAllNamespaces() {
  8881. var unprocessedNamespaces = !Namespace.PROCESSED,
  8882. unprocessedMixins = Ember.anyUnprocessedMixins;
  8883. if (unprocessedNamespaces) {
  8884. findNamespaces();
  8885. Namespace.PROCESSED = true;
  8886. }
  8887. if (unprocessedNamespaces || unprocessedMixins) {
  8888. var namespaces = Namespace.NAMESPACES, namespace;
  8889. for (var i=0, l=namespaces.length; i<l; i++) {
  8890. namespace = namespaces[i];
  8891. processNamespace([namespace.toString()], namespace, {});
  8892. }
  8893. Ember.anyUnprocessedMixins = false;
  8894. }
  8895. }
  8896. function makeToString(ret) {
  8897. return function() { return ret; };
  8898. }
  8899. Ember.Mixin.prototype.toString = classToString;
  8900. })();
  8901. (function() {
  8902. /**
  8903. @module ember
  8904. @submodule ember-runtime
  8905. */
  8906. /**
  8907. Defines a namespace that will contain an executable application. This is
  8908. very similar to a normal namespace except that it is expected to include at
  8909. least a 'ready' function which can be run to initialize the application.
  8910. Currently `Ember.Application` is very similar to `Ember.Namespace.` However,
  8911. this class may be augmented by additional frameworks so it is important to
  8912. use this instance when building new applications.
  8913. # Example Usage
  8914. ```javascript
  8915. MyApp = Ember.Application.create({
  8916. VERSION: '1.0.0',
  8917. store: Ember.Store.create().from(Ember.fixtures)
  8918. });
  8919. MyApp.ready = function() {
  8920. //..init code goes here...
  8921. }
  8922. ```
  8923. @class Application
  8924. @namespace Ember
  8925. @extends Ember.Namespace
  8926. */
  8927. Ember.Application = Ember.Namespace.extend();
  8928. })();
  8929. (function() {
  8930. /**
  8931. @module ember
  8932. @submodule ember-runtime
  8933. */
  8934. var get = Ember.get, set = Ember.set;
  8935. /**
  8936. An ArrayProxy wraps any other object that implements `Ember.Array` and/or
  8937. `Ember.MutableArray,` forwarding all requests. This makes it very useful for
  8938. a number of binding use cases or other cases where being able to swap
  8939. out the underlying array is useful.
  8940. A simple example of usage:
  8941. ```javascript
  8942. var pets = ['dog', 'cat', 'fish'];
  8943. var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) });
  8944. ap.get('firstObject'); // 'dog'
  8945. ap.set('content', ['amoeba', 'paramecium']);
  8946. ap.get('firstObject'); // 'amoeba'
  8947. ```
  8948. This class can also be useful as a layer to transform the contents of
  8949. an array, as they are accessed. This can be done by overriding
  8950. `objectAtContent`:
  8951. ```javascript
  8952. var pets = ['dog', 'cat', 'fish'];
  8953. var ap = Ember.ArrayProxy.create({
  8954. content: Ember.A(pets),
  8955. objectAtContent: function(idx) {
  8956. return this.get('content').objectAt(idx).toUpperCase();
  8957. }
  8958. });
  8959. ap.get('firstObject'); // . 'DOG'
  8960. ```
  8961. @class ArrayProxy
  8962. @namespace Ember
  8963. @extends Ember.Object
  8964. @uses Ember.MutableArray
  8965. */
  8966. Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
  8967. /** @scope Ember.ArrayProxy.prototype */ {
  8968. /**
  8969. The content array. Must be an object that implements `Ember.Array` and/or
  8970. `Ember.MutableArray.`
  8971. @property content
  8972. @type Ember.Array
  8973. */
  8974. content: null,
  8975. /**
  8976. The array that the proxy pretends to be. In the default `ArrayProxy`
  8977. implementation, this and `content` are the same. Subclasses of `ArrayProxy`
  8978. can override this property to provide things like sorting and filtering.
  8979. @property arrangedContent
  8980. */
  8981. arrangedContent: Ember.computed.alias('content'),
  8982. /**
  8983. Should actually retrieve the object at the specified index from the
  8984. content. You can override this method in subclasses to transform the
  8985. content item to something new.
  8986. This method will only be called if content is non-`null`.
  8987. @method objectAtContent
  8988. @param {Number} idx The index to retrieve.
  8989. @return {Object} the value or undefined if none found
  8990. */
  8991. objectAtContent: function(idx) {
  8992. return get(this, 'arrangedContent').objectAt(idx);
  8993. },
  8994. /**
  8995. Should actually replace the specified objects on the content array.
  8996. You can override this method in subclasses to transform the content item
  8997. into something new.
  8998. This method will only be called if content is non-`null`.
  8999. @method replaceContent
  9000. @param {Number} idx The starting index
  9001. @param {Number} amt The number of items to remove from the content.
  9002. @param {Array} objects Optional array of objects to insert or null if no
  9003. objects.
  9004. @return {void}
  9005. */
  9006. replaceContent: function(idx, amt, objects) {
  9007. get(this, 'content').replace(idx, amt, objects);
  9008. },
  9009. /**
  9010. @private
  9011. Invoked when the content property is about to change. Notifies observers that the
  9012. entire array content will change.
  9013. @method _contentWillChange
  9014. */
  9015. _contentWillChange: Ember.beforeObserver(function() {
  9016. this._teardownContent();
  9017. }, 'content'),
  9018. _teardownContent: function() {
  9019. var content = get(this, 'content');
  9020. if (content) {
  9021. content.removeArrayObserver(this, {
  9022. willChange: 'contentArrayWillChange',
  9023. didChange: 'contentArrayDidChange'
  9024. });
  9025. }
  9026. },
  9027. contentArrayWillChange: Ember.K,
  9028. contentArrayDidChange: Ember.K,
  9029. /**
  9030. @private
  9031. Invoked when the content property changes. Notifies observers that the
  9032. entire array content has changed.
  9033. @method _contentDidChange
  9034. */
  9035. _contentDidChange: Ember.observer(function() {
  9036. var content = get(this, 'content');
  9037. Ember.assert("Can't set ArrayProxy's content to itself", content !== this);
  9038. this._setupContent();
  9039. }, 'content'),
  9040. _setupContent: function() {
  9041. var content = get(this, 'content');
  9042. if (content) {
  9043. content.addArrayObserver(this, {
  9044. willChange: 'contentArrayWillChange',
  9045. didChange: 'contentArrayDidChange'
  9046. });
  9047. }
  9048. },
  9049. _arrangedContentWillChange: Ember.beforeObserver(function() {
  9050. var arrangedContent = get(this, 'arrangedContent'),
  9051. len = arrangedContent ? get(arrangedContent, 'length') : 0;
  9052. this.arrangedContentArrayWillChange(this, 0, len, undefined);
  9053. this.arrangedContentWillChange(this);
  9054. this._teardownArrangedContent(arrangedContent);
  9055. }, 'arrangedContent'),
  9056. _arrangedContentDidChange: Ember.observer(function() {
  9057. var arrangedContent = get(this, 'arrangedContent'),
  9058. len = arrangedContent ? get(arrangedContent, 'length') : 0;
  9059. Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this);
  9060. this._setupArrangedContent();
  9061. this.arrangedContentDidChange(this);
  9062. this.arrangedContentArrayDidChange(this, 0, undefined, len);
  9063. }, 'arrangedContent'),
  9064. _setupArrangedContent: function() {
  9065. var arrangedContent = get(this, 'arrangedContent');
  9066. if (arrangedContent) {
  9067. arrangedContent.addArrayObserver(this, {
  9068. willChange: 'arrangedContentArrayWillChange',
  9069. didChange: 'arrangedContentArrayDidChange'
  9070. });
  9071. }
  9072. },
  9073. _teardownArrangedContent: function() {
  9074. var arrangedContent = get(this, 'arrangedContent');
  9075. if (arrangedContent) {
  9076. arrangedContent.removeArrayObserver(this, {
  9077. willChange: 'arrangedContentArrayWillChange',
  9078. didChange: 'arrangedContentArrayDidChange'
  9079. });
  9080. }
  9081. },
  9082. arrangedContentWillChange: Ember.K,
  9083. arrangedContentDidChange: Ember.K,
  9084. objectAt: function(idx) {
  9085. return get(this, 'content') && this.objectAtContent(idx);
  9086. },
  9087. length: Ember.computed(function() {
  9088. var arrangedContent = get(this, 'arrangedContent');
  9089. return arrangedContent ? get(arrangedContent, 'length') : 0;
  9090. // No dependencies since Enumerable notifies length of change
  9091. }),
  9092. replace: function(idx, amt, objects) {
  9093. Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', this.get('content'));
  9094. if (get(this, 'content')) this.replaceContent(idx, amt, objects);
  9095. return this;
  9096. },
  9097. arrangedContentArrayWillChange: function(item, idx, removedCnt, addedCnt) {
  9098. this.arrayContentWillChange(idx, removedCnt, addedCnt);
  9099. },
  9100. arrangedContentArrayDidChange: function(item, idx, removedCnt, addedCnt) {
  9101. this.arrayContentDidChange(idx, removedCnt, addedCnt);
  9102. },
  9103. init: function() {
  9104. this._super();
  9105. this._setupContent();
  9106. this._setupArrangedContent();
  9107. },
  9108. willDestroy: function() {
  9109. this._teardownArrangedContent();
  9110. this._teardownContent();
  9111. }
  9112. });
  9113. })();
  9114. (function() {
  9115. /**
  9116. @module ember
  9117. @submodule ember-runtime
  9118. */
  9119. var get = Ember.get,
  9120. set = Ember.set,
  9121. fmt = Ember.String.fmt,
  9122. addBeforeObserver = Ember.addBeforeObserver,
  9123. addObserver = Ember.addObserver,
  9124. removeBeforeObserver = Ember.removeBeforeObserver,
  9125. removeObserver = Ember.removeObserver,
  9126. propertyWillChange = Ember.propertyWillChange,
  9127. propertyDidChange = Ember.propertyDidChange;
  9128. function contentPropertyWillChange(content, contentKey) {
  9129. var key = contentKey.slice(8); // remove "content."
  9130. if (key in this) { return; } // if shadowed in proxy
  9131. propertyWillChange(this, key);
  9132. }
  9133. function contentPropertyDidChange(content, contentKey) {
  9134. var key = contentKey.slice(8); // remove "content."
  9135. if (key in this) { return; } // if shadowed in proxy
  9136. propertyDidChange(this, key);
  9137. }
  9138. /**
  9139. `Ember.ObjectProxy` forwards all properties not defined by the proxy itself
  9140. to a proxied `content` object.
  9141. ```javascript
  9142. object = Ember.Object.create({
  9143. name: 'Foo'
  9144. });
  9145. proxy = Ember.ObjectProxy.create({
  9146. content: object
  9147. });
  9148. // Access and change existing properties
  9149. proxy.get('name') // 'Foo'
  9150. proxy.set('name', 'Bar');
  9151. object.get('name') // 'Bar'
  9152. // Create new 'description' property on `object`
  9153. proxy.set('description', 'Foo is a whizboo baz');
  9154. object.get('description') // 'Foo is a whizboo baz'
  9155. ```
  9156. While `content` is unset, setting a property to be delegated will throw an
  9157. Error.
  9158. ```javascript
  9159. proxy = Ember.ObjectProxy.create({
  9160. content: null,
  9161. flag: null
  9162. });
  9163. proxy.set('flag', true);
  9164. proxy.get('flag'); // true
  9165. proxy.get('foo'); // undefined
  9166. proxy.set('foo', 'data'); // throws Error
  9167. ```
  9168. Delegated properties can be bound to and will change when content is updated.
  9169. Computed properties on the proxy itself can depend on delegated properties.
  9170. ```javascript
  9171. ProxyWithComputedProperty = Ember.ObjectProxy.extend({
  9172. fullName: function () {
  9173. var firstName = this.get('firstName'),
  9174. lastName = this.get('lastName');
  9175. if (firstName && lastName) {
  9176. return firstName + ' ' + lastName;
  9177. }
  9178. return firstName || lastName;
  9179. }.property('firstName', 'lastName')
  9180. });
  9181. proxy = ProxyWithComputedProperty.create();
  9182. proxy.get('fullName'); // undefined
  9183. proxy.set('content', {
  9184. firstName: 'Tom', lastName: 'Dale'
  9185. }); // triggers property change for fullName on proxy
  9186. proxy.get('fullName'); // 'Tom Dale'
  9187. ```
  9188. @class ObjectProxy
  9189. @namespace Ember
  9190. @extends Ember.Object
  9191. */
  9192. Ember.ObjectProxy = Ember.Object.extend(
  9193. /** @scope Ember.ObjectProxy.prototype */ {
  9194. /**
  9195. The object whose properties will be forwarded.
  9196. @property content
  9197. @type Ember.Object
  9198. @default null
  9199. */
  9200. content: null,
  9201. _contentDidChange: Ember.observer(function() {
  9202. Ember.assert("Can't set ObjectProxy's content to itself", this.get('content') !== this);
  9203. }, 'content'),
  9204. isTruthy: Ember.computed.bool('content'),
  9205. _debugContainerKey: null,
  9206. willWatchProperty: function (key) {
  9207. var contentKey = 'content.' + key;
  9208. addBeforeObserver(this, contentKey, null, contentPropertyWillChange);
  9209. addObserver(this, contentKey, null, contentPropertyDidChange);
  9210. },
  9211. didUnwatchProperty: function (key) {
  9212. var contentKey = 'content.' + key;
  9213. removeBeforeObserver(this, contentKey, null, contentPropertyWillChange);
  9214. removeObserver(this, contentKey, null, contentPropertyDidChange);
  9215. },
  9216. unknownProperty: function (key) {
  9217. var content = get(this, 'content');
  9218. if (content) {
  9219. return get(content, key);
  9220. }
  9221. },
  9222. setUnknownProperty: function (key, value) {
  9223. var content = get(this, 'content');
  9224. Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of object proxy %@: its 'content' is undefined.", [key, value, this]), content);
  9225. return set(content, key, value);
  9226. }
  9227. });
  9228. })();
  9229. (function() {
  9230. /**
  9231. @module ember
  9232. @submodule ember-runtime
  9233. */
  9234. var set = Ember.set, get = Ember.get, guidFor = Ember.guidFor;
  9235. var forEach = Ember.EnumerableUtils.forEach;
  9236. var EachArray = Ember.Object.extend(Ember.Array, {
  9237. init: function(content, keyName, owner) {
  9238. this._super();
  9239. this._keyName = keyName;
  9240. this._owner = owner;
  9241. this._content = content;
  9242. },
  9243. objectAt: function(idx) {
  9244. var item = this._content.objectAt(idx);
  9245. return item && get(item, this._keyName);
  9246. },
  9247. length: Ember.computed(function() {
  9248. var content = this._content;
  9249. return content ? get(content, 'length') : 0;
  9250. })
  9251. });
  9252. var IS_OBSERVER = /^.+:(before|change)$/;
  9253. function addObserverForContentKey(content, keyName, proxy, idx, loc) {
  9254. var objects = proxy._objects, guid;
  9255. if (!objects) objects = proxy._objects = {};
  9256. while(--loc>=idx) {
  9257. var item = content.objectAt(loc);
  9258. if (item) {
  9259. Ember.addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange');
  9260. Ember.addObserver(item, keyName, proxy, 'contentKeyDidChange');
  9261. // keep track of the indicies each item was found at so we can map
  9262. // it back when the obj changes.
  9263. guid = guidFor(item);
  9264. if (!objects[guid]) objects[guid] = [];
  9265. objects[guid].push(loc);
  9266. }
  9267. }
  9268. }
  9269. function removeObserverForContentKey(content, keyName, proxy, idx, loc) {
  9270. var objects = proxy._objects;
  9271. if (!objects) objects = proxy._objects = {};
  9272. var indicies, guid;
  9273. while(--loc>=idx) {
  9274. var item = content.objectAt(loc);
  9275. if (item) {
  9276. Ember.removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange');
  9277. Ember.removeObserver(item, keyName, proxy, 'contentKeyDidChange');
  9278. guid = guidFor(item);
  9279. indicies = objects[guid];
  9280. indicies[indicies.indexOf(loc)] = null;
  9281. }
  9282. }
  9283. }
  9284. /**
  9285. This is the object instance returned when you get the `@each` property on an
  9286. array. It uses the unknownProperty handler to automatically create
  9287. EachArray instances for property names.
  9288. @private
  9289. @class EachProxy
  9290. @namespace Ember
  9291. @extends Ember.Object
  9292. */
  9293. Ember.EachProxy = Ember.Object.extend({
  9294. init: function(content) {
  9295. this._super();
  9296. this._content = content;
  9297. content.addArrayObserver(this);
  9298. // in case someone is already observing some keys make sure they are
  9299. // added
  9300. forEach(Ember.watchedEvents(this), function(eventName) {
  9301. this.didAddListener(eventName);
  9302. }, this);
  9303. },
  9304. /**
  9305. You can directly access mapped properties by simply requesting them.
  9306. The `unknownProperty` handler will generate an EachArray of each item.
  9307. @method unknownProperty
  9308. @param keyName {String}
  9309. @param value {anything}
  9310. */
  9311. unknownProperty: function(keyName, value) {
  9312. var ret;
  9313. ret = new EachArray(this._content, keyName, this);
  9314. Ember.defineProperty(this, keyName, null, ret);
  9315. this.beginObservingContentKey(keyName);
  9316. return ret;
  9317. },
  9318. // ..........................................................
  9319. // ARRAY CHANGES
  9320. // Invokes whenever the content array itself changes.
  9321. arrayWillChange: function(content, idx, removedCnt, addedCnt) {
  9322. var keys = this._keys, key, array, lim;
  9323. lim = removedCnt>0 ? idx+removedCnt : -1;
  9324. Ember.beginPropertyChanges(this);
  9325. for(key in keys) {
  9326. if (!keys.hasOwnProperty(key)) { continue; }
  9327. if (lim>0) removeObserverForContentKey(content, key, this, idx, lim);
  9328. Ember.propertyWillChange(this, key);
  9329. }
  9330. Ember.propertyWillChange(this._content, '@each');
  9331. Ember.endPropertyChanges(this);
  9332. },
  9333. arrayDidChange: function(content, idx, removedCnt, addedCnt) {
  9334. var keys = this._keys, key, array, lim;
  9335. lim = addedCnt>0 ? idx+addedCnt : -1;
  9336. Ember.beginPropertyChanges(this);
  9337. for(key in keys) {
  9338. if (!keys.hasOwnProperty(key)) { continue; }
  9339. if (lim>0) addObserverForContentKey(content, key, this, idx, lim);
  9340. Ember.propertyDidChange(this, key);
  9341. }
  9342. Ember.propertyDidChange(this._content, '@each');
  9343. Ember.endPropertyChanges(this);
  9344. },
  9345. // ..........................................................
  9346. // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS
  9347. // Start monitoring keys based on who is listening...
  9348. didAddListener: function(eventName) {
  9349. if (IS_OBSERVER.test(eventName)) {
  9350. this.beginObservingContentKey(eventName.slice(0, -7));
  9351. }
  9352. },
  9353. didRemoveListener: function(eventName) {
  9354. if (IS_OBSERVER.test(eventName)) {
  9355. this.stopObservingContentKey(eventName.slice(0, -7));
  9356. }
  9357. },
  9358. // ..........................................................
  9359. // CONTENT KEY OBSERVING
  9360. // Actual watch keys on the source content.
  9361. beginObservingContentKey: function(keyName) {
  9362. var keys = this._keys;
  9363. if (!keys) keys = this._keys = {};
  9364. if (!keys[keyName]) {
  9365. keys[keyName] = 1;
  9366. var content = this._content,
  9367. len = get(content, 'length');
  9368. addObserverForContentKey(content, keyName, this, 0, len);
  9369. } else {
  9370. keys[keyName]++;
  9371. }
  9372. },
  9373. stopObservingContentKey: function(keyName) {
  9374. var keys = this._keys;
  9375. if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) {
  9376. var content = this._content,
  9377. len = get(content, 'length');
  9378. removeObserverForContentKey(content, keyName, this, 0, len);
  9379. }
  9380. },
  9381. contentKeyWillChange: function(obj, keyName) {
  9382. Ember.propertyWillChange(this, keyName);
  9383. },
  9384. contentKeyDidChange: function(obj, keyName) {
  9385. Ember.propertyDidChange(this, keyName);
  9386. }
  9387. });
  9388. })();
  9389. (function() {
  9390. /**
  9391. @module ember
  9392. @submodule ember-runtime
  9393. */
  9394. var get = Ember.get, set = Ember.set;
  9395. // Add Ember.Array to Array.prototype. Remove methods with native
  9396. // implementations and supply some more optimized versions of generic methods
  9397. // because they are so common.
  9398. var NativeArray = Ember.Mixin.create(Ember.MutableArray, Ember.Observable, Ember.Copyable, {
  9399. // because length is a built-in property we need to know to just get the
  9400. // original property.
  9401. get: function(key) {
  9402. if (key==='length') return this.length;
  9403. else if ('number' === typeof key) return this[key];
  9404. else return this._super(key);
  9405. },
  9406. objectAt: function(idx) {
  9407. return this[idx];
  9408. },
  9409. // primitive for array support.
  9410. replace: function(idx, amt, objects) {
  9411. if (this.isFrozen) throw Ember.FROZEN_ERROR ;
  9412. // if we replaced exactly the same number of items, then pass only the
  9413. // replaced range. Otherwise, pass the full remaining array length
  9414. // since everything has shifted
  9415. var len = objects ? get(objects, 'length') : 0;
  9416. this.arrayContentWillChange(idx, amt, len);
  9417. if (!objects || objects.length === 0) {
  9418. this.splice(idx, amt) ;
  9419. } else {
  9420. var args = [idx, amt].concat(objects) ;
  9421. this.splice.apply(this,args) ;
  9422. }
  9423. this.arrayContentDidChange(idx, amt, len);
  9424. return this ;
  9425. },
  9426. // If you ask for an unknown property, then try to collect the value
  9427. // from member items.
  9428. unknownProperty: function(key, value) {
  9429. var ret;// = this.reducedProperty(key, value) ;
  9430. if ((value !== undefined) && ret === undefined) {
  9431. ret = this[key] = value;
  9432. }
  9433. return ret ;
  9434. },
  9435. // If browser did not implement indexOf natively, then override with
  9436. // specialized version
  9437. indexOf: function(object, startAt) {
  9438. var idx, len = this.length;
  9439. if (startAt === undefined) startAt = 0;
  9440. else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
  9441. if (startAt < 0) startAt += len;
  9442. for(idx=startAt;idx<len;idx++) {
  9443. if (this[idx] === object) return idx ;
  9444. }
  9445. return -1;
  9446. },
  9447. lastIndexOf: function(object, startAt) {
  9448. var idx, len = this.length;
  9449. if (startAt === undefined) startAt = len-1;
  9450. else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
  9451. if (startAt < 0) startAt += len;
  9452. for(idx=startAt;idx>=0;idx--) {
  9453. if (this[idx] === object) return idx ;
  9454. }
  9455. return -1;
  9456. },
  9457. copy: function(deep) {
  9458. if (deep) {
  9459. return this.map(function(item){ return Ember.copy(item, true); });
  9460. }
  9461. return this.slice();
  9462. }
  9463. });
  9464. // Remove any methods implemented natively so we don't override them
  9465. var ignore = ['length'];
  9466. Ember.EnumerableUtils.forEach(NativeArray.keys(), function(methodName) {
  9467. if (Array.prototype[methodName]) ignore.push(methodName);
  9468. });
  9469. if (ignore.length>0) {
  9470. NativeArray = NativeArray.without.apply(NativeArray, ignore);
  9471. }
  9472. /**
  9473. The NativeArray mixin contains the properties needed to to make the native
  9474. Array support Ember.MutableArray and all of its dependent APIs. Unless you
  9475. have `Ember.EXTEND_PROTOTYPES or `Ember.EXTEND_PROTOTYPES.Array` set to
  9476. false, this will be applied automatically. Otherwise you can apply the mixin
  9477. at anytime by calling `Ember.NativeArray.activate`.
  9478. @class NativeArray
  9479. @namespace Ember
  9480. @extends Ember.Mixin
  9481. @uses Ember.MutableArray
  9482. @uses Ember.MutableEnumerable
  9483. @uses Ember.Copyable
  9484. @uses Ember.Freezable
  9485. */
  9486. Ember.NativeArray = NativeArray;
  9487. /**
  9488. Creates an `Ember.NativeArray` from an Array like object.
  9489. Does not modify the original object.
  9490. @method A
  9491. @for Ember
  9492. @return {Ember.NativeArray}
  9493. */
  9494. Ember.A = function(arr){
  9495. if (arr === undefined) { arr = []; }
  9496. return Ember.Array.detect(arr) ? arr : Ember.NativeArray.apply(arr);
  9497. };
  9498. /**
  9499. Activates the mixin on the Array.prototype if not already applied. Calling
  9500. this method more than once is safe.
  9501. @method activate
  9502. @for Ember.NativeArray
  9503. @static
  9504. @return {void}
  9505. */
  9506. Ember.NativeArray.activate = function() {
  9507. NativeArray.apply(Array.prototype);
  9508. Ember.A = function(arr) { return arr || []; };
  9509. };
  9510. if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) {
  9511. Ember.NativeArray.activate();
  9512. }
  9513. })();
  9514. (function() {
  9515. var DeferredMixin = Ember.DeferredMixin, // mixins/deferred
  9516. EmberObject = Ember.Object, // system/object
  9517. get = Ember.get;
  9518. var Deferred = Ember.Object.extend(DeferredMixin);
  9519. Deferred.reopenClass({
  9520. promise: function(callback, binding) {
  9521. var deferred = Deferred.create();
  9522. callback.call(binding, deferred);
  9523. return get(deferred, 'promise');
  9524. }
  9525. });
  9526. Ember.Deferred = Deferred;
  9527. })();
  9528. (function() {
  9529. /**
  9530. @module ember
  9531. @submodule ember-runtime
  9532. */
  9533. var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {};
  9534. var loaded = {};
  9535. /**
  9536. @method onLoad
  9537. @for Ember
  9538. @param name {String} name of hook
  9539. @param callback {Function} callback to be called
  9540. */
  9541. Ember.onLoad = function(name, callback) {
  9542. var object;
  9543. loadHooks[name] = loadHooks[name] || Ember.A();
  9544. loadHooks[name].pushObject(callback);
  9545. if (object = loaded[name]) {
  9546. callback(object);
  9547. }
  9548. };
  9549. /**
  9550. @method runLoadHooks
  9551. @for Ember
  9552. @param name {String} name of hook
  9553. @param object {Object} object to pass to callbacks
  9554. */
  9555. Ember.runLoadHooks = function(name, object) {
  9556. var hooks;
  9557. loaded[name] = object;
  9558. if (hooks = loadHooks[name]) {
  9559. loadHooks[name].forEach(function(callback) {
  9560. callback(object);
  9561. });
  9562. }
  9563. };
  9564. })();
  9565. (function() {
  9566. })();
  9567. (function() {
  9568. var get = Ember.get;
  9569. /**
  9570. @module ember
  9571. @submodule ember-runtime
  9572. */
  9573. /**
  9574. `Ember.ControllerMixin` provides a standard interface for all classes that
  9575. compose Ember's controller layer: `Ember.Controller`,
  9576. `Ember.ArrayController`, and `Ember.ObjectController`.
  9577. Within an `Ember.Router`-managed application single shared instaces of every
  9578. Controller object in your application's namespace will be added to the
  9579. application's `Ember.Router` instance. See `Ember.Application#initialize`
  9580. for additional information.
  9581. ## Views
  9582. By default a controller instance will be the rendering context
  9583. for its associated `Ember.View.` This connection is made during calls to
  9584. `Ember.ControllerMixin#connectOutlet`.
  9585. Within the view's template, the `Ember.View` instance can be accessed
  9586. through the controller with `{{view}}`.
  9587. ## Target Forwarding
  9588. By default a controller will target your application's `Ember.Router`
  9589. instance. Calls to `{{action}}` within the template of a controller's view
  9590. are forwarded to the router. See `Ember.Handlebars.helpers.action` for
  9591. additional information.
  9592. @class ControllerMixin
  9593. @namespace Ember
  9594. @extends Ember.Mixin
  9595. */
  9596. Ember.ControllerMixin = Ember.Mixin.create({
  9597. /* ducktype as a controller */
  9598. isController: true,
  9599. /**
  9600. The object to which events from the view should be sent.
  9601. For example, when a Handlebars template uses the `{{action}}` helper,
  9602. it will attempt to send the event to the view's controller's `target`.
  9603. By default, a controller's `target` is set to the router after it is
  9604. instantiated by `Ember.Application#initialize`.
  9605. @property target
  9606. @default null
  9607. */
  9608. target: null,
  9609. container: null,
  9610. store: null,
  9611. model: Ember.computed.alias('content'),
  9612. send: function(actionName) {
  9613. var args = [].slice.call(arguments, 1), target;
  9614. if (this[actionName]) {
  9615. Ember.assert("The controller " + this + " does not have the action " + actionName, typeof this[actionName] === 'function');
  9616. this[actionName].apply(this, args);
  9617. } else if(target = get(this, 'target')) {
  9618. Ember.assert("The target for controller " + this + " (" + target + ") did not define a `send` method", typeof target.send === 'function');
  9619. target.send.apply(target, arguments);
  9620. }
  9621. }
  9622. });
  9623. /**
  9624. @class Controller
  9625. @namespace Ember
  9626. @extends Ember.Object
  9627. @uses Ember.ControllerMixin
  9628. */
  9629. Ember.Controller = Ember.Object.extend(Ember.ControllerMixin);
  9630. })();
  9631. (function() {
  9632. /**
  9633. @module ember
  9634. @submodule ember-runtime
  9635. */
  9636. var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach;
  9637. /**
  9638. `Ember.SortableMixin` provides a standard interface for array proxies
  9639. to specify a sort order and maintain this sorting when objects are added,
  9640. removed, or updated without changing the implicit order of their underlying
  9641. content array:
  9642. ```javascript
  9643. songs = [
  9644. {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'},
  9645. {trackNumber: 2, title: 'Back in the U.S.S.R.'},
  9646. {trackNumber: 3, title: 'Glass Onion'},
  9647. ];
  9648. songsController = Ember.ArrayController.create({
  9649. content: songs,
  9650. sortProperties: ['trackNumber'],
  9651. sortAscending: true
  9652. });
  9653. songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'}
  9654. songsController.addObject({trackNumber: 1, title: 'Dear Prudence'});
  9655. songsController.get('firstObject'); // {trackNumber: 1, title: 'Dear Prudence'}
  9656. ```
  9657. @class SortableMixin
  9658. @namespace Ember
  9659. @extends Ember.Mixin
  9660. @uses Ember.MutableEnumerable
  9661. */
  9662. Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
  9663. /**
  9664. Specifies which properties dictate the arrangedContent's sort order.
  9665. @property {Array} sortProperties
  9666. */
  9667. sortProperties: null,
  9668. /**
  9669. Specifies the arrangedContent's sort direction
  9670. @property {Boolean} sortAscending
  9671. */
  9672. sortAscending: true,
  9673. orderBy: function(item1, item2) {
  9674. var result = 0,
  9675. sortProperties = get(this, 'sortProperties'),
  9676. sortAscending = get(this, 'sortAscending');
  9677. Ember.assert("you need to define `sortProperties`", !!sortProperties);
  9678. forEach(sortProperties, function(propertyName) {
  9679. if (result === 0) {
  9680. result = Ember.compare(get(item1, propertyName), get(item2, propertyName));
  9681. if ((result !== 0) && !sortAscending) {
  9682. result = (-1) * result;
  9683. }
  9684. }
  9685. });
  9686. return result;
  9687. },
  9688. destroy: function() {
  9689. var content = get(this, 'content'),
  9690. sortProperties = get(this, 'sortProperties');
  9691. if (content && sortProperties) {
  9692. forEach(content, function(item) {
  9693. forEach(sortProperties, function(sortProperty) {
  9694. Ember.removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
  9695. }, this);
  9696. }, this);
  9697. }
  9698. return this._super();
  9699. },
  9700. isSorted: Ember.computed.bool('sortProperties'),
  9701. arrangedContent: Ember.computed('content', 'sortProperties.@each', function(key, value) {
  9702. var content = get(this, 'content'),
  9703. isSorted = get(this, 'isSorted'),
  9704. sortProperties = get(this, 'sortProperties'),
  9705. self = this;
  9706. if (content && isSorted) {
  9707. content = content.slice();
  9708. content.sort(function(item1, item2) {
  9709. return self.orderBy(item1, item2);
  9710. });
  9711. forEach(content, function(item) {
  9712. forEach(sortProperties, function(sortProperty) {
  9713. Ember.addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
  9714. }, this);
  9715. }, this);
  9716. return Ember.A(content);
  9717. }
  9718. return content;
  9719. }),
  9720. _contentWillChange: Ember.beforeObserver(function() {
  9721. var content = get(this, 'content'),
  9722. sortProperties = get(this, 'sortProperties');
  9723. if (content && sortProperties) {
  9724. forEach(content, function(item) {
  9725. forEach(sortProperties, function(sortProperty) {
  9726. Ember.removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
  9727. }, this);
  9728. }, this);
  9729. }
  9730. this._super();
  9731. }, 'content'),
  9732. sortAscendingWillChange: Ember.beforeObserver(function() {
  9733. this._lastSortAscending = get(this, 'sortAscending');
  9734. }, 'sortAscending'),
  9735. sortAscendingDidChange: Ember.observer(function() {
  9736. if (get(this, 'sortAscending') !== this._lastSortAscending) {
  9737. var arrangedContent = get(this, 'arrangedContent');
  9738. arrangedContent.reverseObjects();
  9739. }
  9740. }, 'sortAscending'),
  9741. contentArrayWillChange: function(array, idx, removedCount, addedCount) {
  9742. var isSorted = get(this, 'isSorted');
  9743. if (isSorted) {
  9744. var arrangedContent = get(this, 'arrangedContent');
  9745. var removedObjects = array.slice(idx, idx+removedCount);
  9746. var sortProperties = get(this, 'sortProperties');
  9747. forEach(removedObjects, function(item) {
  9748. arrangedContent.removeObject(item);
  9749. forEach(sortProperties, function(sortProperty) {
  9750. Ember.removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
  9751. }, this);
  9752. }, this);
  9753. }
  9754. return this._super(array, idx, removedCount, addedCount);
  9755. },
  9756. contentArrayDidChange: function(array, idx, removedCount, addedCount) {
  9757. var isSorted = get(this, 'isSorted'),
  9758. sortProperties = get(this, 'sortProperties');
  9759. if (isSorted) {
  9760. var addedObjects = array.slice(idx, idx+addedCount);
  9761. var arrangedContent = get(this, 'arrangedContent');
  9762. forEach(addedObjects, function(item) {
  9763. this.insertItemSorted(item);
  9764. forEach(sortProperties, function(sortProperty) {
  9765. Ember.addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
  9766. }, this);
  9767. }, this);
  9768. }
  9769. return this._super(array, idx, removedCount, addedCount);
  9770. },
  9771. insertItemSorted: function(item) {
  9772. var arrangedContent = get(this, 'arrangedContent');
  9773. var length = get(arrangedContent, 'length');
  9774. var idx = this._binarySearch(item, 0, length);
  9775. arrangedContent.insertAt(idx, item);
  9776. },
  9777. contentItemSortPropertyDidChange: function(item) {
  9778. var arrangedContent = get(this, 'arrangedContent'),
  9779. oldIndex = arrangedContent.indexOf(item),
  9780. leftItem = arrangedContent.objectAt(oldIndex - 1),
  9781. rightItem = arrangedContent.objectAt(oldIndex + 1),
  9782. leftResult = leftItem && this.orderBy(item, leftItem),
  9783. rightResult = rightItem && this.orderBy(item, rightItem);
  9784. if (leftResult < 0 || rightResult > 0) {
  9785. arrangedContent.removeObject(item);
  9786. this.insertItemSorted(item);
  9787. }
  9788. },
  9789. _binarySearch: function(item, low, high) {
  9790. var mid, midItem, res, arrangedContent;
  9791. if (low === high) {
  9792. return low;
  9793. }
  9794. arrangedContent = get(this, 'arrangedContent');
  9795. mid = low + Math.floor((high - low) / 2);
  9796. midItem = arrangedContent.objectAt(mid);
  9797. res = this.orderBy(midItem, item);
  9798. if (res < 0) {
  9799. return this._binarySearch(item, mid+1, high);
  9800. } else if (res > 0) {
  9801. return this._binarySearch(item, low, mid);
  9802. }
  9803. return mid;
  9804. }
  9805. });
  9806. })();
  9807. (function() {
  9808. /**
  9809. @module ember
  9810. @submodule ember-runtime
  9811. */
  9812. var get = Ember.get, set = Ember.set, isGlobalPath = Ember.isGlobalPath,
  9813. forEach = Ember.EnumerableUtils.forEach, replace = Ember.EnumerableUtils.replace;
  9814. /**
  9815. `Ember.ArrayController` provides a way for you to publish a collection of
  9816. objects so that you can easily bind to the collection from a Handlebars
  9817. `#each` helper, an `Ember.CollectionView`, or other controllers.
  9818. The advantage of using an `ArrayController` is that you only have to set up
  9819. your view bindings once; to change what's displayed, simply swap out the
  9820. `content` property on the controller.
  9821. For example, imagine you wanted to display a list of items fetched via an XHR
  9822. request. Create an `Ember.ArrayController` and set its `content` property:
  9823. ```javascript
  9824. MyApp.listController = Ember.ArrayController.create();
  9825. $.get('people.json', function(data) {
  9826. MyApp.listController.set('content', data);
  9827. });
  9828. ```
  9829. Then, create a view that binds to your new controller:
  9830. ```handlebars
  9831. {{#each MyApp.listController}}
  9832. {{firstName}} {{lastName}}
  9833. {{/each}}
  9834. ```
  9835. Although you are binding to the controller, the behavior of this controller
  9836. is to pass through any methods or properties to the underlying array. This
  9837. capability comes from `Ember.ArrayProxy`, which this class inherits from.
  9838. Sometimes you want to display computed properties within the body of an
  9839. `#each` helper that depend on the underlying items in `content`, but are not
  9840. present on those items. To do this, set `itemController` to the name of a
  9841. controller (probably an `ObjectController`) that will wrap each individual item.
  9842. For example:
  9843. ```handlebars
  9844. {{#each post in controller}}
  9845. <li>{{title}} ({{titleLength}} characters)</li>
  9846. {{/each}}
  9847. ```
  9848. ```javascript
  9849. App.PostsController = Ember.ArrayController.extend({
  9850. itemController: 'post'
  9851. });
  9852. App.PostController = Ember.ObjectController.extend({
  9853. // the `title` property will be proxied to the underlying post.
  9854. titleLength: function() {
  9855. return this.get('title').length;
  9856. }.property('title')
  9857. });
  9858. ```
  9859. In some cases it is helpful to return a different `itemController` depending
  9860. on the particular item. Subclasses can do this by overriding
  9861. `lookupItemController`.
  9862. For example:
  9863. ```javascript
  9864. App.MyArrayController = Ember.ArrayController.extend({
  9865. lookupItemController: function( object ) {
  9866. if (object.get('isSpecial')) {
  9867. return "special"; // use App.SpecialController
  9868. } else {
  9869. return "regular"; // use App.RegularController
  9870. }
  9871. }
  9872. });
  9873. ```
  9874. @class ArrayController
  9875. @namespace Ember
  9876. @extends Ember.ArrayProxy
  9877. @uses Ember.SortableMixin
  9878. @uses Ember.ControllerMixin
  9879. */
  9880. Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
  9881. Ember.SortableMixin, {
  9882. /**
  9883. The controller used to wrap items, if any.
  9884. @property itemController
  9885. @type String
  9886. @default null
  9887. */
  9888. itemController: null,
  9889. /**
  9890. Return the name of the controller to wrap items, or `null` if items should
  9891. be returned directly. The default implementation simply returns the
  9892. `itemController` property, but subclasses can override this method to return
  9893. different controllers for different objects.
  9894. For example:
  9895. ```javascript
  9896. App.MyArrayController = Ember.ArrayController.extend({
  9897. lookupItemController: function( object ) {
  9898. if (object.get('isSpecial')) {
  9899. return "special"; // use App.SpecialController
  9900. } else {
  9901. return "regular"; // use App.RegularController
  9902. }
  9903. }
  9904. });
  9905. ```
  9906. @method
  9907. @type String
  9908. @default null
  9909. */
  9910. lookupItemController: function(object) {
  9911. return get(this, 'itemController');
  9912. },
  9913. objectAtContent: function(idx) {
  9914. var length = get(this, 'length'),
  9915. object = get(this,'arrangedContent').objectAt(idx);
  9916. if (idx >= 0 && idx < length) {
  9917. var controllerClass = this.lookupItemController(object);
  9918. if (controllerClass) {
  9919. return this.controllerAt(idx, object, controllerClass);
  9920. }
  9921. }
  9922. // When `controllerClass` is falsy, we have not opted in to using item
  9923. // controllers, so return the object directly.
  9924. // When the index is out of range, we want to return the "out of range"
  9925. // value, whatever that might be. Rather than make assumptions
  9926. // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`.
  9927. return object;
  9928. },
  9929. arrangedContentDidChange: function() {
  9930. this._super();
  9931. this._resetSubContainers();
  9932. },
  9933. arrayContentDidChange: function(idx, removedCnt, addedCnt) {
  9934. var subContainers = get(this, 'subContainers'),
  9935. subContainersToRemove = subContainers.slice(idx, idx+removedCnt);
  9936. forEach(subContainersToRemove, function(subContainer) {
  9937. if (subContainer) { subContainer.destroy(); }
  9938. });
  9939. replace(subContainers, idx, removedCnt, new Array(addedCnt));
  9940. // The shadow array of subcontainers must be updated before we trigger
  9941. // observers, otherwise observers will get the wrong subcontainer when
  9942. // calling `objectAt`
  9943. this._super(idx, removedCnt, addedCnt);
  9944. },
  9945. init: function() {
  9946. this._super();
  9947. if (!this.get('content')) { this.set('content', Ember.A()); }
  9948. this._resetSubContainers();
  9949. },
  9950. controllerAt: function(idx, object, controllerClass) {
  9951. var container = get(this, 'container'),
  9952. subContainers = get(this, 'subContainers'),
  9953. subContainer = subContainers[idx],
  9954. controller;
  9955. if (!subContainer) {
  9956. subContainer = subContainers[idx] = container.child();
  9957. }
  9958. controller = subContainer.lookup("controller:" + controllerClass);
  9959. if (!controller) {
  9960. throw new Error('Could not resolve itemController: "' + controllerClass + '"');
  9961. }
  9962. controller.set('target', this);
  9963. controller.set('content', object);
  9964. return controller;
  9965. },
  9966. subContainers: null,
  9967. _resetSubContainers: function() {
  9968. var subContainers = get(this, 'subContainers');
  9969. if (subContainers) {
  9970. forEach(subContainers, function(subContainer) {
  9971. if (subContainer) { subContainer.destroy(); }
  9972. });
  9973. }
  9974. this.set('subContainers', Ember.A());
  9975. }
  9976. });
  9977. })();
  9978. (function() {
  9979. /**
  9980. @module ember
  9981. @submodule ember-runtime
  9982. */
  9983. /**
  9984. `Ember.ObjectController` is part of Ember's Controller layer. A single shared
  9985. instance of each `Ember.ObjectController` subclass in your application's
  9986. namespace will be created at application initialization and be stored on your
  9987. application's `Ember.Router` instance.
  9988. `Ember.ObjectController` derives its functionality from its superclass
  9989. `Ember.ObjectProxy` and the `Ember.ControllerMixin` mixin.
  9990. @class ObjectController
  9991. @namespace Ember
  9992. @extends Ember.ObjectProxy
  9993. @uses Ember.ControllerMixin
  9994. **/
  9995. Ember.ObjectController = Ember.ObjectProxy.extend(Ember.ControllerMixin);
  9996. })();
  9997. (function() {
  9998. })();
  9999. (function() {
  10000. /**
  10001. Ember Runtime
  10002. @module ember
  10003. @submodule ember-runtime
  10004. @requires ember-metal
  10005. */
  10006. })();
  10007. (function() {
  10008. /**
  10009. @module ember
  10010. @submodule ember-views
  10011. */
  10012. var jQuery = Ember.imports.jQuery;
  10013. Ember.assert("Ember Views require jQuery 1.8 or 1.9", jQuery && (jQuery().jquery.match(/^1\.(8|9)(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY));
  10014. /**
  10015. Alias for jQuery
  10016. @method $
  10017. @for Ember
  10018. */
  10019. Ember.$ = jQuery;
  10020. })();
  10021. (function() {
  10022. /**
  10023. @module ember
  10024. @submodule ember-views
  10025. */
  10026. // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents
  10027. var dragEvents = Ember.String.w('dragstart drag dragenter dragleave dragover drop dragend');
  10028. // Copies the `dataTransfer` property from a browser event object onto the
  10029. // jQuery event object for the specified events
  10030. Ember.EnumerableUtils.forEach(dragEvents, function(eventName) {
  10031. Ember.$.event.fixHooks[eventName] = { props: ['dataTransfer'] };
  10032. });
  10033. })();
  10034. (function() {
  10035. /**
  10036. @module ember
  10037. @submodule ember-views
  10038. */
  10039. /*** BEGIN METAMORPH HELPERS ***/
  10040. // Internet Explorer prior to 9 does not allow setting innerHTML if the first element
  10041. // is a "zero-scope" element. This problem can be worked around by making
  10042. // the first node an invisible text node. We, like Modernizr, use &shy;
  10043. var needsShy = (function(){
  10044. var testEl = document.createElement('div');
  10045. testEl.innerHTML = "<div></div>";
  10046. testEl.firstChild.innerHTML = "<script></script>";
  10047. return testEl.firstChild.innerHTML === '';
  10048. })();
  10049. // IE 8 (and likely earlier) likes to move whitespace preceeding
  10050. // a script tag to appear after it. This means that we can
  10051. // accidentally remove whitespace when updating a morph.
  10052. var movesWhitespace = (function() {
  10053. var testEl = document.createElement('div');
  10054. testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value";
  10055. return testEl.childNodes[0].nodeValue === 'Test:' &&
  10056. testEl.childNodes[2].nodeValue === ' Value';
  10057. })();
  10058. // Use this to find children by ID instead of using jQuery
  10059. var findChildById = function(element, id) {
  10060. if (element.getAttribute('id') === id) { return element; }
  10061. var len = element.childNodes.length, idx, node, found;
  10062. for (idx=0; idx<len; idx++) {
  10063. node = element.childNodes[idx];
  10064. found = node.nodeType === 1 && findChildById(node, id);
  10065. if (found) { return found; }
  10066. }
  10067. };
  10068. var setInnerHTMLWithoutFix = function(element, html) {
  10069. if (needsShy) {
  10070. html = '&shy;' + html;
  10071. }
  10072. var matches = [];
  10073. if (movesWhitespace) {
  10074. // Right now we only check for script tags with ids with the
  10075. // goal of targeting morphs.
  10076. html = html.replace(/(\s+)(<script id='([^']+)')/g, function(match, spaces, tag, id) {
  10077. matches.push([id, spaces]);
  10078. return tag;
  10079. });
  10080. }
  10081. element.innerHTML = html;
  10082. // If we have to do any whitespace adjustments do them now
  10083. if (matches.length > 0) {
  10084. var len = matches.length, idx;
  10085. for (idx=0; idx<len; idx++) {
  10086. var script = findChildById(element, matches[idx][0]),
  10087. node = document.createTextNode(matches[idx][1]);
  10088. script.parentNode.insertBefore(node, script);
  10089. }
  10090. }
  10091. if (needsShy) {
  10092. var shyElement = element.firstChild;
  10093. while (shyElement.nodeType === 1 && !shyElement.nodeName) {
  10094. shyElement = shyElement.firstChild;
  10095. }
  10096. if (shyElement.nodeType === 3 && shyElement.nodeValue.charAt(0) === "\u00AD") {
  10097. shyElement.nodeValue = shyElement.nodeValue.slice(1);
  10098. }
  10099. }
  10100. };
  10101. /*** END METAMORPH HELPERS */
  10102. var innerHTMLTags = {};
  10103. var canSetInnerHTML = function(tagName) {
  10104. if (innerHTMLTags[tagName] !== undefined) {
  10105. return innerHTMLTags[tagName];
  10106. }
  10107. var canSet = true;
  10108. // IE 8 and earlier don't allow us to do innerHTML on select
  10109. if (tagName.toLowerCase() === 'select') {
  10110. var el = document.createElement('select');
  10111. setInnerHTMLWithoutFix(el, '<option value="test">Test</option>');
  10112. canSet = el.options.length === 1;
  10113. }
  10114. innerHTMLTags[tagName] = canSet;
  10115. return canSet;
  10116. };
  10117. var setInnerHTML = function(element, html) {
  10118. var tagName = element.tagName;
  10119. if (canSetInnerHTML(tagName)) {
  10120. setInnerHTMLWithoutFix(element, html);
  10121. } else {
  10122. Ember.assert("Can't set innerHTML on "+element.tagName+" in this browser", element.outerHTML);
  10123. var startTag = element.outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0],
  10124. endTag = '</'+tagName+'>';
  10125. var wrapper = document.createElement('div');
  10126. setInnerHTMLWithoutFix(wrapper, startTag + html + endTag);
  10127. element = wrapper.firstChild;
  10128. while (element.tagName !== tagName) {
  10129. element = element.nextSibling;
  10130. }
  10131. }
  10132. return element;
  10133. };
  10134. function isSimpleClick(event) {
  10135. var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey,
  10136. secondaryClick = event.which > 1; // IE9 may return undefined
  10137. return !modifier && !secondaryClick;
  10138. }
  10139. Ember.ViewUtils = {
  10140. setInnerHTML: setInnerHTML,
  10141. isSimpleClick: isSimpleClick
  10142. };
  10143. })();
  10144. (function() {
  10145. /**
  10146. @module ember
  10147. @submodule ember-views
  10148. */
  10149. var get = Ember.get, set = Ember.set;
  10150. var indexOf = Ember.ArrayPolyfills.indexOf;
  10151. var ClassSet = function() {
  10152. this.seen = {};
  10153. this.list = [];
  10154. };
  10155. ClassSet.prototype = {
  10156. add: function(string) {
  10157. if (string in this.seen) { return; }
  10158. this.seen[string] = true;
  10159. this.list.push(string);
  10160. },
  10161. toDOM: function() {
  10162. return this.list.join(" ");
  10163. }
  10164. };
  10165. /**
  10166. `Ember.RenderBuffer` gathers information regarding the a view and generates the
  10167. final representation. `Ember.RenderBuffer` will generate HTML which can be pushed
  10168. to the DOM.
  10169. @class RenderBuffer
  10170. @namespace Ember
  10171. @constructor
  10172. */
  10173. Ember.RenderBuffer = function(tagName) {
  10174. return new Ember._RenderBuffer(tagName);
  10175. };
  10176. Ember._RenderBuffer = function(tagName) {
  10177. this.tagNames = [tagName || null];
  10178. this.buffer = [];
  10179. };
  10180. Ember._RenderBuffer.prototype =
  10181. /** @scope Ember.RenderBuffer.prototype */ {
  10182. // The root view's element
  10183. _element: null,
  10184. /**
  10185. @private
  10186. An internal set used to de-dupe class names when `addClass()` is
  10187. used. After each call to `addClass()`, the `classes` property
  10188. will be updated.
  10189. @property elementClasses
  10190. @type Array
  10191. @default []
  10192. */
  10193. elementClasses: null,
  10194. /**
  10195. Array of class names which will be applied in the class attribute.
  10196. You can use `setClasses()` to set this property directly. If you
  10197. use `addClass()`, it will be maintained for you.
  10198. @property classes
  10199. @type Array
  10200. @default []
  10201. */
  10202. classes: null,
  10203. /**
  10204. The id in of the element, to be applied in the id attribute.
  10205. You should not set this property yourself, rather, you should use
  10206. the `id()` method of `Ember.RenderBuffer`.
  10207. @property elementId
  10208. @type String
  10209. @default null
  10210. */
  10211. elementId: null,
  10212. /**
  10213. A hash keyed on the name of the attribute and whose value will be
  10214. applied to that attribute. For example, if you wanted to apply a
  10215. `data-view="Foo.bar"` property to an element, you would set the
  10216. elementAttributes hash to `{'data-view':'Foo.bar'}`.
  10217. You should not maintain this hash yourself, rather, you should use
  10218. the `attr()` method of `Ember.RenderBuffer`.
  10219. @property elementAttributes
  10220. @type Hash
  10221. @default {}
  10222. */
  10223. elementAttributes: null,
  10224. /**
  10225. A hash keyed on the name of the properties and whose value will be
  10226. applied to that property. For example, if you wanted to apply a
  10227. `checked=true` property to an element, you would set the
  10228. elementProperties hash to `{'checked':true}`.
  10229. You should not maintain this hash yourself, rather, you should use
  10230. the `prop()` method of `Ember.RenderBuffer`.
  10231. @property elementProperties
  10232. @type Hash
  10233. @default {}
  10234. */
  10235. elementProperties: null,
  10236. /**
  10237. The tagname of the element an instance of `Ember.RenderBuffer` represents.
  10238. Usually, this gets set as the first parameter to `Ember.RenderBuffer`. For
  10239. example, if you wanted to create a `p` tag, then you would call
  10240. ```javascript
  10241. Ember.RenderBuffer('p')
  10242. ```
  10243. @property elementTag
  10244. @type String
  10245. @default null
  10246. */
  10247. elementTag: null,
  10248. /**
  10249. A hash keyed on the name of the style attribute and whose value will
  10250. be applied to that attribute. For example, if you wanted to apply a
  10251. `background-color:black;` style to an element, you would set the
  10252. elementStyle hash to `{'background-color':'black'}`.
  10253. You should not maintain this hash yourself, rather, you should use
  10254. the `style()` method of `Ember.RenderBuffer`.
  10255. @property elementStyle
  10256. @type Hash
  10257. @default {}
  10258. */
  10259. elementStyle: null,
  10260. /**
  10261. Nested `RenderBuffers` will set this to their parent `RenderBuffer`
  10262. instance.
  10263. @property parentBuffer
  10264. @type Ember._RenderBuffer
  10265. */
  10266. parentBuffer: null,
  10267. /**
  10268. Adds a string of HTML to the `RenderBuffer`.
  10269. @method push
  10270. @param {String} string HTML to push into the buffer
  10271. @chainable
  10272. */
  10273. push: function(string) {
  10274. this.buffer.push(string);
  10275. return this;
  10276. },
  10277. /**
  10278. Adds a class to the buffer, which will be rendered to the class attribute.
  10279. @method addClass
  10280. @param {String} className Class name to add to the buffer
  10281. @chainable
  10282. */
  10283. addClass: function(className) {
  10284. // lazily create elementClasses
  10285. var elementClasses = this.elementClasses = (this.elementClasses || new ClassSet());
  10286. this.elementClasses.add(className);
  10287. this.classes = this.elementClasses.list;
  10288. return this;
  10289. },
  10290. setClasses: function(classNames) {
  10291. this.classes = classNames;
  10292. },
  10293. /**
  10294. Sets the elementID to be used for the element.
  10295. @method id
  10296. @param {String} id
  10297. @chainable
  10298. */
  10299. id: function(id) {
  10300. this.elementId = id;
  10301. return this;
  10302. },
  10303. // duck type attribute functionality like jQuery so a render buffer
  10304. // can be used like a jQuery object in attribute binding scenarios.
  10305. /**
  10306. Adds an attribute which will be rendered to the element.
  10307. @method attr
  10308. @param {String} name The name of the attribute
  10309. @param {String} value The value to add to the attribute
  10310. @chainable
  10311. @return {Ember.RenderBuffer|String} this or the current attribute value
  10312. */
  10313. attr: function(name, value) {
  10314. var attributes = this.elementAttributes = (this.elementAttributes || {});
  10315. if (arguments.length === 1) {
  10316. return attributes[name];
  10317. } else {
  10318. attributes[name] = value;
  10319. }
  10320. return this;
  10321. },
  10322. /**
  10323. Remove an attribute from the list of attributes to render.
  10324. @method removeAttr
  10325. @param {String} name The name of the attribute
  10326. @chainable
  10327. */
  10328. removeAttr: function(name) {
  10329. var attributes = this.elementAttributes;
  10330. if (attributes) { delete attributes[name]; }
  10331. return this;
  10332. },
  10333. /**
  10334. Adds an property which will be rendered to the element.
  10335. @method prop
  10336. @param {String} name The name of the property
  10337. @param {String} value The value to add to the property
  10338. @chainable
  10339. @return {Ember.RenderBuffer|String} this or the current property value
  10340. */
  10341. prop: function(name, value) {
  10342. var properties = this.elementProperties = (this.elementProperties || {});
  10343. if (arguments.length === 1) {
  10344. return properties[name];
  10345. } else {
  10346. properties[name] = value;
  10347. }
  10348. return this;
  10349. },
  10350. /**
  10351. Remove an property from the list of properties to render.
  10352. @method removeProp
  10353. @param {String} name The name of the property
  10354. @chainable
  10355. */
  10356. removeProp: function(name) {
  10357. var properties = this.elementProperties;
  10358. if (properties) { delete properties[name]; }
  10359. return this;
  10360. },
  10361. /**
  10362. Adds a style to the style attribute which will be rendered to the element.
  10363. @method style
  10364. @param {String} name Name of the style
  10365. @param {String} value
  10366. @chainable
  10367. */
  10368. style: function(name, value) {
  10369. var style = this.elementStyle = (this.elementStyle || {});
  10370. this.elementStyle[name] = value;
  10371. return this;
  10372. },
  10373. begin: function(tagName) {
  10374. this.tagNames.push(tagName || null);
  10375. return this;
  10376. },
  10377. pushOpeningTag: function() {
  10378. var tagName = this.currentTagName();
  10379. if (!tagName) { return; }
  10380. if (!this._element && this.buffer.length === 0) {
  10381. this._element = this.generateElement();
  10382. return;
  10383. }
  10384. var buffer = this.buffer,
  10385. id = this.elementId,
  10386. classes = this.classes,
  10387. attrs = this.elementAttributes,
  10388. props = this.elementProperties,
  10389. style = this.elementStyle,
  10390. attr, prop;
  10391. buffer.push('<' + tagName);
  10392. if (id) {
  10393. buffer.push(' id="' + this._escapeAttribute(id) + '"');
  10394. this.elementId = null;
  10395. }
  10396. if (classes) {
  10397. buffer.push(' class="' + this._escapeAttribute(classes.join(' ')) + '"');
  10398. this.classes = null;
  10399. }
  10400. if (style) {
  10401. buffer.push(' style="');
  10402. for (prop in style) {
  10403. if (style.hasOwnProperty(prop)) {
  10404. buffer.push(prop + ':' + this._escapeAttribute(style[prop]) + ';');
  10405. }
  10406. }
  10407. buffer.push('"');
  10408. this.elementStyle = null;
  10409. }
  10410. if (attrs) {
  10411. for (attr in attrs) {
  10412. if (attrs.hasOwnProperty(attr)) {
  10413. buffer.push(' ' + attr + '="' + this._escapeAttribute(attrs[attr]) + '"');
  10414. }
  10415. }
  10416. this.elementAttributes = null;
  10417. }
  10418. if (props) {
  10419. for (prop in props) {
  10420. if (props.hasOwnProperty(prop)) {
  10421. var value = props[prop];
  10422. if (value || typeof(value) === 'number') {
  10423. if (value === true) {
  10424. buffer.push(' ' + prop + '="' + prop + '"');
  10425. } else {
  10426. buffer.push(' ' + prop + '="' + this._escapeAttribute(props[prop]) + '"');
  10427. }
  10428. }
  10429. }
  10430. }
  10431. this.elementProperties = null;
  10432. }
  10433. buffer.push('>');
  10434. },
  10435. pushClosingTag: function() {
  10436. var tagName = this.tagNames.pop();
  10437. if (tagName) { this.buffer.push('</' + tagName + '>'); }
  10438. },
  10439. currentTagName: function() {
  10440. return this.tagNames[this.tagNames.length-1];
  10441. },
  10442. generateElement: function() {
  10443. var tagName = this.tagNames.pop(), // pop since we don't need to close
  10444. element = document.createElement(tagName),
  10445. $element = Ember.$(element),
  10446. id = this.elementId,
  10447. classes = this.classes,
  10448. attrs = this.elementAttributes,
  10449. props = this.elementProperties,
  10450. style = this.elementStyle,
  10451. styleBuffer = '', attr, prop;
  10452. if (id) {
  10453. $element.attr('id', id);
  10454. this.elementId = null;
  10455. }
  10456. if (classes) {
  10457. $element.attr('class', classes.join(' '));
  10458. this.classes = null;
  10459. }
  10460. if (style) {
  10461. for (prop in style) {
  10462. if (style.hasOwnProperty(prop)) {
  10463. styleBuffer += (prop + ':' + style[prop] + ';');
  10464. }
  10465. }
  10466. $element.attr('style', styleBuffer);
  10467. this.elementStyle = null;
  10468. }
  10469. if (attrs) {
  10470. for (attr in attrs) {
  10471. if (attrs.hasOwnProperty(attr)) {
  10472. $element.attr(attr, attrs[attr]);
  10473. }
  10474. }
  10475. this.elementAttributes = null;
  10476. }
  10477. if (props) {
  10478. for (prop in props) {
  10479. if (props.hasOwnProperty(prop)) {
  10480. $element.prop(prop, props[prop]);
  10481. }
  10482. }
  10483. this.elementProperties = null;
  10484. }
  10485. return element;
  10486. },
  10487. /**
  10488. @method element
  10489. @return {DOMElement} The element corresponding to the generated HTML
  10490. of this buffer
  10491. */
  10492. element: function() {
  10493. var html = this.innerString();
  10494. if (html) {
  10495. this._element = Ember.ViewUtils.setInnerHTML(this._element, html);
  10496. }
  10497. return this._element;
  10498. },
  10499. /**
  10500. Generates the HTML content for this buffer.
  10501. @method string
  10502. @return {String} The generated HTML
  10503. */
  10504. string: function() {
  10505. if (this._element) {
  10506. return this.element().outerHTML;
  10507. } else {
  10508. return this.innerString();
  10509. }
  10510. },
  10511. innerString: function() {
  10512. return this.buffer.join('');
  10513. },
  10514. _escapeAttribute: function(value) {
  10515. // Stolen shamelessly from Handlebars
  10516. var escape = {
  10517. "<": "&lt;",
  10518. ">": "&gt;",
  10519. '"': "&quot;",
  10520. "'": "&#x27;",
  10521. "`": "&#x60;"
  10522. };
  10523. var badChars = /&(?!\w+;)|[<>"'`]/g;
  10524. var possible = /[&<>"'`]/;
  10525. var escapeChar = function(chr) {
  10526. return escape[chr] || "&amp;";
  10527. };
  10528. var string = value.toString();
  10529. if(!possible.test(string)) { return string; }
  10530. return string.replace(badChars, escapeChar);
  10531. }
  10532. };
  10533. })();
  10534. (function() {
  10535. /**
  10536. @module ember
  10537. @submodule ember-views
  10538. */
  10539. var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
  10540. /**
  10541. `Ember.EventDispatcher` handles delegating browser events to their
  10542. corresponding `Ember.Views.` For example, when you click on a view,
  10543. `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets
  10544. called.
  10545. @class EventDispatcher
  10546. @namespace Ember
  10547. @private
  10548. @extends Ember.Object
  10549. */
  10550. Ember.EventDispatcher = Ember.Object.extend(
  10551. /** @scope Ember.EventDispatcher.prototype */{
  10552. /**
  10553. @private
  10554. The root DOM element to which event listeners should be attached. Event
  10555. listeners will be attached to the document unless this is overridden.
  10556. Can be specified as a DOMElement or a selector string.
  10557. The default body is a string since this may be evaluated before document.body
  10558. exists in the DOM.
  10559. @property rootElement
  10560. @type DOMElement
  10561. @default 'body'
  10562. */
  10563. rootElement: 'body',
  10564. /**
  10565. @private
  10566. Sets up event listeners for standard browser events.
  10567. This will be called after the browser sends a `DOMContentReady` event. By
  10568. default, it will set up all of the listeners on the document body. If you
  10569. would like to register the listeners on a different element, set the event
  10570. dispatcher's `root` property.
  10571. @method setup
  10572. @param addedEvents {Hash}
  10573. */
  10574. setup: function(addedEvents) {
  10575. var event, events = {
  10576. touchstart : 'touchStart',
  10577. touchmove : 'touchMove',
  10578. touchend : 'touchEnd',
  10579. touchcancel : 'touchCancel',
  10580. keydown : 'keyDown',
  10581. keyup : 'keyUp',
  10582. keypress : 'keyPress',
  10583. mousedown : 'mouseDown',
  10584. mouseup : 'mouseUp',
  10585. contextmenu : 'contextMenu',
  10586. click : 'click',
  10587. dblclick : 'doubleClick',
  10588. mousemove : 'mouseMove',
  10589. focusin : 'focusIn',
  10590. focusout : 'focusOut',
  10591. mouseenter : 'mouseEnter',
  10592. mouseleave : 'mouseLeave',
  10593. submit : 'submit',
  10594. input : 'input',
  10595. change : 'change',
  10596. dragstart : 'dragStart',
  10597. drag : 'drag',
  10598. dragenter : 'dragEnter',
  10599. dragleave : 'dragLeave',
  10600. dragover : 'dragOver',
  10601. drop : 'drop',
  10602. dragend : 'dragEnd'
  10603. };
  10604. Ember.$.extend(events, addedEvents || {});
  10605. var rootElement = Ember.$(get(this, 'rootElement'));
  10606. Ember.assert(fmt('You cannot use the same root element (%@) multiple times in an Ember.Application', [rootElement.selector || rootElement[0].tagName]), !rootElement.is('.ember-application'));
  10607. Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length);
  10608. Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length);
  10609. rootElement.addClass('ember-application');
  10610. Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application'));
  10611. for (event in events) {
  10612. if (events.hasOwnProperty(event)) {
  10613. this.setupHandler(rootElement, event, events[event]);
  10614. }
  10615. }
  10616. },
  10617. /**
  10618. @private
  10619. Registers an event listener on the document. If the given event is
  10620. triggered, the provided event handler will be triggered on the target view.
  10621. If the target view does not implement the event handler, or if the handler
  10622. returns `false`, the parent view will be called. The event will continue to
  10623. bubble to each successive parent view until it reaches the top.
  10624. For example, to have the `mouseDown` method called on the target view when
  10625. a `mousedown` event is received from the browser, do the following:
  10626. ```javascript
  10627. setupHandler('mousedown', 'mouseDown');
  10628. ```
  10629. @method setupHandler
  10630. @param {Element} rootElement
  10631. @param {String} event the browser-originated event to listen to
  10632. @param {String} eventName the name of the method to call on the view
  10633. */
  10634. setupHandler: function(rootElement, event, eventName) {
  10635. var self = this;
  10636. rootElement.delegate('.ember-view', event + '.ember', function(evt, triggeringManager) {
  10637. return Ember.handleErrors(function() {
  10638. var view = Ember.View.views[this.id],
  10639. result = true, manager = null;
  10640. manager = self._findNearestEventManager(view,eventName);
  10641. if (manager && manager !== triggeringManager) {
  10642. result = self._dispatchEvent(manager, evt, eventName, view);
  10643. } else if (view) {
  10644. result = self._bubbleEvent(view,evt,eventName);
  10645. } else {
  10646. evt.stopPropagation();
  10647. }
  10648. return result;
  10649. }, this);
  10650. });
  10651. rootElement.delegate('[data-ember-action]', event + '.ember', function(evt) {
  10652. return Ember.handleErrors(function() {
  10653. var actionId = Ember.$(evt.currentTarget).attr('data-ember-action'),
  10654. action = Ember.Handlebars.ActionHelper.registeredActions[actionId];
  10655. // We have to check for action here since in some cases, jQuery will trigger
  10656. // an event on `removeChild` (i.e. focusout) after we've already torn down the
  10657. // action handlers for the view.
  10658. if (action && action.eventName === eventName) {
  10659. return action.handler(evt);
  10660. }
  10661. }, this);
  10662. });
  10663. },
  10664. _findNearestEventManager: function(view, eventName) {
  10665. var manager = null;
  10666. while (view) {
  10667. manager = get(view, 'eventManager');
  10668. if (manager && manager[eventName]) { break; }
  10669. view = get(view, 'parentView');
  10670. }
  10671. return manager;
  10672. },
  10673. _dispatchEvent: function(object, evt, eventName, view) {
  10674. var result = true;
  10675. var handler = object[eventName];
  10676. if (Ember.typeOf(handler) === 'function') {
  10677. result = handler.call(object, evt, view);
  10678. // Do not preventDefault in eventManagers.
  10679. evt.stopPropagation();
  10680. }
  10681. else {
  10682. result = this._bubbleEvent(view, evt, eventName);
  10683. }
  10684. return result;
  10685. },
  10686. _bubbleEvent: function(view, evt, eventName) {
  10687. return Ember.run(function() {
  10688. return view.handleEvent(eventName, evt);
  10689. });
  10690. },
  10691. destroy: function() {
  10692. var rootElement = get(this, 'rootElement');
  10693. Ember.$(rootElement).undelegate('.ember').removeClass('ember-application');
  10694. return this._super();
  10695. }
  10696. });
  10697. })();
  10698. (function() {
  10699. /**
  10700. @module ember
  10701. @submodule ember-views
  10702. */
  10703. // Add a new named queue for rendering views that happens
  10704. // after bindings have synced, and a queue for scheduling actions
  10705. // that that should occur after view rendering.
  10706. var queues = Ember.run.queues;
  10707. queues.splice(Ember.$.inArray('actions', queues)+1, 0, 'render', 'afterRender');
  10708. })();
  10709. (function() {
  10710. /**
  10711. @module ember
  10712. @submodule ember-views
  10713. */
  10714. var get = Ember.get, set = Ember.set;
  10715. // Original class declaration and documentation in runtime/lib/controllers/controller.js
  10716. // NOTE: It may be possible with YUIDoc to combine docs in two locations
  10717. /**
  10718. Additional methods for the ControllerMixin
  10719. @class ControllerMixin
  10720. @namespace Ember
  10721. */
  10722. Ember.ControllerMixin.reopen({
  10723. target: null,
  10724. namespace: null,
  10725. view: null,
  10726. container: null,
  10727. _childContainers: null,
  10728. init: function() {
  10729. this._super();
  10730. set(this, '_childContainers', {});
  10731. },
  10732. _modelDidChange: Ember.observer(function() {
  10733. var containers = get(this, '_childContainers'),
  10734. container;
  10735. for (var prop in containers) {
  10736. if (!containers.hasOwnProperty(prop)) { continue; }
  10737. containers[prop].destroy();
  10738. }
  10739. set(this, '_childContainers', {});
  10740. }, 'model')
  10741. });
  10742. })();
  10743. (function() {
  10744. })();
  10745. (function() {
  10746. var states = {};
  10747. /**
  10748. @module ember
  10749. @submodule ember-views
  10750. */
  10751. var get = Ember.get, set = Ember.set, addObserver = Ember.addObserver, removeObserver = Ember.removeObserver;
  10752. var meta = Ember.meta, guidFor = Ember.guidFor, fmt = Ember.String.fmt;
  10753. var a_slice = [].slice;
  10754. var a_forEach = Ember.EnumerableUtils.forEach;
  10755. var a_addObject = Ember.EnumerableUtils.addObject;
  10756. var childViewsProperty = Ember.computed(function() {
  10757. var childViews = this._childViews, ret = Ember.A(), view = this;
  10758. a_forEach(childViews, function(view) {
  10759. if (view.isVirtual) {
  10760. ret.pushObjects(get(view, 'childViews'));
  10761. } else {
  10762. ret.push(view);
  10763. }
  10764. });
  10765. ret.replace = function (idx, removedCount, addedViews) {
  10766. if (view instanceof Ember.ContainerView) {
  10767. Ember.deprecate("Manipulating a Ember.ContainerView through its childViews property is deprecated. Please use the ContainerView instance itself as an Ember.MutableArray.");
  10768. return view.replace(idx, removedCount, addedViews);
  10769. }
  10770. throw new Error("childViews is immutable");
  10771. };
  10772. return ret;
  10773. });
  10774. Ember.warn("The VIEW_PRESERVES_CONTEXT flag has been removed and the functionality can no longer be disabled.", Ember.ENV.VIEW_PRESERVES_CONTEXT !== false);
  10775. /**
  10776. Global hash of shared templates. This will automatically be populated
  10777. by the build tools so that you can store your Handlebars templates in
  10778. separate files that get loaded into JavaScript at buildtime.
  10779. @property TEMPLATES
  10780. @for Ember
  10781. @type Hash
  10782. */
  10783. Ember.TEMPLATES = {};
  10784. Ember.CoreView = Ember.Object.extend(Ember.Evented, {
  10785. isView: true,
  10786. states: states,
  10787. init: function() {
  10788. this._super();
  10789. // Register the view for event handling. This hash is used by
  10790. // Ember.EventDispatcher to dispatch incoming events.
  10791. if (!this.isVirtual) {
  10792. Ember.assert("Attempted to register a view with an id already in use: "+this.elementId, !Ember.View.views[this.elementId]);
  10793. Ember.View.views[this.elementId] = this;
  10794. }
  10795. this.addBeforeObserver('elementId', function() {
  10796. throw new Error("Changing a view's elementId after creation is not allowed");
  10797. });
  10798. this.transitionTo('preRender');
  10799. },
  10800. /**
  10801. If the view is currently inserted into the DOM of a parent view, this
  10802. property will point to the parent of the view.
  10803. @property parentView
  10804. @type Ember.View
  10805. @default null
  10806. */
  10807. parentView: Ember.computed(function() {
  10808. var parent = this._parentView;
  10809. if (parent && parent.isVirtual) {
  10810. return get(parent, 'parentView');
  10811. } else {
  10812. return parent;
  10813. }
  10814. }).property('_parentView'),
  10815. state: null,
  10816. _parentView: null,
  10817. // return the current view, not including virtual views
  10818. concreteView: Ember.computed(function() {
  10819. if (!this.isVirtual) { return this; }
  10820. else { return get(this, 'parentView'); }
  10821. }).property('parentView').volatile(),
  10822. instrumentName: 'core_view',
  10823. instrumentDetails: function(hash) {
  10824. hash.object = this.toString();
  10825. },
  10826. /**
  10827. @private
  10828. Invoked by the view system when this view needs to produce an HTML
  10829. representation. This method will create a new render buffer, if needed,
  10830. then apply any default attributes, such as class names and visibility.
  10831. Finally, the `render()` method is invoked, which is responsible for
  10832. doing the bulk of the rendering.
  10833. You should not need to override this method; instead, implement the
  10834. `template` property, or if you need more control, override the `render`
  10835. method.
  10836. @method renderToBuffer
  10837. @param {Ember.RenderBuffer} buffer the render buffer. If no buffer is
  10838. passed, a default buffer, using the current view's `tagName`, will
  10839. be used.
  10840. */
  10841. renderToBuffer: function(parentBuffer, bufferOperation) {
  10842. var name = 'render.' + this.instrumentName,
  10843. details = {};
  10844. this.instrumentDetails(details);
  10845. return Ember.instrument(name, details, function() {
  10846. return this._renderToBuffer(parentBuffer, bufferOperation);
  10847. }, this);
  10848. },
  10849. _renderToBuffer: function(parentBuffer, bufferOperation) {
  10850. Ember.run.sync();
  10851. // If this is the top-most view, start a new buffer. Otherwise,
  10852. // create a new buffer relative to the original using the
  10853. // provided buffer operation (for example, `insertAfter` will
  10854. // insert a new buffer after the "parent buffer").
  10855. var tagName = this.tagName;
  10856. if (tagName === null || tagName === undefined) {
  10857. tagName = 'div';
  10858. }
  10859. var buffer = this.buffer = parentBuffer && parentBuffer.begin(tagName) || Ember.RenderBuffer(tagName);
  10860. this.transitionTo('inBuffer', false);
  10861. this.beforeRender(buffer);
  10862. this.render(buffer);
  10863. this.afterRender(buffer);
  10864. return buffer;
  10865. },
  10866. /**
  10867. @private
  10868. Override the default event firing from `Ember.Evented` to
  10869. also call methods with the given name.
  10870. @method trigger
  10871. @param name {String}
  10872. */
  10873. trigger: function(name) {
  10874. this._super.apply(this, arguments);
  10875. var method = this[name];
  10876. if (method) {
  10877. var args = [], i, l;
  10878. for (i = 1, l = arguments.length; i < l; i++) {
  10879. args.push(arguments[i]);
  10880. }
  10881. return method.apply(this, args);
  10882. }
  10883. },
  10884. has: function(name) {
  10885. return Ember.typeOf(this[name]) === 'function' || this._super(name);
  10886. },
  10887. willDestroy: function() {
  10888. var parent = this._parentView;
  10889. // destroy the element -- this will avoid each child view destroying
  10890. // the element over and over again...
  10891. if (!this.removedFromDOM) { this.destroyElement(); }
  10892. // remove from parent if found. Don't call removeFromParent,
  10893. // as removeFromParent will try to remove the element from
  10894. // the DOM again.
  10895. if (parent) { parent.removeChild(this); }
  10896. this.transitionTo('destroyed');
  10897. // next remove view from global hash
  10898. if (!this.isVirtual) delete Ember.View.views[this.elementId];
  10899. },
  10900. clearRenderedChildren: Ember.K,
  10901. triggerRecursively: Ember.K,
  10902. invokeRecursively: Ember.K,
  10903. transitionTo: Ember.K,
  10904. destroyElement: Ember.K
  10905. });
  10906. /**
  10907. `Ember.View` is the class in Ember responsible for encapsulating templates of
  10908. HTML content, combining templates with data to render as sections of a page's
  10909. DOM, and registering and responding to user-initiated events.
  10910. ## HTML Tag
  10911. The default HTML tag name used for a view's DOM representation is `div`. This
  10912. can be customized by setting the `tagName` property. The following view
  10913. class:
  10914. ```javascript
  10915. ParagraphView = Ember.View.extend({
  10916. tagName: 'em'
  10917. });
  10918. ```
  10919. Would result in instances with the following HTML:
  10920. ```html
  10921. <em id="ember1" class="ember-view"></em>
  10922. ```
  10923. ## HTML `class` Attribute
  10924. The HTML `class` attribute of a view's tag can be set by providing a
  10925. `classNames` property that is set to an array of strings:
  10926. ```javascript
  10927. MyView = Ember.View.extend({
  10928. classNames: ['my-class', 'my-other-class']
  10929. });
  10930. ```
  10931. Will result in view instances with an HTML representation of:
  10932. ```html
  10933. <div id="ember1" class="ember-view my-class my-other-class"></div>
  10934. ```
  10935. `class` attribute values can also be set by providing a `classNameBindings`
  10936. property set to an array of properties names for the view. The return value
  10937. of these properties will be added as part of the value for the view's `class`
  10938. attribute. These properties can be computed properties:
  10939. ```javascript
  10940. MyView = Ember.View.extend({
  10941. classNameBindings: ['propertyA', 'propertyB'],
  10942. propertyA: 'from-a',
  10943. propertyB: function(){
  10944. if(someLogic){ return 'from-b'; }
  10945. }.property()
  10946. });
  10947. ```
  10948. Will result in view instances with an HTML representation of:
  10949. ```html
  10950. <div id="ember1" class="ember-view from-a from-b"></div>
  10951. ```
  10952. If the value of a class name binding returns a boolean the property name
  10953. itself will be used as the class name if the property is true. The class name
  10954. will not be added if the value is `false` or `undefined`.
  10955. ```javascript
  10956. MyView = Ember.View.extend({
  10957. classNameBindings: ['hovered'],
  10958. hovered: true
  10959. });
  10960. ```
  10961. Will result in view instances with an HTML representation of:
  10962. ```html
  10963. <div id="ember1" class="ember-view hovered"></div>
  10964. ```
  10965. When using boolean class name bindings you can supply a string value other
  10966. than the property name for use as the `class` HTML attribute by appending the
  10967. preferred value after a ":" character when defining the binding:
  10968. ```javascript
  10969. MyView = Ember.View.extend({
  10970. classNameBindings: ['awesome:so-very-cool'],
  10971. awesome: true
  10972. });
  10973. ```
  10974. Will result in view instances with an HTML representation of:
  10975. ```html
  10976. <div id="ember1" class="ember-view so-very-cool"></div>
  10977. ```
  10978. Boolean value class name bindings whose property names are in a
  10979. camelCase-style format will be converted to a dasherized format:
  10980. ```javascript
  10981. MyView = Ember.View.extend({
  10982. classNameBindings: ['isUrgent'],
  10983. isUrgent: true
  10984. });
  10985. ```
  10986. Will result in view instances with an HTML representation of:
  10987. ```html
  10988. <div id="ember1" class="ember-view is-urgent"></div>
  10989. ```
  10990. Class name bindings can also refer to object values that are found by
  10991. traversing a path relative to the view itself:
  10992. ```javascript
  10993. MyView = Ember.View.extend({
  10994. classNameBindings: ['messages.empty']
  10995. messages: Ember.Object.create({
  10996. empty: true
  10997. })
  10998. });
  10999. ```
  11000. Will result in view instances with an HTML representation of:
  11001. ```html
  11002. <div id="ember1" class="ember-view empty"></div>
  11003. ```
  11004. If you want to add a class name for a property which evaluates to true and
  11005. and a different class name if it evaluates to false, you can pass a binding
  11006. like this:
  11007. ```javascript
  11008. // Applies 'enabled' class when isEnabled is true and 'disabled' when isEnabled is false
  11009. Ember.View.create({
  11010. classNameBindings: ['isEnabled:enabled:disabled']
  11011. isEnabled: true
  11012. });
  11013. ```
  11014. Will result in view instances with an HTML representation of:
  11015. ```html
  11016. <div id="ember1" class="ember-view enabled"></div>
  11017. ```
  11018. When isEnabled is `false`, the resulting HTML reprensentation looks like
  11019. this:
  11020. ```html
  11021. <div id="ember1" class="ember-view disabled"></div>
  11022. ```
  11023. This syntax offers the convenience to add a class if a property is `false`:
  11024. ```javascript
  11025. // Applies no class when isEnabled is true and class 'disabled' when isEnabled is false
  11026. Ember.View.create({
  11027. classNameBindings: ['isEnabled::disabled']
  11028. isEnabled: true
  11029. });
  11030. ```
  11031. Will result in view instances with an HTML representation of:
  11032. ```html
  11033. <div id="ember1" class="ember-view"></div>
  11034. ```
  11035. When the `isEnabled` property on the view is set to `false`, it will result
  11036. in view instances with an HTML representation of:
  11037. ```html
  11038. <div id="ember1" class="ember-view disabled"></div>
  11039. ```
  11040. Updates to the the value of a class name binding will result in automatic
  11041. update of the HTML `class` attribute in the view's rendered HTML
  11042. representation. If the value becomes `false` or `undefined` the class name
  11043. will be removed.
  11044. Both `classNames` and `classNameBindings` are concatenated properties. See
  11045. `Ember.Object` documentation for more information about concatenated
  11046. properties.
  11047. ## HTML Attributes
  11048. The HTML attribute section of a view's tag can be set by providing an
  11049. `attributeBindings` property set to an array of property names on the view.
  11050. The return value of these properties will be used as the value of the view's
  11051. HTML associated attribute:
  11052. ```javascript
  11053. AnchorView = Ember.View.extend({
  11054. tagName: 'a',
  11055. attributeBindings: ['href'],
  11056. href: 'http://google.com'
  11057. });
  11058. ```
  11059. Will result in view instances with an HTML representation of:
  11060. ```html
  11061. <a id="ember1" class="ember-view" href="http://google.com"></a>
  11062. ```
  11063. If the return value of an `attributeBindings` monitored property is a boolean
  11064. the property will follow HTML's pattern of repeating the attribute's name as
  11065. its value:
  11066. ```javascript
  11067. MyTextInput = Ember.View.extend({
  11068. tagName: 'input',
  11069. attributeBindings: ['disabled'],
  11070. disabled: true
  11071. });
  11072. ```
  11073. Will result in view instances with an HTML representation of:
  11074. ```html
  11075. <input id="ember1" class="ember-view" disabled="disabled" />
  11076. ```
  11077. `attributeBindings` can refer to computed properties:
  11078. ```javascript
  11079. MyTextInput = Ember.View.extend({
  11080. tagName: 'input',
  11081. attributeBindings: ['disabled'],
  11082. disabled: function(){
  11083. if (someLogic) {
  11084. return true;
  11085. } else {
  11086. return false;
  11087. }
  11088. }.property()
  11089. });
  11090. ```
  11091. Updates to the the property of an attribute binding will result in automatic
  11092. update of the HTML attribute in the view's rendered HTML representation.
  11093. `attributeBindings` is a concatenated property. See `Ember.Object`
  11094. documentation for more information about concatenated properties.
  11095. ## Templates
  11096. The HTML contents of a view's rendered representation are determined by its
  11097. template. Templates can be any function that accepts an optional context
  11098. parameter and returns a string of HTML that will be inserted within the
  11099. view's tag. Most typically in Ember this function will be a compiled
  11100. `Ember.Handlebars` template.
  11101. ```javascript
  11102. AView = Ember.View.extend({
  11103. template: Ember.Handlebars.compile('I am the template')
  11104. });
  11105. ```
  11106. Will result in view instances with an HTML representation of:
  11107. ```html
  11108. <div id="ember1" class="ember-view">I am the template</div>
  11109. ```
  11110. Within an Ember application is more common to define a Handlebars templates as
  11111. part of a page:
  11112. ```html
  11113. <script type='text/x-handlebars' data-template-name='some-template'>
  11114. Hello
  11115. </script>
  11116. ```
  11117. And associate it by name using a view's `templateName` property:
  11118. ```javascript
  11119. AView = Ember.View.extend({
  11120. templateName: 'some-template'
  11121. });
  11122. ```
  11123. Using a value for `templateName` that does not have a Handlebars template
  11124. with a matching `data-template-name` attribute will throw an error.
  11125. Assigning a value to both `template` and `templateName` properties will throw
  11126. an error.
  11127. For views classes that may have a template later defined (e.g. as the block
  11128. portion of a `{{view}}` Handlebars helper call in another template or in
  11129. a subclass), you can provide a `defaultTemplate` property set to compiled
  11130. template function. If a template is not later provided for the view instance
  11131. the `defaultTemplate` value will be used:
  11132. ```javascript
  11133. AView = Ember.View.extend({
  11134. defaultTemplate: Ember.Handlebars.compile('I was the default'),
  11135. template: null,
  11136. templateName: null
  11137. });
  11138. ```
  11139. Will result in instances with an HTML representation of:
  11140. ```html
  11141. <div id="ember1" class="ember-view">I was the default</div>
  11142. ```
  11143. If a `template` or `templateName` is provided it will take precedence over
  11144. `defaultTemplate`:
  11145. ```javascript
  11146. AView = Ember.View.extend({
  11147. defaultTemplate: Ember.Handlebars.compile('I was the default')
  11148. });
  11149. aView = AView.create({
  11150. template: Ember.Handlebars.compile('I was the template, not default')
  11151. });
  11152. ```
  11153. Will result in the following HTML representation when rendered:
  11154. ```html
  11155. <div id="ember1" class="ember-view">I was the template, not default</div>
  11156. ```
  11157. ## View Context
  11158. The default context of the compiled template is the view's controller:
  11159. ```javascript
  11160. AView = Ember.View.extend({
  11161. template: Ember.Handlebars.compile('Hello {{excitedGreeting}}')
  11162. });
  11163. aController = Ember.Object.create({
  11164. firstName: 'Barry',
  11165. excitedGreeting: function(){
  11166. return this.get("content.firstName") + "!!!"
  11167. }.property()
  11168. });
  11169. aView = AView.create({
  11170. controller: aController,
  11171. });
  11172. ```
  11173. Will result in an HTML representation of:
  11174. ```html
  11175. <div id="ember1" class="ember-view">Hello Barry!!!</div>
  11176. ```
  11177. A context can also be explicitly supplied through the view's `context`
  11178. property. If the view has neither `context` nor `controller` properties, the
  11179. `parentView`'s context will be used.
  11180. ## Layouts
  11181. Views can have a secondary template that wraps their main template. Like
  11182. primary templates, layouts can be any function that accepts an optional
  11183. context parameter and returns a string of HTML that will be inserted inside
  11184. view's tag. Views whose HTML element is self closing (e.g. `<input />`)
  11185. cannot have a layout and this property will be ignored.
  11186. Most typically in Ember a layout will be a compiled `Ember.Handlebars`
  11187. template.
  11188. A view's layout can be set directly with the `layout` property or reference
  11189. an existing Handlebars template by name with the `layoutName` property.
  11190. A template used as a layout must contain a single use of the Handlebars
  11191. `{{yield}}` helper. The HTML contents of a view's rendered `template` will be
  11192. inserted at this location:
  11193. ```javascript
  11194. AViewWithLayout = Ember.View.extend({
  11195. layout: Ember.Handlebars.compile("<div class='my-decorative-class'>{{yield}}</div>")
  11196. template: Ember.Handlebars.compile("I got wrapped"),
  11197. });
  11198. ```
  11199. Will result in view instances with an HTML representation of:
  11200. ```html
  11201. <div id="ember1" class="ember-view">
  11202. <div class="my-decorative-class">
  11203. I got wrapped
  11204. </div>
  11205. </div>
  11206. ```
  11207. See `Handlebars.helpers.yield` for more information.
  11208. ## Responding to Browser Events
  11209. Views can respond to user-initiated events in one of three ways: method
  11210. implementation, through an event manager, and through `{{action}}` helper use
  11211. in their template or layout.
  11212. ### Method Implementation
  11213. Views can respond to user-initiated events by implementing a method that
  11214. matches the event name. A `jQuery.Event` object will be passed as the
  11215. argument to this method.
  11216. ```javascript
  11217. AView = Ember.View.extend({
  11218. click: function(event){
  11219. // will be called when when an instance's
  11220. // rendered element is clicked
  11221. }
  11222. });
  11223. ```
  11224. ### Event Managers
  11225. Views can define an object as their `eventManager` property. This object can
  11226. then implement methods that match the desired event names. Matching events
  11227. that occur on the view's rendered HTML or the rendered HTML of any of its DOM
  11228. descendants will trigger this method. A `jQuery.Event` object will be passed
  11229. as the first argument to the method and an `Ember.View` object as the
  11230. second. The `Ember.View` will be the view whose rendered HTML was interacted
  11231. with. This may be the view with the `eventManager` property or one of its
  11232. descendent views.
  11233. ```javascript
  11234. AView = Ember.View.extend({
  11235. eventManager: Ember.Object.create({
  11236. doubleClick: function(event, view){
  11237. // will be called when when an instance's
  11238. // rendered element or any rendering
  11239. // of this views's descendent
  11240. // elements is clicked
  11241. }
  11242. })
  11243. });
  11244. ```
  11245. An event defined for an event manager takes precedence over events of the
  11246. same name handled through methods on the view.
  11247. ```javascript
  11248. AView = Ember.View.extend({
  11249. mouseEnter: function(event){
  11250. // will never trigger.
  11251. },
  11252. eventManager: Ember.Object.create({
  11253. mouseEnter: function(event, view){
  11254. // takes presedence over AView#mouseEnter
  11255. }
  11256. })
  11257. });
  11258. ```
  11259. Similarly a view's event manager will take precedence for events of any views
  11260. rendered as a descendent. A method name that matches an event name will not
  11261. be called if the view instance was rendered inside the HTML representation of
  11262. a view that has an `eventManager` property defined that handles events of the
  11263. name. Events not handled by the event manager will still trigger method calls
  11264. on the descendent.
  11265. ```javascript
  11266. OuterView = Ember.View.extend({
  11267. template: Ember.Handlebars.compile("outer {{#view InnerView}}inner{{/view}} outer"),
  11268. eventManager: Ember.Object.create({
  11269. mouseEnter: function(event, view){
  11270. // view might be instance of either
  11271. // OutsideView or InnerView depending on
  11272. // where on the page the user interaction occured
  11273. }
  11274. })
  11275. });
  11276. InnerView = Ember.View.extend({
  11277. click: function(event){
  11278. // will be called if rendered inside
  11279. // an OuterView because OuterView's
  11280. // eventManager doesn't handle click events
  11281. },
  11282. mouseEnter: function(event){
  11283. // will never be called if rendered inside
  11284. // an OuterView.
  11285. }
  11286. });
  11287. ```
  11288. ### Handlebars `{{action}}` Helper
  11289. See `Handlebars.helpers.action`.
  11290. ### Event Names
  11291. Possible events names for any of the responding approaches described above
  11292. are:
  11293. Touch events:
  11294. * `touchStart`
  11295. * `touchMove`
  11296. * `touchEnd`
  11297. * `touchCancel`
  11298. Keyboard events
  11299. * `keyDown`
  11300. * `keyUp`
  11301. * `keyPress`
  11302. Mouse events
  11303. * `mouseDown`
  11304. * `mouseUp`
  11305. * `contextMenu`
  11306. * `click`
  11307. * `doubleClick`
  11308. * `mouseMove`
  11309. * `focusIn`
  11310. * `focusOut`
  11311. * `mouseEnter`
  11312. * `mouseLeave`
  11313. Form events:
  11314. * `submit`
  11315. * `change`
  11316. * `focusIn`
  11317. * `focusOut`
  11318. * `input`
  11319. HTML5 drag and drop events:
  11320. * `dragStart`
  11321. * `drag`
  11322. * `dragEnter`
  11323. * `dragLeave`
  11324. * `drop`
  11325. * `dragEnd`
  11326. ## Handlebars `{{view}}` Helper
  11327. Other `Ember.View` instances can be included as part of a view's template by
  11328. using the `{{view}}` Handlebars helper. See `Handlebars.helpers.view` for
  11329. additional information.
  11330. @class View
  11331. @namespace Ember
  11332. @extends Ember.Object
  11333. @uses Ember.Evented
  11334. */
  11335. Ember.View = Ember.CoreView.extend(
  11336. /** @scope Ember.View.prototype */ {
  11337. concatenatedProperties: ['classNames', 'classNameBindings', 'attributeBindings'],
  11338. /**
  11339. @property isView
  11340. @type Boolean
  11341. @default true
  11342. @final
  11343. */
  11344. isView: true,
  11345. // ..........................................................
  11346. // TEMPLATE SUPPORT
  11347. //
  11348. /**
  11349. The name of the template to lookup if no template is provided.
  11350. `Ember.View` will look for a template with this name in this view's
  11351. `templates` object. By default, this will be a global object
  11352. shared in `Ember.TEMPLATES`.
  11353. @property templateName
  11354. @type String
  11355. @default null
  11356. */
  11357. templateName: null,
  11358. /**
  11359. The name of the layout to lookup if no layout is provided.
  11360. `Ember.View` will look for a template with this name in this view's
  11361. `templates` object. By default, this will be a global object
  11362. shared in `Ember.TEMPLATES`.
  11363. @property layoutName
  11364. @type String
  11365. @default null
  11366. */
  11367. layoutName: null,
  11368. /**
  11369. The hash in which to look for `templateName`.
  11370. @property templates
  11371. @type Ember.Object
  11372. @default Ember.TEMPLATES
  11373. */
  11374. templates: Ember.TEMPLATES,
  11375. /**
  11376. The template used to render the view. This should be a function that
  11377. accepts an optional context parameter and returns a string of HTML that
  11378. will be inserted into the DOM relative to its parent view.
  11379. In general, you should set the `templateName` property instead of setting
  11380. the template yourself.
  11381. @property template
  11382. @type Function
  11383. */
  11384. template: Ember.computed(function(key, value) {
  11385. if (value !== undefined) { return value; }
  11386. var templateName = get(this, 'templateName'),
  11387. template = this.templateForName(templateName, 'template');
  11388. Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template);
  11389. return template || get(this, 'defaultTemplate');
  11390. }).property('templateName'),
  11391. container: Ember.computed(function() {
  11392. var parentView = get(this, '_parentView');
  11393. if (parentView) { return get(parentView, 'container'); }
  11394. return Ember.Container && Ember.Container.defaultContainer;
  11395. }),
  11396. /**
  11397. The controller managing this view. If this property is set, it will be
  11398. made available for use by the template.
  11399. @property controller
  11400. @type Object
  11401. */
  11402. controller: Ember.computed(function(key) {
  11403. var parentView = get(this, '_parentView');
  11404. return parentView ? get(parentView, 'controller') : null;
  11405. }).property('_parentView'),
  11406. /**
  11407. A view may contain a layout. A layout is a regular template but
  11408. supersedes the `template` property during rendering. It is the
  11409. responsibility of the layout template to retrieve the `template`
  11410. property from the view (or alternatively, call `Handlebars.helpers.yield`,
  11411. `{{yield}}`) to render it in the correct location.
  11412. This is useful for a view that has a shared wrapper, but which delegates
  11413. the rendering of the contents of the wrapper to the `template` property
  11414. on a subclass.
  11415. @property layout
  11416. @type Function
  11417. */
  11418. layout: Ember.computed(function(key) {
  11419. var layoutName = get(this, 'layoutName'),
  11420. layout = this.templateForName(layoutName, 'layout');
  11421. Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || layout);
  11422. return layout || get(this, 'defaultLayout');
  11423. }).property('layoutName'),
  11424. templateForName: function(name, type) {
  11425. if (!name) { return; }
  11426. Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') === -1);
  11427. var container = get(this, 'container');
  11428. if (container) {
  11429. return container.lookup('template:' + name);
  11430. }
  11431. },
  11432. /**
  11433. The object from which templates should access properties.
  11434. This object will be passed to the template function each time the render
  11435. method is called, but it is up to the individual function to decide what
  11436. to do with it.
  11437. By default, this will be the view's controller.
  11438. @property context
  11439. @type Object
  11440. */
  11441. context: Ember.computed(function(key, value) {
  11442. if (arguments.length === 2) {
  11443. set(this, '_context', value);
  11444. return value;
  11445. } else {
  11446. return get(this, '_context');
  11447. }
  11448. }).volatile(),
  11449. /**
  11450. @private
  11451. Private copy of the view's template context. This can be set directly
  11452. by Handlebars without triggering the observer that causes the view
  11453. to be re-rendered.
  11454. The context of a view is looked up as follows:
  11455. 1. Supplied context (usually by Handlebars)
  11456. 2. Specified controller
  11457. 3. `parentView`'s context (for a child of a ContainerView)
  11458. The code in Handlebars that overrides the `_context` property first
  11459. checks to see whether the view has a specified controller. This is
  11460. something of a hack and should be revisited.
  11461. @property _context
  11462. */
  11463. _context: Ember.computed(function(key) {
  11464. var parentView, controller;
  11465. if (controller = get(this, 'controller')) {
  11466. return controller;
  11467. }
  11468. parentView = this._parentView;
  11469. if (parentView) {
  11470. return get(parentView, '_context');
  11471. }
  11472. return null;
  11473. }),
  11474. /**
  11475. @private
  11476. If a value that affects template rendering changes, the view should be
  11477. re-rendered to reflect the new value.
  11478. @method _displayPropertyDidChange
  11479. */
  11480. _contextDidChange: Ember.observer(function() {
  11481. this.rerender();
  11482. }, 'context'),
  11483. /**
  11484. If `false`, the view will appear hidden in DOM.
  11485. @property isVisible
  11486. @type Boolean
  11487. @default null
  11488. */
  11489. isVisible: true,
  11490. /**
  11491. @private
  11492. Array of child views. You should never edit this array directly.
  11493. Instead, use `appendChild` and `removeFromParent`.
  11494. @property childViews
  11495. @type Array
  11496. @default []
  11497. */
  11498. childViews: childViewsProperty,
  11499. _childViews: [],
  11500. // When it's a virtual view, we need to notify the parent that their
  11501. // childViews will change.
  11502. _childViewsWillChange: Ember.beforeObserver(function() {
  11503. if (this.isVirtual) {
  11504. var parentView = get(this, 'parentView');
  11505. if (parentView) { Ember.propertyWillChange(parentView, 'childViews'); }
  11506. }
  11507. }, 'childViews'),
  11508. // When it's a virtual view, we need to notify the parent that their
  11509. // childViews did change.
  11510. _childViewsDidChange: Ember.observer(function() {
  11511. if (this.isVirtual) {
  11512. var parentView = get(this, 'parentView');
  11513. if (parentView) { Ember.propertyDidChange(parentView, 'childViews'); }
  11514. }
  11515. }, 'childViews'),
  11516. /**
  11517. Return the nearest ancestor that is an instance of the provided
  11518. class.
  11519. @property nearestInstanceOf
  11520. @param {Class} klass Subclass of Ember.View (or Ember.View itself)
  11521. @return Ember.View
  11522. @deprecated
  11523. */
  11524. nearestInstanceOf: function(klass) {
  11525. Ember.deprecate("nearestInstanceOf is deprecated and will be removed from future releases. Use nearestOfType.");
  11526. var view = get(this, 'parentView');
  11527. while (view) {
  11528. if(view instanceof klass) { return view; }
  11529. view = get(view, 'parentView');
  11530. }
  11531. },
  11532. /**
  11533. Return the nearest ancestor that is an instance of the provided
  11534. class or mixin.
  11535. @property nearestOfType
  11536. @param {Class,Mixin} klass Subclass of Ember.View (or Ember.View itself),
  11537. or an instance of Ember.Mixin.
  11538. @return Ember.View
  11539. */
  11540. nearestOfType: function(klass) {
  11541. var view = get(this, 'parentView'),
  11542. isOfType = klass instanceof Ember.Mixin ?
  11543. function(view) { return klass.detect(view); } :
  11544. function(view) { return klass.detect(view.constructor); };
  11545. while (view) {
  11546. if( isOfType(view) ) { return view; }
  11547. view = get(view, 'parentView');
  11548. }
  11549. },
  11550. /**
  11551. Return the nearest ancestor that has a given property.
  11552. @property nearestWithProperty
  11553. @param {String} property A property name
  11554. @return Ember.View
  11555. */
  11556. nearestWithProperty: function(property) {
  11557. var view = get(this, 'parentView');
  11558. while (view) {
  11559. if (property in view) { return view; }
  11560. view = get(view, 'parentView');
  11561. }
  11562. },
  11563. /**
  11564. Return the nearest ancestor whose parent is an instance of
  11565. `klass`.
  11566. @property nearestChildOf
  11567. @param {Class} klass Subclass of Ember.View (or Ember.View itself)
  11568. @return Ember.View
  11569. */
  11570. nearestChildOf: function(klass) {
  11571. var view = get(this, 'parentView');
  11572. while (view) {
  11573. if(get(view, 'parentView') instanceof klass) { return view; }
  11574. view = get(view, 'parentView');
  11575. }
  11576. },
  11577. /**
  11578. @private
  11579. When the parent view changes, recursively invalidate `controller`
  11580. @method _parentViewDidChange
  11581. */
  11582. _parentViewDidChange: Ember.observer(function() {
  11583. if (this.isDestroying) { return; }
  11584. if (get(this, 'parentView.controller') && !get(this, 'controller')) {
  11585. this.notifyPropertyChange('controller');
  11586. }
  11587. }, '_parentView'),
  11588. _controllerDidChange: Ember.observer(function() {
  11589. if (this.isDestroying) { return; }
  11590. this.rerender();
  11591. this.forEachChildView(function(view) {
  11592. view.propertyDidChange('controller');
  11593. });
  11594. }, 'controller'),
  11595. cloneKeywords: function() {
  11596. var templateData = get(this, 'templateData');
  11597. var keywords = templateData ? Ember.copy(templateData.keywords) : {};
  11598. set(keywords, 'view', get(this, 'concreteView'));
  11599. set(keywords, '_view', this);
  11600. set(keywords, 'controller', get(this, 'controller'));
  11601. return keywords;
  11602. },
  11603. /**
  11604. Called on your view when it should push strings of HTML into a
  11605. `Ember.RenderBuffer`. Most users will want to override the `template`
  11606. or `templateName` properties instead of this method.
  11607. By default, `Ember.View` will look for a function in the `template`
  11608. property and invoke it with the value of `context`. The value of
  11609. `context` will be the view's controller unless you override it.
  11610. @method render
  11611. @param {Ember.RenderBuffer} buffer The render buffer
  11612. */
  11613. render: function(buffer) {
  11614. // If this view has a layout, it is the responsibility of the
  11615. // the layout to render the view's template. Otherwise, render the template
  11616. // directly.
  11617. var template = get(this, 'layout') || get(this, 'template');
  11618. if (template) {
  11619. var context = get(this, 'context');
  11620. var keywords = this.cloneKeywords();
  11621. var output;
  11622. var data = {
  11623. view: this,
  11624. buffer: buffer,
  11625. isRenderData: true,
  11626. keywords: keywords,
  11627. insideGroup: get(this, 'templateData.insideGroup')
  11628. };
  11629. // Invoke the template with the provided template context, which
  11630. // is the view's controller by default. A hash of data is also passed that provides
  11631. // the template with access to the view and render buffer.
  11632. Ember.assert('template must be a function. Did you mean to call Ember.Handlebars.compile("...") or specify templateName instead?', typeof template === 'function');
  11633. // The template should write directly to the render buffer instead
  11634. // of returning a string.
  11635. output = template(context, { data: data });
  11636. // If the template returned a string instead of writing to the buffer,
  11637. // push the string onto the buffer.
  11638. if (output !== undefined) { buffer.push(output); }
  11639. }
  11640. },
  11641. /**
  11642. Renders the view again. This will work regardless of whether the
  11643. view is already in the DOM or not. If the view is in the DOM, the
  11644. rendering process will be deferred to give bindings a chance
  11645. to synchronize.
  11646. If children were added during the rendering process using `appendChild`,
  11647. `rerender` will remove them, because they will be added again
  11648. if needed by the next `render`.
  11649. In general, if the display of your view changes, you should modify
  11650. the DOM element directly instead of manually calling `rerender`, which can
  11651. be slow.
  11652. @method rerender
  11653. */
  11654. rerender: function() {
  11655. return this.currentState.rerender(this);
  11656. },
  11657. clearRenderedChildren: function() {
  11658. var lengthBefore = this.lengthBeforeRender,
  11659. lengthAfter = this.lengthAfterRender;
  11660. // If there were child views created during the last call to render(),
  11661. // remove them under the assumption that they will be re-created when
  11662. // we re-render.
  11663. // VIEW-TODO: Unit test this path.
  11664. var childViews = this._childViews;
  11665. for (var i=lengthAfter-1; i>=lengthBefore; i--) {
  11666. if (childViews[i]) { childViews[i].destroy(); }
  11667. }
  11668. },
  11669. /**
  11670. @private
  11671. Iterates over the view's `classNameBindings` array, inserts the value
  11672. of the specified property into the `classNames` array, then creates an
  11673. observer to update the view's element if the bound property ever changes
  11674. in the future.
  11675. @method _applyClassNameBindings
  11676. */
  11677. _applyClassNameBindings: function(classBindings) {
  11678. var classNames = this.classNames,
  11679. elem, newClass, dasherizedClass;
  11680. // Loop through all of the configured bindings. These will be either
  11681. // property names ('isUrgent') or property paths relative to the view
  11682. // ('content.isUrgent')
  11683. a_forEach(classBindings, function(binding) {
  11684. // Variable in which the old class value is saved. The observer function
  11685. // closes over this variable, so it knows which string to remove when
  11686. // the property changes.
  11687. var oldClass;
  11688. // Extract just the property name from bindings like 'foo:bar'
  11689. var parsedPath = Ember.View._parsePropertyPath(binding);
  11690. // Set up an observer on the context. If the property changes, toggle the
  11691. // class name.
  11692. var observer = function() {
  11693. // Get the current value of the property
  11694. newClass = this._classStringForProperty(binding);
  11695. elem = this.$();
  11696. // If we had previously added a class to the element, remove it.
  11697. if (oldClass) {
  11698. elem.removeClass(oldClass);
  11699. // Also remove from classNames so that if the view gets rerendered,
  11700. // the class doesn't get added back to the DOM.
  11701. classNames.removeObject(oldClass);
  11702. }
  11703. // If necessary, add a new class. Make sure we keep track of it so
  11704. // it can be removed in the future.
  11705. if (newClass) {
  11706. elem.addClass(newClass);
  11707. oldClass = newClass;
  11708. } else {
  11709. oldClass = null;
  11710. }
  11711. };
  11712. // Get the class name for the property at its current value
  11713. dasherizedClass = this._classStringForProperty(binding);
  11714. if (dasherizedClass) {
  11715. // Ensure that it gets into the classNames array
  11716. // so it is displayed when we render.
  11717. a_addObject(classNames, dasherizedClass);
  11718. // Save a reference to the class name so we can remove it
  11719. // if the observer fires. Remember that this variable has
  11720. // been closed over by the observer.
  11721. oldClass = dasherizedClass;
  11722. }
  11723. this.registerObserver(this, parsedPath.path, observer);
  11724. // Remove className so when the view is rerendered,
  11725. // the className is added based on binding reevaluation
  11726. this.one('willClearRender', function() {
  11727. if (oldClass) {
  11728. classNames.removeObject(oldClass);
  11729. oldClass = null;
  11730. }
  11731. });
  11732. }, this);
  11733. },
  11734. /**
  11735. @private
  11736. Iterates through the view's attribute bindings, sets up observers for each,
  11737. then applies the current value of the attributes to the passed render buffer.
  11738. @method _applyAttributeBindings
  11739. @param {Ember.RenderBuffer} buffer
  11740. */
  11741. _applyAttributeBindings: function(buffer, attributeBindings) {
  11742. var attributeValue, elem, type;
  11743. a_forEach(attributeBindings, function(binding) {
  11744. var split = binding.split(':'),
  11745. property = split[0],
  11746. attributeName = split[1] || property;
  11747. // Create an observer to add/remove/change the attribute if the
  11748. // JavaScript property changes.
  11749. var observer = function() {
  11750. elem = this.$();
  11751. if (!elem) { return; }
  11752. attributeValue = get(this, property);
  11753. Ember.View.applyAttributeBindings(elem, attributeName, attributeValue);
  11754. };
  11755. this.registerObserver(this, property, observer);
  11756. // Determine the current value and add it to the render buffer
  11757. // if necessary.
  11758. attributeValue = get(this, property);
  11759. Ember.View.applyAttributeBindings(buffer, attributeName, attributeValue);
  11760. }, this);
  11761. },
  11762. /**
  11763. @private
  11764. Given a property name, returns a dasherized version of that
  11765. property name if the property evaluates to a non-falsy value.
  11766. For example, if the view has property `isUrgent` that evaluates to true,
  11767. passing `isUrgent` to this method will return `"is-urgent"`.
  11768. @method _classStringForProperty
  11769. @param property
  11770. */
  11771. _classStringForProperty: function(property) {
  11772. var parsedPath = Ember.View._parsePropertyPath(property);
  11773. var path = parsedPath.path;
  11774. var val = get(this, path);
  11775. if (val === undefined && Ember.isGlobalPath(path)) {
  11776. val = get(Ember.lookup, path);
  11777. }
  11778. return Ember.View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName);
  11779. },
  11780. // ..........................................................
  11781. // ELEMENT SUPPORT
  11782. //
  11783. /**
  11784. Returns the current DOM element for the view.
  11785. @property element
  11786. @type DOMElement
  11787. */
  11788. element: Ember.computed(function(key, value) {
  11789. if (value !== undefined) {
  11790. return this.currentState.setElement(this, value);
  11791. } else {
  11792. return this.currentState.getElement(this);
  11793. }
  11794. }).property('_parentView'),
  11795. /**
  11796. Returns a jQuery object for this view's element. If you pass in a selector
  11797. string, this method will return a jQuery object, using the current element
  11798. as its buffer.
  11799. For example, calling `view.$('li')` will return a jQuery object containing
  11800. all of the `li` elements inside the DOM element of this view.
  11801. @property $
  11802. @param {String} [selector] a jQuery-compatible selector string
  11803. @return {jQuery} the CoreQuery object for the DOM node
  11804. */
  11805. $: function(sel) {
  11806. return this.currentState.$(this, sel);
  11807. },
  11808. mutateChildViews: function(callback) {
  11809. var childViews = this._childViews,
  11810. idx = childViews.length,
  11811. view;
  11812. while(--idx >= 0) {
  11813. view = childViews[idx];
  11814. callback.call(this, view, idx);
  11815. }
  11816. return this;
  11817. },
  11818. forEachChildView: function(callback) {
  11819. var childViews = this._childViews;
  11820. if (!childViews) { return this; }
  11821. var len = childViews.length,
  11822. view, idx;
  11823. for(idx = 0; idx < len; idx++) {
  11824. view = childViews[idx];
  11825. callback.call(this, view);
  11826. }
  11827. return this;
  11828. },
  11829. /**
  11830. Appends the view's element to the specified parent element.
  11831. If the view does not have an HTML representation yet, `createElement()`
  11832. will be called automatically.
  11833. Note that this method just schedules the view to be appended; the DOM
  11834. element will not be appended to the given element until all bindings have
  11835. finished synchronizing.
  11836. This is not typically a function that you will need to call directly when
  11837. building your application. You might consider using `Ember.ContainerView`
  11838. instead. If you do need to use `appendTo`, be sure that the target element
  11839. you are providing is associated with an `Ember.Application` and does not
  11840. have an ancestor element that is associated with an Ember view.
  11841. @method appendTo
  11842. @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object
  11843. @return {Ember.View} receiver
  11844. */
  11845. appendTo: function(target) {
  11846. // Schedule the DOM element to be created and appended to the given
  11847. // element after bindings have synchronized.
  11848. this._insertElementLater(function() {
  11849. Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !Ember.$(target).is('.ember-view') && !Ember.$(target).parents().is('.ember-view'));
  11850. this.$().appendTo(target);
  11851. });
  11852. return this;
  11853. },
  11854. /**
  11855. Replaces the content of the specified parent element with this view's
  11856. element. If the view does not have an HTML representation yet,
  11857. `createElement()` will be called automatically.
  11858. Note that this method just schedules the view to be appended; the DOM
  11859. element will not be appended to the given element until all bindings have
  11860. finished synchronizing
  11861. @method replaceIn
  11862. @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object
  11863. @return {Ember.View} received
  11864. */
  11865. replaceIn: function(target) {
  11866. Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !Ember.$(target).is('.ember-view') && !Ember.$(target).parents().is('.ember-view'));
  11867. this._insertElementLater(function() {
  11868. Ember.$(target).empty();
  11869. this.$().appendTo(target);
  11870. });
  11871. return this;
  11872. },
  11873. /**
  11874. @private
  11875. Schedules a DOM operation to occur during the next render phase. This
  11876. ensures that all bindings have finished synchronizing before the view is
  11877. rendered.
  11878. To use, pass a function that performs a DOM operation.
  11879. Before your function is called, this view and all child views will receive
  11880. the `willInsertElement` event. After your function is invoked, this view
  11881. and all of its child views will receive the `didInsertElement` event.
  11882. ```javascript
  11883. view._insertElementLater(function() {
  11884. this.createElement();
  11885. this.$().appendTo('body');
  11886. });
  11887. ```
  11888. @method _insertElementLater
  11889. @param {Function} fn the function that inserts the element into the DOM
  11890. */
  11891. _insertElementLater: function(fn) {
  11892. this._scheduledInsert = Ember.run.scheduleOnce('render', this, '_insertElement', fn);
  11893. },
  11894. _insertElement: function (fn) {
  11895. this._scheduledInsert = null;
  11896. this.currentState.insertElement(this, fn);
  11897. },
  11898. /**
  11899. Appends the view's element to the document body. If the view does
  11900. not have an HTML representation yet, `createElement()` will be called
  11901. automatically.
  11902. Note that this method just schedules the view to be appended; the DOM
  11903. element will not be appended to the document body until all bindings have
  11904. finished synchronizing.
  11905. @method append
  11906. @return {Ember.View} receiver
  11907. */
  11908. append: function() {
  11909. return this.appendTo(document.body);
  11910. },
  11911. /**
  11912. Removes the view's element from the element to which it is attached.
  11913. @method remove
  11914. @return {Ember.View} receiver
  11915. */
  11916. remove: function() {
  11917. // What we should really do here is wait until the end of the run loop
  11918. // to determine if the element has been re-appended to a different
  11919. // element.
  11920. // In the interim, we will just re-render if that happens. It is more
  11921. // important than elements get garbage collected.
  11922. if (!this.removedFromDOM) { this.destroyElement(); }
  11923. this.invokeRecursively(function(view) {
  11924. if (view.clearRenderedChildren) { view.clearRenderedChildren(); }
  11925. });
  11926. },
  11927. elementId: null,
  11928. /**
  11929. Attempts to discover the element in the parent element. The default
  11930. implementation looks for an element with an ID of `elementId` (or the
  11931. view's guid if `elementId` is null). You can override this method to
  11932. provide your own form of lookup. For example, if you want to discover your
  11933. element using a CSS class name instead of an ID.
  11934. @method findElementInParentElement
  11935. @param {DOMElement} parentElement The parent's DOM element
  11936. @return {DOMElement} The discovered element
  11937. */
  11938. findElementInParentElement: function(parentElem) {
  11939. var id = "#" + this.elementId;
  11940. return Ember.$(id)[0] || Ember.$(id, parentElem)[0];
  11941. },
  11942. /**
  11943. Creates a DOM representation of the view and all of its
  11944. child views by recursively calling the `render()` method.
  11945. After the element has been created, `didInsertElement` will
  11946. be called on this view and all of its child views.
  11947. @method createElement
  11948. @return {Ember.View} receiver
  11949. */
  11950. createElement: function() {
  11951. if (get(this, 'element')) { return this; }
  11952. var buffer = this.renderToBuffer();
  11953. set(this, 'element', buffer.element());
  11954. return this;
  11955. },
  11956. /**
  11957. Called when a view is going to insert an element into the DOM.
  11958. @event willInsertElement
  11959. */
  11960. willInsertElement: Ember.K,
  11961. /**
  11962. Called when the element of the view has been inserted into the DOM.
  11963. Override this function to do any set up that requires an element in the
  11964. document body.
  11965. @event didInsertElement
  11966. */
  11967. didInsertElement: Ember.K,
  11968. /**
  11969. Called when the view is about to rerender, but before anything has
  11970. been torn down. This is a good opportunity to tear down any manual
  11971. observers you have installed based on the DOM state
  11972. @event willClearRender
  11973. */
  11974. willClearRender: Ember.K,
  11975. /**
  11976. @private
  11977. Run this callback on the current view and recursively on child views.
  11978. @method invokeRecursively
  11979. @param fn {Function}
  11980. */
  11981. invokeRecursively: function(fn) {
  11982. var childViews = [this], currentViews, view;
  11983. while (childViews.length) {
  11984. currentViews = childViews.slice();
  11985. childViews = [];
  11986. for (var i=0, l=currentViews.length; i<l; i++) {
  11987. view = currentViews[i];
  11988. fn.call(view, view);
  11989. if (view._childViews) {
  11990. childViews.push.apply(childViews, view._childViews);
  11991. }
  11992. }
  11993. }
  11994. },
  11995. triggerRecursively: function(eventName) {
  11996. var childViews = [this], currentViews, view;
  11997. while (childViews.length) {
  11998. currentViews = childViews.slice();
  11999. childViews = [];
  12000. for (var i=0, l=currentViews.length; i<l; i++) {
  12001. view = currentViews[i];
  12002. if (view.trigger) { view.trigger(eventName); }
  12003. if (view._childViews) {
  12004. childViews.push.apply(childViews, view._childViews);
  12005. }
  12006. }
  12007. }
  12008. },
  12009. /**
  12010. Destroys any existing element along with the element for any child views
  12011. as well. If the view does not currently have a element, then this method
  12012. will do nothing.
  12013. If you implement `willDestroyElement()` on your view, then this method will
  12014. be invoked on your view before your element is destroyed to give you a
  12015. chance to clean up any event handlers, etc.
  12016. If you write a `willDestroyElement()` handler, you can assume that your
  12017. `didInsertElement()` handler was called earlier for the same element.
  12018. Normally you will not call or override this method yourself, but you may
  12019. want to implement the above callbacks when it is run.
  12020. @method destroyElement
  12021. @return {Ember.View} receiver
  12022. */
  12023. destroyElement: function() {
  12024. return this.currentState.destroyElement(this);
  12025. },
  12026. /**
  12027. Called when the element of the view is going to be destroyed. Override
  12028. this function to do any teardown that requires an element, like removing
  12029. event listeners.
  12030. @event willDestroyElement
  12031. */
  12032. willDestroyElement: function() {},
  12033. /**
  12034. @private
  12035. Triggers the `willDestroyElement` event (which invokes the
  12036. `willDestroyElement()` method if it exists) on this view and all child
  12037. views.
  12038. Before triggering `willDestroyElement`, it first triggers the
  12039. `willClearRender` event recursively.
  12040. @method _notifyWillDestroyElement
  12041. */
  12042. _notifyWillDestroyElement: function() {
  12043. this.triggerRecursively('willClearRender');
  12044. this.triggerRecursively('willDestroyElement');
  12045. },
  12046. _elementWillChange: Ember.beforeObserver(function() {
  12047. this.forEachChildView(function(view) {
  12048. Ember.propertyWillChange(view, 'element');
  12049. });
  12050. }, 'element'),
  12051. /**
  12052. @private
  12053. If this view's element changes, we need to invalidate the caches of our
  12054. child views so that we do not retain references to DOM elements that are
  12055. no longer needed.
  12056. @method _elementDidChange
  12057. */
  12058. _elementDidChange: Ember.observer(function() {
  12059. this.forEachChildView(function(view) {
  12060. Ember.propertyDidChange(view, 'element');
  12061. });
  12062. }, 'element'),
  12063. /**
  12064. Called when the parentView property has changed.
  12065. @event parentViewDidChange
  12066. */
  12067. parentViewDidChange: Ember.K,
  12068. instrumentName: 'view',
  12069. instrumentDetails: function(hash) {
  12070. hash.template = get(this, 'templateName');
  12071. this._super(hash);
  12072. },
  12073. _renderToBuffer: function(parentBuffer, bufferOperation) {
  12074. this.lengthBeforeRender = this._childViews.length;
  12075. var buffer = this._super(parentBuffer, bufferOperation);
  12076. this.lengthAfterRender = this._childViews.length;
  12077. return buffer;
  12078. },
  12079. renderToBufferIfNeeded: function () {
  12080. return this.currentState.renderToBufferIfNeeded(this, this);
  12081. },
  12082. beforeRender: function(buffer) {
  12083. this.applyAttributesToBuffer(buffer);
  12084. buffer.pushOpeningTag();
  12085. },
  12086. afterRender: function(buffer) {
  12087. buffer.pushClosingTag();
  12088. },
  12089. applyAttributesToBuffer: function(buffer) {
  12090. // Creates observers for all registered class name and attribute bindings,
  12091. // then adds them to the element.
  12092. var classNameBindings = get(this, 'classNameBindings');
  12093. if (classNameBindings.length) {
  12094. this._applyClassNameBindings(classNameBindings);
  12095. }
  12096. // Pass the render buffer so the method can apply attributes directly.
  12097. // This isn't needed for class name bindings because they use the
  12098. // existing classNames infrastructure.
  12099. var attributeBindings = get(this, 'attributeBindings');
  12100. if (attributeBindings.length) {
  12101. this._applyAttributeBindings(buffer, attributeBindings);
  12102. }
  12103. buffer.setClasses(this.classNames);
  12104. buffer.id(this.elementId);
  12105. var role = get(this, 'ariaRole');
  12106. if (role) {
  12107. buffer.attr('role', role);
  12108. }
  12109. if (get(this, 'isVisible') === false) {
  12110. buffer.style('display', 'none');
  12111. }
  12112. },
  12113. // ..........................................................
  12114. // STANDARD RENDER PROPERTIES
  12115. //
  12116. /**
  12117. Tag name for the view's outer element. The tag name is only used when an
  12118. element is first created. If you change the `tagName` for an element, you
  12119. must destroy and recreate the view element.
  12120. By default, the render buffer will use a `<div>` tag for views.
  12121. @property tagName
  12122. @type String
  12123. @default null
  12124. */
  12125. // We leave this null by default so we can tell the difference between
  12126. // the default case and a user-specified tag.
  12127. tagName: null,
  12128. /**
  12129. The WAI-ARIA role of the control represented by this view. For example, a
  12130. button may have a role of type 'button', or a pane may have a role of
  12131. type 'alertdialog'. This property is used by assistive software to help
  12132. visually challenged users navigate rich web applications.
  12133. The full list of valid WAI-ARIA roles is available at:
  12134. http://www.w3.org/TR/wai-aria/roles#roles_categorization
  12135. @property ariaRole
  12136. @type String
  12137. @default null
  12138. */
  12139. ariaRole: null,
  12140. /**
  12141. Standard CSS class names to apply to the view's outer element. This
  12142. property automatically inherits any class names defined by the view's
  12143. superclasses as well.
  12144. @property classNames
  12145. @type Array
  12146. @default ['ember-view']
  12147. */
  12148. classNames: ['ember-view'],
  12149. /**
  12150. A list of properties of the view to apply as class names. If the property
  12151. is a string value, the value of that string will be applied as a class
  12152. name.
  12153. ```javascript
  12154. // Applies the 'high' class to the view element
  12155. Ember.View.create({
  12156. classNameBindings: ['priority']
  12157. priority: 'high'
  12158. });
  12159. ```
  12160. If the value of the property is a Boolean, the name of that property is
  12161. added as a dasherized class name.
  12162. ```javascript
  12163. // Applies the 'is-urgent' class to the view element
  12164. Ember.View.create({
  12165. classNameBindings: ['isUrgent']
  12166. isUrgent: true
  12167. });
  12168. ```
  12169. If you would prefer to use a custom value instead of the dasherized
  12170. property name, you can pass a binding like this:
  12171. ```javascript
  12172. // Applies the 'urgent' class to the view element
  12173. Ember.View.create({
  12174. classNameBindings: ['isUrgent:urgent']
  12175. isUrgent: true
  12176. });
  12177. ```
  12178. This list of properties is inherited from the view's superclasses as well.
  12179. @property classNameBindings
  12180. @type Array
  12181. @default []
  12182. */
  12183. classNameBindings: [],
  12184. /**
  12185. A list of properties of the view to apply as attributes. If the property is
  12186. a string value, the value of that string will be applied as the attribute.
  12187. ```javascript
  12188. // Applies the type attribute to the element
  12189. // with the value "button", like <div type="button">
  12190. Ember.View.create({
  12191. attributeBindings: ['type'],
  12192. type: 'button'
  12193. });
  12194. ```
  12195. If the value of the property is a Boolean, the name of that property is
  12196. added as an attribute.
  12197. ```javascript
  12198. // Renders something like <div enabled="enabled">
  12199. Ember.View.create({
  12200. attributeBindings: ['enabled'],
  12201. enabled: true
  12202. });
  12203. ```
  12204. @property attributeBindings
  12205. */
  12206. attributeBindings: [],
  12207. // .......................................................
  12208. // CORE DISPLAY METHODS
  12209. //
  12210. /**
  12211. @private
  12212. Setup a view, but do not finish waking it up.
  12213. - configure `childViews`
  12214. - register the view with the global views hash, which is used for event
  12215. dispatch
  12216. @method init
  12217. */
  12218. init: function() {
  12219. this.elementId = this.elementId || guidFor(this);
  12220. this._super();
  12221. // setup child views. be sure to clone the child views array first
  12222. this._childViews = this._childViews.slice();
  12223. Ember.assert("Only arrays are allowed for 'classNameBindings'", Ember.typeOf(this.classNameBindings) === 'array');
  12224. this.classNameBindings = Ember.A(this.classNameBindings.slice());
  12225. Ember.assert("Only arrays are allowed for 'classNames'", Ember.typeOf(this.classNames) === 'array');
  12226. this.classNames = Ember.A(this.classNames.slice());
  12227. var viewController = get(this, 'viewController');
  12228. if (viewController) {
  12229. viewController = get(viewController);
  12230. if (viewController) {
  12231. set(viewController, 'view', this);
  12232. }
  12233. }
  12234. },
  12235. appendChild: function(view, options) {
  12236. return this.currentState.appendChild(this, view, options);
  12237. },
  12238. /**
  12239. Removes the child view from the parent view.
  12240. @method removeChild
  12241. @param {Ember.View} view
  12242. @return {Ember.View} receiver
  12243. */
  12244. removeChild: function(view) {
  12245. // If we're destroying, the entire subtree will be
  12246. // freed, and the DOM will be handled separately,
  12247. // so no need to mess with childViews.
  12248. if (this.isDestroying) { return; }
  12249. // update parent node
  12250. set(view, '_parentView', null);
  12251. // remove view from childViews array.
  12252. var childViews = this._childViews;
  12253. Ember.EnumerableUtils.removeObject(childViews, view);
  12254. this.propertyDidChange('childViews'); // HUH?! what happened to will change?
  12255. return this;
  12256. },
  12257. /**
  12258. Removes all children from the `parentView`.
  12259. @method removeAllChildren
  12260. @return {Ember.View} receiver
  12261. */
  12262. removeAllChildren: function() {
  12263. return this.mutateChildViews(function(view) {
  12264. this.removeChild(view);
  12265. });
  12266. },
  12267. destroyAllChildren: function() {
  12268. return this.mutateChildViews(function(view) {
  12269. view.destroy();
  12270. });
  12271. },
  12272. /**
  12273. Removes the view from its `parentView`, if one is found. Otherwise
  12274. does nothing.
  12275. @method removeFromParent
  12276. @return {Ember.View} receiver
  12277. */
  12278. removeFromParent: function() {
  12279. var parent = this._parentView;
  12280. // Remove DOM element from parent
  12281. this.remove();
  12282. if (parent) { parent.removeChild(this); }
  12283. return this;
  12284. },
  12285. /**
  12286. You must call `destroy` on a view to destroy the view (and all of its
  12287. child views). This will remove the view from any parent node, then make
  12288. sure that the DOM element managed by the view can be released by the
  12289. memory manager.
  12290. @method willDestroy
  12291. */
  12292. willDestroy: function() {
  12293. // calling this._super() will nuke computed properties and observers,
  12294. // so collect any information we need before calling super.
  12295. var childViews = this._childViews,
  12296. parent = this._parentView,
  12297. childLen, i;
  12298. // destroy the element -- this will avoid each child view destroying
  12299. // the element over and over again...
  12300. if (!this.removedFromDOM) { this.destroyElement(); }
  12301. childLen = childViews.length;
  12302. for (i=childLen-1; i>=0; i--) {
  12303. childViews[i].removedFromDOM = true;
  12304. }
  12305. // remove from non-virtual parent view if viewName was specified
  12306. if (this.viewName) {
  12307. var nonVirtualParentView = get(this, 'parentView');
  12308. if (nonVirtualParentView) {
  12309. set(nonVirtualParentView, this.viewName, null);
  12310. }
  12311. }
  12312. // remove from parent if found. Don't call removeFromParent,
  12313. // as removeFromParent will try to remove the element from
  12314. // the DOM again.
  12315. if (parent) { parent.removeChild(this); }
  12316. this.transitionTo('destroyed');
  12317. childLen = childViews.length;
  12318. for (i=childLen-1; i>=0; i--) {
  12319. childViews[i].destroy();
  12320. }
  12321. // next remove view from global hash
  12322. if (!this.isVirtual) delete Ember.View.views[get(this, 'elementId')];
  12323. },
  12324. /**
  12325. Instantiates a view to be added to the childViews array during view
  12326. initialization. You generally will not call this method directly unless
  12327. you are overriding `createChildViews()`. Note that this method will
  12328. automatically configure the correct settings on the new view instance to
  12329. act as a child of the parent.
  12330. @method createChildView
  12331. @param {Class} viewClass
  12332. @param {Hash} [attrs] Attributes to add
  12333. @return {Ember.View} new instance
  12334. */
  12335. createChildView: function(view, attrs) {
  12336. if (view.isView && view._parentView === this) { return view; }
  12337. if (Ember.CoreView.detect(view)) {
  12338. attrs = attrs || {};
  12339. attrs._parentView = this;
  12340. attrs.templateData = attrs.templateData || get(this, 'templateData');
  12341. view = view.create(attrs);
  12342. // don't set the property on a virtual view, as they are invisible to
  12343. // consumers of the view API
  12344. if (view.viewName) { set(get(this, 'concreteView'), view.viewName, view); }
  12345. } else {
  12346. Ember.assert('You must pass instance or subclass of View', view.isView);
  12347. if (attrs) {
  12348. view.setProperties(attrs);
  12349. }
  12350. if (!get(view, 'templateData')) {
  12351. set(view, 'templateData', get(this, 'templateData'));
  12352. }
  12353. set(view, '_parentView', this);
  12354. }
  12355. return view;
  12356. },
  12357. becameVisible: Ember.K,
  12358. becameHidden: Ember.K,
  12359. /**
  12360. @private
  12361. When the view's `isVisible` property changes, toggle the visibility
  12362. element of the actual DOM element.
  12363. @method _isVisibleDidChange
  12364. */
  12365. _isVisibleDidChange: Ember.observer(function() {
  12366. var $el = this.$();
  12367. if (!$el) { return; }
  12368. var isVisible = get(this, 'isVisible');
  12369. $el.toggle(isVisible);
  12370. if (this._isAncestorHidden()) { return; }
  12371. if (isVisible) {
  12372. this._notifyBecameVisible();
  12373. } else {
  12374. this._notifyBecameHidden();
  12375. }
  12376. }, 'isVisible'),
  12377. _notifyBecameVisible: function() {
  12378. this.trigger('becameVisible');
  12379. this.forEachChildView(function(view) {
  12380. var isVisible = get(view, 'isVisible');
  12381. if (isVisible || isVisible === null) {
  12382. view._notifyBecameVisible();
  12383. }
  12384. });
  12385. },
  12386. _notifyBecameHidden: function() {
  12387. this.trigger('becameHidden');
  12388. this.forEachChildView(function(view) {
  12389. var isVisible = get(view, 'isVisible');
  12390. if (isVisible || isVisible === null) {
  12391. view._notifyBecameHidden();
  12392. }
  12393. });
  12394. },
  12395. _isAncestorHidden: function() {
  12396. var parent = get(this, 'parentView');
  12397. while (parent) {
  12398. if (get(parent, 'isVisible') === false) { return true; }
  12399. parent = get(parent, 'parentView');
  12400. }
  12401. return false;
  12402. },
  12403. clearBuffer: function() {
  12404. this.invokeRecursively(function(view) {
  12405. view.buffer = null;
  12406. });
  12407. },
  12408. transitionTo: function(state, children) {
  12409. this.currentState = this.states[state];
  12410. this.state = state;
  12411. if (children !== false) {
  12412. this.forEachChildView(function(view) {
  12413. view.transitionTo(state);
  12414. });
  12415. }
  12416. },
  12417. // .......................................................
  12418. // EVENT HANDLING
  12419. //
  12420. /**
  12421. @private
  12422. Handle events from `Ember.EventDispatcher`
  12423. @method handleEvent
  12424. @param eventName {String}
  12425. @param evt {Event}
  12426. */
  12427. handleEvent: function(eventName, evt) {
  12428. return this.currentState.handleEvent(this, eventName, evt);
  12429. },
  12430. registerObserver: function(root, path, target, observer) {
  12431. Ember.addObserver(root, path, target, observer);
  12432. this.one('willClearRender', function() {
  12433. Ember.removeObserver(root, path, target, observer);
  12434. });
  12435. }
  12436. });
  12437. /*
  12438. Describe how the specified actions should behave in the various
  12439. states that a view can exist in. Possible states:
  12440. * preRender: when a view is first instantiated, and after its
  12441. element was destroyed, it is in the preRender state
  12442. * inBuffer: once a view has been rendered, but before it has
  12443. been inserted into the DOM, it is in the inBuffer state
  12444. * inDOM: once a view has been inserted into the DOM it is in
  12445. the inDOM state. A view spends the vast majority of its
  12446. existence in this state.
  12447. * destroyed: once a view has been destroyed (using the destroy
  12448. method), it is in this state. No further actions can be invoked
  12449. on a destroyed view.
  12450. */
  12451. // in the destroyed state, everything is illegal
  12452. // before rendering has begun, all legal manipulations are noops.
  12453. // inside the buffer, legal manipulations are done on the buffer
  12454. // once the view has been inserted into the DOM, legal manipulations
  12455. // are done on the DOM element.
  12456. var DOMManager = {
  12457. prepend: function(view, html) {
  12458. view.$().prepend(html);
  12459. },
  12460. after: function(view, html) {
  12461. view.$().after(html);
  12462. },
  12463. html: function(view, html) {
  12464. view.$().html(html);
  12465. },
  12466. replace: function(view) {
  12467. var element = get(view, 'element');
  12468. set(view, 'element', null);
  12469. view._insertElementLater(function() {
  12470. Ember.$(element).replaceWith(get(view, 'element'));
  12471. });
  12472. },
  12473. remove: function(view) {
  12474. view.$().remove();
  12475. },
  12476. empty: function(view) {
  12477. view.$().empty();
  12478. }
  12479. };
  12480. Ember.View.reopen({
  12481. domManager: DOMManager
  12482. });
  12483. Ember.View.reopenClass({
  12484. /**
  12485. @private
  12486. Parse a path and return an object which holds the parsed properties.
  12487. For example a path like "content.isEnabled:enabled:disabled" wil return the
  12488. following object:
  12489. ```javascript
  12490. {
  12491. path: "content.isEnabled",
  12492. className: "enabled",
  12493. falsyClassName: "disabled",
  12494. classNames: ":enabled:disabled"
  12495. }
  12496. ```
  12497. @method _parsePropertyPath
  12498. @static
  12499. */
  12500. _parsePropertyPath: function(path) {
  12501. var split = path.split(':'),
  12502. propertyPath = split[0],
  12503. classNames = "",
  12504. className,
  12505. falsyClassName;
  12506. // check if the property is defined as prop:class or prop:trueClass:falseClass
  12507. if (split.length > 1) {
  12508. className = split[1];
  12509. if (split.length === 3) { falsyClassName = split[2]; }
  12510. classNames = ':' + className;
  12511. if (falsyClassName) { classNames += ":" + falsyClassName; }
  12512. }
  12513. return {
  12514. path: propertyPath,
  12515. classNames: classNames,
  12516. className: (className === '') ? undefined : className,
  12517. falsyClassName: falsyClassName
  12518. };
  12519. },
  12520. /**
  12521. @private
  12522. Get the class name for a given value, based on the path, optional
  12523. `className` and optional `falsyClassName`.
  12524. - if a `className` or `falsyClassName` has been specified:
  12525. - if the value is truthy and `className` has been specified,
  12526. `className` is returned
  12527. - if the value is falsy and `falsyClassName` has been specified,
  12528. `falsyClassName` is returned
  12529. - otherwise `null` is returned
  12530. - if the value is `true`, the dasherized last part of the supplied path
  12531. is returned
  12532. - if the value is not `false`, `undefined` or `null`, the `value`
  12533. is returned
  12534. - if none of the above rules apply, `null` is returned
  12535. @method _classStringForValue
  12536. @param path
  12537. @param val
  12538. @param className
  12539. @param falsyClassName
  12540. @static
  12541. */
  12542. _classStringForValue: function(path, val, className, falsyClassName) {
  12543. // When using the colon syntax, evaluate the truthiness or falsiness
  12544. // of the value to determine which className to return
  12545. if (className || falsyClassName) {
  12546. if (className && !!val) {
  12547. return className;
  12548. } else if (falsyClassName && !val) {
  12549. return falsyClassName;
  12550. } else {
  12551. return null;
  12552. }
  12553. // If value is a Boolean and true, return the dasherized property
  12554. // name.
  12555. } else if (val === true) {
  12556. // Normalize property path to be suitable for use
  12557. // as a class name. For exaple, content.foo.barBaz
  12558. // becomes bar-baz.
  12559. var parts = path.split('.');
  12560. return Ember.String.dasherize(parts[parts.length-1]);
  12561. // If the value is not false, undefined, or null, return the current
  12562. // value of the property.
  12563. } else if (val !== false && val !== undefined && val !== null) {
  12564. return val;
  12565. // Nothing to display. Return null so that the old class is removed
  12566. // but no new class is added.
  12567. } else {
  12568. return null;
  12569. }
  12570. }
  12571. });
  12572. /**
  12573. Global views hash
  12574. @property views
  12575. @static
  12576. @type Hash
  12577. */
  12578. Ember.View.views = {};
  12579. // If someone overrides the child views computed property when
  12580. // defining their class, we want to be able to process the user's
  12581. // supplied childViews and then restore the original computed property
  12582. // at view initialization time. This happens in Ember.ContainerView's init
  12583. // method.
  12584. Ember.View.childViewsProperty = childViewsProperty;
  12585. Ember.View.applyAttributeBindings = function(elem, name, value) {
  12586. var type = Ember.typeOf(value);
  12587. // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js
  12588. if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) {
  12589. if (value !== elem.attr(name)) {
  12590. elem.attr(name, value);
  12591. }
  12592. } else if (name === 'value' || type === 'boolean') {
  12593. if (value !== elem.prop(name)) {
  12594. // value and booleans should always be properties
  12595. elem.prop(name, value);
  12596. }
  12597. } else if (!value) {
  12598. elem.removeAttr(name);
  12599. }
  12600. };
  12601. Ember.View.states = states;
  12602. })();
  12603. (function() {
  12604. /**
  12605. @module ember
  12606. @submodule ember-views
  12607. */
  12608. var get = Ember.get, set = Ember.set;
  12609. Ember.View.states._default = {
  12610. // appendChild is only legal while rendering the buffer.
  12611. appendChild: function() {
  12612. throw "You can't use appendChild outside of the rendering process";
  12613. },
  12614. $: function() {
  12615. return undefined;
  12616. },
  12617. getElement: function() {
  12618. return null;
  12619. },
  12620. // Handle events from `Ember.EventDispatcher`
  12621. handleEvent: function() {
  12622. return true; // continue event propagation
  12623. },
  12624. destroyElement: function(view) {
  12625. set(view, 'element', null);
  12626. if (view._scheduledInsert) {
  12627. Ember.run.cancel(view._scheduledInsert);
  12628. view._scheduledInsert = null;
  12629. }
  12630. return view;
  12631. },
  12632. renderToBufferIfNeeded: function () {
  12633. return false;
  12634. },
  12635. rerender: Ember.K
  12636. };
  12637. })();
  12638. (function() {
  12639. /**
  12640. @module ember
  12641. @submodule ember-views
  12642. */
  12643. var preRender = Ember.View.states.preRender = Ember.create(Ember.View.states._default);
  12644. Ember.merge(preRender, {
  12645. // a view leaves the preRender state once its element has been
  12646. // created (createElement).
  12647. insertElement: function(view, fn) {
  12648. view.createElement();
  12649. view.triggerRecursively('willInsertElement');
  12650. // after createElement, the view will be in the hasElement state.
  12651. fn.call(view);
  12652. view.transitionTo('inDOM');
  12653. view.triggerRecursively('didInsertElement');
  12654. },
  12655. renderToBufferIfNeeded: function(view) {
  12656. return view.renderToBuffer();
  12657. },
  12658. empty: Ember.K,
  12659. setElement: function(view, value) {
  12660. if (value !== null) {
  12661. view.transitionTo('hasElement');
  12662. }
  12663. return value;
  12664. }
  12665. });
  12666. })();
  12667. (function() {
  12668. /**
  12669. @module ember
  12670. @submodule ember-views
  12671. */
  12672. var get = Ember.get, set = Ember.set, meta = Ember.meta;
  12673. var inBuffer = Ember.View.states.inBuffer = Ember.create(Ember.View.states._default);
  12674. Ember.merge(inBuffer, {
  12675. $: function(view, sel) {
  12676. // if we don't have an element yet, someone calling this.$() is
  12677. // trying to update an element that isn't in the DOM. Instead,
  12678. // rerender the view to allow the render method to reflect the
  12679. // changes.
  12680. view.rerender();
  12681. return Ember.$();
  12682. },
  12683. // when a view is rendered in a buffer, rerendering it simply
  12684. // replaces the existing buffer with a new one
  12685. rerender: function(view) {
  12686. throw new Ember.Error("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.");
  12687. },
  12688. // when a view is rendered in a buffer, appending a child
  12689. // view will render that view and append the resulting
  12690. // buffer into its buffer.
  12691. appendChild: function(view, childView, options) {
  12692. var buffer = view.buffer;
  12693. childView = view.createChildView(childView, options);
  12694. view._childViews.push(childView);
  12695. childView.renderToBuffer(buffer);
  12696. view.propertyDidChange('childViews');
  12697. return childView;
  12698. },
  12699. // when a view is rendered in a buffer, destroying the
  12700. // element will simply destroy the buffer and put the
  12701. // state back into the preRender state.
  12702. destroyElement: function(view) {
  12703. view.clearBuffer();
  12704. view._notifyWillDestroyElement();
  12705. view.transitionTo('preRender');
  12706. return view;
  12707. },
  12708. empty: function() {
  12709. Ember.assert("Emptying a view in the inBuffer state is not allowed and should not happen under normal circumstances. Most likely there is a bug in your application. This may be due to excessive property change notifications.");
  12710. },
  12711. renderToBufferIfNeeded: function (view) {
  12712. return view.buffer;
  12713. },
  12714. // It should be impossible for a rendered view to be scheduled for
  12715. // insertion.
  12716. insertElement: function() {
  12717. throw "You can't insert an element that has already been rendered";
  12718. },
  12719. setElement: function(view, value) {
  12720. if (value === null) {
  12721. view.transitionTo('preRender');
  12722. } else {
  12723. view.clearBuffer();
  12724. view.transitionTo('hasElement');
  12725. }
  12726. return value;
  12727. }
  12728. });
  12729. })();
  12730. (function() {
  12731. /**
  12732. @module ember
  12733. @submodule ember-views
  12734. */
  12735. var get = Ember.get, set = Ember.set, meta = Ember.meta;
  12736. var hasElement = Ember.View.states.hasElement = Ember.create(Ember.View.states._default);
  12737. Ember.merge(hasElement, {
  12738. $: function(view, sel) {
  12739. var elem = get(view, 'element');
  12740. return sel ? Ember.$(sel, elem) : Ember.$(elem);
  12741. },
  12742. getElement: function(view) {
  12743. var parent = get(view, 'parentView');
  12744. if (parent) { parent = get(parent, 'element'); }
  12745. if (parent) { return view.findElementInParentElement(parent); }
  12746. return Ember.$("#" + get(view, 'elementId'))[0];
  12747. },
  12748. setElement: function(view, value) {
  12749. if (value === null) {
  12750. view.transitionTo('preRender');
  12751. } else {
  12752. throw "You cannot set an element to a non-null value when the element is already in the DOM.";
  12753. }
  12754. return value;
  12755. },
  12756. // once the view has been inserted into the DOM, rerendering is
  12757. // deferred to allow bindings to synchronize.
  12758. rerender: function(view) {
  12759. view.triggerRecursively('willClearRender');
  12760. view.clearRenderedChildren();
  12761. view.domManager.replace(view);
  12762. return view;
  12763. },
  12764. // once the view is already in the DOM, destroying it removes it
  12765. // from the DOM, nukes its element, and puts it back into the
  12766. // preRender state if inDOM.
  12767. destroyElement: function(view) {
  12768. view._notifyWillDestroyElement();
  12769. view.domManager.remove(view);
  12770. set(view, 'element', null);
  12771. if (view._scheduledInsert) {
  12772. Ember.run.cancel(view._scheduledInsert);
  12773. view._scheduledInsert = null;
  12774. }
  12775. return view;
  12776. },
  12777. empty: function(view) {
  12778. var _childViews = view._childViews, len, idx;
  12779. if (_childViews) {
  12780. len = _childViews.length;
  12781. for (idx = 0; idx < len; idx++) {
  12782. _childViews[idx]._notifyWillDestroyElement();
  12783. }
  12784. }
  12785. view.domManager.empty(view);
  12786. },
  12787. // Handle events from `Ember.EventDispatcher`
  12788. handleEvent: function(view, eventName, evt) {
  12789. if (view.has(eventName)) {
  12790. // Handler should be able to re-dispatch events, so we don't
  12791. // preventDefault or stopPropagation.
  12792. return view.trigger(eventName, evt);
  12793. } else {
  12794. return true; // continue event propagation
  12795. }
  12796. }
  12797. });
  12798. var inDOM = Ember.View.states.inDOM = Ember.create(hasElement);
  12799. Ember.merge(inDOM, {
  12800. insertElement: function(view, fn) {
  12801. throw "You can't insert an element into the DOM that has already been inserted";
  12802. }
  12803. });
  12804. })();
  12805. (function() {
  12806. /**
  12807. @module ember
  12808. @submodule ember-views
  12809. */
  12810. var destroyedError = "You can't call %@ on a destroyed view", fmt = Ember.String.fmt;
  12811. var destroyed = Ember.View.states.destroyed = Ember.create(Ember.View.states._default);
  12812. Ember.merge(destroyed, {
  12813. appendChild: function() {
  12814. throw fmt(destroyedError, ['appendChild']);
  12815. },
  12816. rerender: function() {
  12817. throw fmt(destroyedError, ['rerender']);
  12818. },
  12819. destroyElement: function() {
  12820. throw fmt(destroyedError, ['destroyElement']);
  12821. },
  12822. empty: function() {
  12823. throw fmt(destroyedError, ['empty']);
  12824. },
  12825. setElement: function() {
  12826. throw fmt(destroyedError, ["set('element', ...)"]);
  12827. },
  12828. renderToBufferIfNeeded: function() {
  12829. throw fmt(destroyedError, ["renderToBufferIfNeeded"]);
  12830. },
  12831. // Since element insertion is scheduled, don't do anything if
  12832. // the view has been destroyed between scheduling and execution
  12833. insertElement: Ember.K
  12834. });
  12835. })();
  12836. (function() {
  12837. Ember.View.cloneStates = function(from) {
  12838. var into = {};
  12839. into._default = {};
  12840. into.preRender = Ember.create(into._default);
  12841. into.destroyed = Ember.create(into._default);
  12842. into.inBuffer = Ember.create(into._default);
  12843. into.hasElement = Ember.create(into._default);
  12844. into.inDOM = Ember.create(into.hasElement);
  12845. var viewState;
  12846. for (var stateName in from) {
  12847. if (!from.hasOwnProperty(stateName)) { continue; }
  12848. Ember.merge(into[stateName], from[stateName]);
  12849. }
  12850. return into;
  12851. };
  12852. })();
  12853. (function() {
  12854. var states = Ember.View.cloneStates(Ember.View.states);
  12855. /**
  12856. @module ember
  12857. @submodule ember-views
  12858. */
  12859. var get = Ember.get, set = Ember.set, meta = Ember.meta;
  12860. var forEach = Ember.EnumerableUtils.forEach;
  12861. /**
  12862. A `ContainerView` is an `Ember.View` subclass that implements `Ember.MutableArray`
  12863. allowing programatic management of its child views.
  12864. ## Setting Initial Child Views
  12865. The initial array of child views can be set in one of two ways. You can
  12866. provide a `childViews` property at creation time that contains instance of
  12867. `Ember.View`:
  12868. ```javascript
  12869. aContainer = Ember.ContainerView.create({
  12870. childViews: [Ember.View.create(), Ember.View.create()]
  12871. });
  12872. ```
  12873. You can also provide a list of property names whose values are instances of
  12874. `Ember.View`:
  12875. ```javascript
  12876. aContainer = Ember.ContainerView.create({
  12877. childViews: ['aView', 'bView', 'cView'],
  12878. aView: Ember.View.create(),
  12879. bView: Ember.View.create(),
  12880. cView: Ember.View.create()
  12881. });
  12882. ```
  12883. The two strategies can be combined:
  12884. ```javascript
  12885. aContainer = Ember.ContainerView.create({
  12886. childViews: ['aView', Ember.View.create()],
  12887. aView: Ember.View.create()
  12888. });
  12889. ```
  12890. Each child view's rendering will be inserted into the container's rendered
  12891. HTML in the same order as its position in the `childViews` property.
  12892. ## Adding and Removing Child Views
  12893. The container view implements `Ember.MutableArray` allowing programatic management of its child views.
  12894. To remove a view, pass that view into a `removeObject` call on the container view.
  12895. Given an empty `<body>` the following code
  12896. ```javascript
  12897. aContainer = Ember.ContainerView.create({
  12898. classNames: ['the-container'],
  12899. childViews: ['aView', 'bView'],
  12900. aView: Ember.View.create({
  12901. template: Ember.Handlebars.compile("A")
  12902. }),
  12903. bView: Ember.View.create({
  12904. template: Ember.Handlebars.compile("B")
  12905. })
  12906. });
  12907. aContainer.appendTo('body');
  12908. ```
  12909. Results in the HTML
  12910. ```html
  12911. <div class="ember-view the-container">
  12912. <div class="ember-view">A</div>
  12913. <div class="ember-view">B</div>
  12914. </div>
  12915. ```
  12916. Removing a view
  12917. ```javascript
  12918. aContainer.toArray(); // [aContainer.aView, aContainer.bView]
  12919. aContainer.removeObject(aContainer.get('bView'));
  12920. aContainer.toArray(); // [aContainer.aView]
  12921. ```
  12922. Will result in the following HTML
  12923. ```html
  12924. <div class="ember-view the-container">
  12925. <div class="ember-view">A</div>
  12926. </div>
  12927. ```
  12928. Similarly, adding a child view is accomplished by adding `Ember.View` instances to the
  12929. container view.
  12930. Given an empty `<body>` the following code
  12931. ```javascript
  12932. aContainer = Ember.ContainerView.create({
  12933. classNames: ['the-container'],
  12934. childViews: ['aView', 'bView'],
  12935. aView: Ember.View.create({
  12936. template: Ember.Handlebars.compile("A")
  12937. }),
  12938. bView: Ember.View.create({
  12939. template: Ember.Handlebars.compile("B")
  12940. })
  12941. });
  12942. aContainer.appendTo('body');
  12943. ```
  12944. Results in the HTML
  12945. ```html
  12946. <div class="ember-view the-container">
  12947. <div class="ember-view">A</div>
  12948. <div class="ember-view">B</div>
  12949. </div>
  12950. ```
  12951. Adding a view
  12952. ```javascript
  12953. AnotherViewClass = Ember.View.extend({
  12954. template: Ember.Handlebars.compile("Another view")
  12955. });
  12956. aContainer.toArray(); // [aContainer.aView, aContainer.bView]
  12957. aContainer.pushObject(AnotherViewClass.create());
  12958. aContainer.toArray(); // [aContainer.aView, aContainer.bView, <AnotherViewClass instance>]
  12959. ```
  12960. Will result in the following HTML
  12961. ```html
  12962. <div class="ember-view the-container">
  12963. <div class="ember-view">A</div>
  12964. <div class="ember-view">B</div>
  12965. <div class="ember-view">Another view</div>
  12966. </div>
  12967. ```
  12968. ## Templates and Layout
  12969. A `template`, `templateName`, `defaultTemplate`, `layout`, `layoutName` or
  12970. `defaultLayout` property on a container view will not result in the template
  12971. or layout being rendered. The HTML contents of a `Ember.ContainerView`'s DOM
  12972. representation will only be the rendered HTML of its child views.
  12973. ## Binding a View to Display
  12974. If you would like to display a single view in your ContainerView, you can set
  12975. its `currentView` property. When the `currentView` property is set to a view
  12976. instance, it will be added to the ContainerView. If the `currentView` property
  12977. is later changed to a different view, the new view will replace the old view.
  12978. If `currentView` is set to `null`, the last `currentView` will be removed.
  12979. This functionality is useful for cases where you want to bind the display of
  12980. a ContainerView to a controller or state manager. For example, you can bind
  12981. the `currentView` of a container to a controller like this:
  12982. ```javascript
  12983. App.appController = Ember.Object.create({
  12984. view: Ember.View.create({
  12985. templateName: 'person_template'
  12986. })
  12987. });
  12988. ```
  12989. ```handlebars
  12990. {{view Ember.ContainerView currentViewBinding="App.appController.view"}}
  12991. ```
  12992. @class ContainerView
  12993. @namespace Ember
  12994. @extends Ember.View
  12995. */
  12996. Ember.ContainerView = Ember.View.extend(Ember.MutableArray, {
  12997. states: states,
  12998. init: function() {
  12999. this._super();
  13000. var childViews = get(this, 'childViews');
  13001. // redefine view's childViews property that was obliterated
  13002. Ember.defineProperty(this, 'childViews', Ember.View.childViewsProperty);
  13003. var _childViews = this._childViews;
  13004. forEach(childViews, function(viewName, idx) {
  13005. var view;
  13006. if ('string' === typeof viewName) {
  13007. view = get(this, viewName);
  13008. view = this.createChildView(view);
  13009. set(this, viewName, view);
  13010. } else {
  13011. view = this.createChildView(viewName);
  13012. }
  13013. _childViews[idx] = view;
  13014. }, this);
  13015. var currentView = get(this, 'currentView');
  13016. if (currentView) {
  13017. _childViews.push(this.createChildView(currentView));
  13018. }
  13019. },
  13020. replace: function(idx, removedCount, addedViews) {
  13021. var addedCount = addedViews ? get(addedViews, 'length') : 0;
  13022. this.arrayContentWillChange(idx, removedCount, addedCount);
  13023. this.childViewsWillChange(this._childViews, idx, removedCount);
  13024. if (addedCount === 0) {
  13025. this._childViews.splice(idx, removedCount) ;
  13026. } else {
  13027. var args = [idx, removedCount].concat(addedViews);
  13028. this._childViews.splice.apply(this._childViews, args);
  13029. }
  13030. this.arrayContentDidChange(idx, removedCount, addedCount);
  13031. this.childViewsDidChange(this._childViews, idx, removedCount, addedCount);
  13032. return this;
  13033. },
  13034. objectAt: function(idx) {
  13035. return this._childViews[idx];
  13036. },
  13037. length: Ember.computed(function () {
  13038. return this._childViews.length;
  13039. }),
  13040. /**
  13041. @private
  13042. Instructs each child view to render to the passed render buffer.
  13043. @method render
  13044. @param {Ember.RenderBuffer} buffer the buffer to render to
  13045. */
  13046. render: function(buffer) {
  13047. this.forEachChildView(function(view) {
  13048. view.renderToBuffer(buffer);
  13049. });
  13050. },
  13051. instrumentName: 'render.container',
  13052. /**
  13053. @private
  13054. When a child view is removed, destroy its element so that
  13055. it is removed from the DOM.
  13056. The array observer that triggers this action is set up in the
  13057. `renderToBuffer` method.
  13058. @method childViewsWillChange
  13059. @param {Ember.Array} views the child views array before mutation
  13060. @param {Number} start the start position of the mutation
  13061. @param {Number} removed the number of child views removed
  13062. **/
  13063. childViewsWillChange: function(views, start, removed) {
  13064. this.propertyWillChange('childViews');
  13065. if (removed > 0) {
  13066. var changedViews = views.slice(start, start+removed);
  13067. // transition to preRender before clearing parentView
  13068. this.currentState.childViewsWillChange(this, views, start, removed);
  13069. this.initializeViews(changedViews, null, null);
  13070. }
  13071. },
  13072. removeChild: function(child) {
  13073. this.removeObject(child);
  13074. return this;
  13075. },
  13076. /**
  13077. @private
  13078. When a child view is added, make sure the DOM gets updated appropriately.
  13079. If the view has already rendered an element, we tell the child view to
  13080. create an element and insert it into the DOM. If the enclosing container
  13081. view has already written to a buffer, but not yet converted that buffer
  13082. into an element, we insert the string representation of the child into the
  13083. appropriate place in the buffer.
  13084. @method childViewsDidChange
  13085. @param {Ember.Array} views the array of child views afte the mutation has occurred
  13086. @param {Number} start the start position of the mutation
  13087. @param {Number} removed the number of child views removed
  13088. @param {Number} the number of child views added
  13089. */
  13090. childViewsDidChange: function(views, start, removed, added) {
  13091. if (added > 0) {
  13092. var changedViews = views.slice(start, start+added);
  13093. this.initializeViews(changedViews, this, get(this, 'templateData'));
  13094. this.currentState.childViewsDidChange(this, views, start, added);
  13095. }
  13096. this.propertyDidChange('childViews');
  13097. },
  13098. initializeViews: function(views, parentView, templateData) {
  13099. forEach(views, function(view) {
  13100. set(view, '_parentView', parentView);
  13101. if (!get(view, 'templateData')) {
  13102. set(view, 'templateData', templateData);
  13103. }
  13104. });
  13105. },
  13106. currentView: null,
  13107. _currentViewWillChange: Ember.beforeObserver(function() {
  13108. var currentView = get(this, 'currentView');
  13109. if (currentView) {
  13110. currentView.destroy();
  13111. }
  13112. }, 'currentView'),
  13113. _currentViewDidChange: Ember.observer(function() {
  13114. var currentView = get(this, 'currentView');
  13115. if (currentView) {
  13116. this.pushObject(currentView);
  13117. }
  13118. }, 'currentView'),
  13119. _ensureChildrenAreInDOM: function () {
  13120. this.currentState.ensureChildrenAreInDOM(this);
  13121. }
  13122. });
  13123. Ember.merge(states._default, {
  13124. childViewsWillChange: Ember.K,
  13125. childViewsDidChange: Ember.K,
  13126. ensureChildrenAreInDOM: Ember.K
  13127. });
  13128. Ember.merge(states.inBuffer, {
  13129. childViewsDidChange: function(parentView, views, start, added) {
  13130. throw new Error('You cannot modify child views while in the inBuffer state');
  13131. }
  13132. });
  13133. Ember.merge(states.hasElement, {
  13134. childViewsWillChange: function(view, views, start, removed) {
  13135. for (var i=start; i<start+removed; i++) {
  13136. views[i].remove();
  13137. }
  13138. },
  13139. childViewsDidChange: function(view, views, start, added) {
  13140. Ember.run.scheduleOnce('render', view, '_ensureChildrenAreInDOM');
  13141. },
  13142. ensureChildrenAreInDOM: function(view) {
  13143. var childViews = view._childViews, i, len, childView, previous, buffer;
  13144. for (i = 0, len = childViews.length; i < len; i++) {
  13145. childView = childViews[i];
  13146. buffer = childView.renderToBufferIfNeeded();
  13147. if (buffer) {
  13148. childView.triggerRecursively('willInsertElement');
  13149. if (previous) {
  13150. previous.domManager.after(previous, buffer.string());
  13151. } else {
  13152. view.domManager.prepend(view, buffer.string());
  13153. }
  13154. childView.transitionTo('inDOM');
  13155. childView.propertyDidChange('element');
  13156. childView.triggerRecursively('didInsertElement');
  13157. }
  13158. previous = childView;
  13159. }
  13160. }
  13161. });
  13162. })();
  13163. (function() {
  13164. /**
  13165. @module ember
  13166. @submodule ember-views
  13167. */
  13168. var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
  13169. /**
  13170. `Ember.CollectionView` is an `Ember.View` descendent responsible for managing
  13171. a collection (an array or array-like object) by maintaing a child view object
  13172. and associated DOM representation for each item in the array and ensuring
  13173. that child views and their associated rendered HTML are updated when items in
  13174. the array are added, removed, or replaced.
  13175. ## Setting content
  13176. The managed collection of objects is referenced as the `Ember.CollectionView`
  13177. instance's `content` property.
  13178. ```javascript
  13179. someItemsView = Ember.CollectionView.create({
  13180. content: ['A', 'B','C']
  13181. })
  13182. ```
  13183. The view for each item in the collection will have its `content` property set
  13184. to the item.
  13185. ## Specifying itemViewClass
  13186. By default the view class for each item in the managed collection will be an
  13187. instance of `Ember.View`. You can supply a different class by setting the
  13188. `CollectionView`'s `itemViewClass` property.
  13189. Given an empty `<body>` and the following code:
  13190. ```javascript
  13191. someItemsView = Ember.CollectionView.create({
  13192. classNames: ['a-collection'],
  13193. content: ['A','B','C'],
  13194. itemViewClass: Ember.View.extend({
  13195. template: Ember.Handlebars.compile("the letter: {{view.content}}")
  13196. })
  13197. });
  13198. someItemsView.appendTo('body');
  13199. ```
  13200. Will result in the following HTML structure
  13201. ```html
  13202. <div class="ember-view a-collection">
  13203. <div class="ember-view">the letter: A</div>
  13204. <div class="ember-view">the letter: B</div>
  13205. <div class="ember-view">the letter: C</div>
  13206. </div>
  13207. ```
  13208. ## Automatic matching of parent/child tagNames
  13209. Setting the `tagName` property of a `CollectionView` to any of
  13210. "ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result
  13211. in the item views receiving an appropriately matched `tagName` property.
  13212. Given an empty `<body>` and the following code:
  13213. ```javascript
  13214. anUndorderedListView = Ember.CollectionView.create({
  13215. tagName: 'ul',
  13216. content: ['A','B','C'],
  13217. itemViewClass: Ember.View.extend({
  13218. template: Ember.Handlebars.compile("the letter: {{view.content}}")
  13219. })
  13220. });
  13221. anUndorderedListView.appendTo('body');
  13222. ```
  13223. Will result in the following HTML structure
  13224. ```html
  13225. <ul class="ember-view a-collection">
  13226. <li class="ember-view">the letter: A</li>
  13227. <li class="ember-view">the letter: B</li>
  13228. <li class="ember-view">the letter: C</li>
  13229. </ul>
  13230. ```
  13231. Additional `tagName` pairs can be provided by adding to
  13232. `Ember.CollectionView.CONTAINER_MAP `
  13233. ```javascript
  13234. Ember.CollectionView.CONTAINER_MAP['article'] = 'section'
  13235. ```
  13236. ## Programatic creation of child views
  13237. For cases where additional customization beyond the use of a single
  13238. `itemViewClass` or `tagName` matching is required CollectionView's
  13239. `createChildView` method can be overidden:
  13240. ```javascript
  13241. CustomCollectionView = Ember.CollectionView.extend({
  13242. createChildView: function(viewClass, attrs) {
  13243. if (attrs.content.kind == 'album') {
  13244. viewClass = App.AlbumView;
  13245. } else {
  13246. viewClass = App.SongView;
  13247. }
  13248. this._super(viewClass, attrs);
  13249. }
  13250. });
  13251. ```
  13252. ## Empty View
  13253. You can provide an `Ember.View` subclass to the `Ember.CollectionView`
  13254. instance as its `emptyView` property. If the `content` property of a
  13255. `CollectionView` is set to `null` or an empty array, an instance of this view
  13256. will be the `CollectionView`s only child.
  13257. ```javascript
  13258. aListWithNothing = Ember.CollectionView.create({
  13259. classNames: ['nothing']
  13260. content: null,
  13261. emptyView: Ember.View.extend({
  13262. template: Ember.Handlebars.compile("The collection is empty")
  13263. })
  13264. });
  13265. aListWithNothing.appendTo('body');
  13266. ```
  13267. Will result in the following HTML structure
  13268. ```html
  13269. <div class="ember-view nothing">
  13270. <div class="ember-view">
  13271. The collection is empty
  13272. </div>
  13273. </div>
  13274. ```
  13275. ## Adding and Removing items
  13276. The `childViews` property of a `CollectionView` should not be directly
  13277. manipulated. Instead, add, remove, replace items from its `content` property.
  13278. This will trigger appropriate changes to its rendered HTML.
  13279. ## Use in templates via the `{{collection}}` `Ember.Handlebars` helper
  13280. `Ember.Handlebars` provides a helper specifically for adding
  13281. `CollectionView`s to templates. See `Ember.Handlebars.collection` for more
  13282. details
  13283. @class CollectionView
  13284. @namespace Ember
  13285. @extends Ember.ContainerView
  13286. @since Ember 0.9
  13287. */
  13288. Ember.CollectionView = Ember.ContainerView.extend(
  13289. /** @scope Ember.CollectionView.prototype */ {
  13290. /**
  13291. A list of items to be displayed by the `Ember.CollectionView`.
  13292. @property content
  13293. @type Ember.Array
  13294. @default null
  13295. */
  13296. content: null,
  13297. /**
  13298. @private
  13299. This provides metadata about what kind of empty view class this
  13300. collection would like if it is being instantiated from another
  13301. system (like Handlebars)
  13302. @property emptyViewClass
  13303. */
  13304. emptyViewClass: Ember.View,
  13305. /**
  13306. An optional view to display if content is set to an empty array.
  13307. @property emptyView
  13308. @type Ember.View
  13309. @default null
  13310. */
  13311. emptyView: null,
  13312. /**
  13313. @property itemViewClass
  13314. @type Ember.View
  13315. @default Ember.View
  13316. */
  13317. itemViewClass: Ember.View,
  13318. init: function() {
  13319. var ret = this._super();
  13320. this._contentDidChange();
  13321. return ret;
  13322. },
  13323. _contentWillChange: Ember.beforeObserver(function() {
  13324. var content = this.get('content');
  13325. if (content) { content.removeArrayObserver(this); }
  13326. var len = content ? get(content, 'length') : 0;
  13327. this.arrayWillChange(content, 0, len);
  13328. }, 'content'),
  13329. /**
  13330. @private
  13331. Check to make sure that the content has changed, and if so,
  13332. update the children directly. This is always scheduled
  13333. asynchronously, to allow the element to be created before
  13334. bindings have synchronized and vice versa.
  13335. @method _contentDidChange
  13336. */
  13337. _contentDidChange: Ember.observer(function() {
  13338. var content = get(this, 'content');
  13339. if (content) {
  13340. Ember.assert(fmt("an Ember.CollectionView's content must implement Ember.Array. You passed %@", [content]), Ember.Array.detect(content));
  13341. content.addArrayObserver(this);
  13342. }
  13343. var len = content ? get(content, 'length') : 0;
  13344. this.arrayDidChange(content, 0, null, len);
  13345. }, 'content'),
  13346. willDestroy: function() {
  13347. var content = get(this, 'content');
  13348. if (content) { content.removeArrayObserver(this); }
  13349. this._super();
  13350. if (this._createdEmptyView) {
  13351. this._createdEmptyView.destroy();
  13352. }
  13353. },
  13354. arrayWillChange: function(content, start, removedCount) {
  13355. // If the contents were empty before and this template collection has an
  13356. // empty view remove it now.
  13357. var emptyView = get(this, 'emptyView');
  13358. if (emptyView && emptyView instanceof Ember.View) {
  13359. emptyView.removeFromParent();
  13360. }
  13361. // Loop through child views that correspond with the removed items.
  13362. // Note that we loop from the end of the array to the beginning because
  13363. // we are mutating it as we go.
  13364. var childViews = this._childViews, childView, idx, len;
  13365. len = this._childViews.length;
  13366. var removingAll = removedCount === len;
  13367. if (removingAll) {
  13368. this.currentState.empty(this);
  13369. }
  13370. for (idx = start + removedCount - 1; idx >= start; idx--) {
  13371. childView = childViews[idx];
  13372. if (removingAll) { childView.removedFromDOM = true; }
  13373. childView.destroy();
  13374. }
  13375. },
  13376. /**
  13377. Called when a mutation to the underlying content array occurs.
  13378. This method will replay that mutation against the views that compose the
  13379. `Ember.CollectionView`, ensuring that the view reflects the model.
  13380. This array observer is added in `contentDidChange`.
  13381. @method arrayDidChange
  13382. @param {Array} addedObjects the objects that were added to the content
  13383. @param {Array} removedObjects the objects that were removed from the content
  13384. @param {Number} changeIndex the index at which the changes occurred
  13385. */
  13386. arrayDidChange: function(content, start, removed, added) {
  13387. var itemViewClass = get(this, 'itemViewClass'),
  13388. addedViews = [], view, item, idx, len, itemTagName;
  13389. if ('string' === typeof itemViewClass) {
  13390. itemViewClass = get(itemViewClass);
  13391. }
  13392. Ember.assert(fmt("itemViewClass must be a subclass of Ember.View, not %@", [itemViewClass]), Ember.View.detect(itemViewClass));
  13393. len = content ? get(content, 'length') : 0;
  13394. if (len) {
  13395. for (idx = start; idx < start+added; idx++) {
  13396. item = content.objectAt(idx);
  13397. view = this.createChildView(itemViewClass, {
  13398. content: item,
  13399. contentIndex: idx
  13400. });
  13401. addedViews.push(view);
  13402. }
  13403. } else {
  13404. var emptyView = get(this, 'emptyView');
  13405. if (!emptyView) { return; }
  13406. var isClass = Ember.CoreView.detect(emptyView);
  13407. emptyView = this.createChildView(emptyView);
  13408. addedViews.push(emptyView);
  13409. set(this, 'emptyView', emptyView);
  13410. if (isClass) { this._createdEmptyView = emptyView; }
  13411. }
  13412. this.replace(start, 0, addedViews);
  13413. },
  13414. createChildView: function(view, attrs) {
  13415. view = this._super(view, attrs);
  13416. var itemTagName = get(view, 'tagName');
  13417. var tagName = (itemTagName === null || itemTagName === undefined) ? Ember.CollectionView.CONTAINER_MAP[get(this, 'tagName')] : itemTagName;
  13418. set(view, 'tagName', tagName);
  13419. return view;
  13420. }
  13421. });
  13422. /**
  13423. A map of parent tags to their default child tags. You can add
  13424. additional parent tags if you want collection views that use
  13425. a particular parent tag to default to a child tag.
  13426. @property CONTAINER_MAP
  13427. @type Hash
  13428. @static
  13429. @final
  13430. */
  13431. Ember.CollectionView.CONTAINER_MAP = {
  13432. ul: 'li',
  13433. ol: 'li',
  13434. table: 'tr',
  13435. thead: 'tr',
  13436. tbody: 'tr',
  13437. tfoot: 'tr',
  13438. tr: 'td',
  13439. select: 'option'
  13440. };
  13441. })();
  13442. (function() {
  13443. })();
  13444. (function() {
  13445. /*globals jQuery*/
  13446. /**
  13447. Ember Views
  13448. @module ember
  13449. @submodule ember-views
  13450. @requires ember-runtime
  13451. @main ember-views
  13452. */
  13453. })();
  13454. (function() {
  13455. define("metamorph",
  13456. [],
  13457. function() {
  13458. "use strict";
  13459. // ==========================================================================
  13460. // Project: metamorph
  13461. // Copyright: ©2011 My Company Inc. All rights reserved.
  13462. // ==========================================================================
  13463. var K = function(){},
  13464. guid = 0,
  13465. document = window.document,
  13466. // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
  13467. supportsRange = ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
  13468. // Internet Explorer prior to 9 does not allow setting innerHTML if the first element
  13469. // is a "zero-scope" element. This problem can be worked around by making
  13470. // the first node an invisible text node. We, like Modernizr, use &shy;
  13471. needsShy = (function(){
  13472. var testEl = document.createElement('div');
  13473. testEl.innerHTML = "<div></div>";
  13474. testEl.firstChild.innerHTML = "<script></script>";
  13475. return testEl.firstChild.innerHTML === '';
  13476. })(),
  13477. // IE 8 (and likely earlier) likes to move whitespace preceeding
  13478. // a script tag to appear after it. This means that we can
  13479. // accidentally remove whitespace when updating a morph.
  13480. movesWhitespace = (function() {
  13481. var testEl = document.createElement('div');
  13482. testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value";
  13483. return testEl.childNodes[0].nodeValue === 'Test:' &&
  13484. testEl.childNodes[2].nodeValue === ' Value';
  13485. })();
  13486. // Constructor that supports either Metamorph('foo') or new
  13487. // Metamorph('foo');
  13488. //
  13489. // Takes a string of HTML as the argument.
  13490. var Metamorph = function(html) {
  13491. var self;
  13492. if (this instanceof Metamorph) {
  13493. self = this;
  13494. } else {
  13495. self = new K();
  13496. }
  13497. self.innerHTML = html;
  13498. var myGuid = 'metamorph-'+(guid++);
  13499. self.start = myGuid + '-start';
  13500. self.end = myGuid + '-end';
  13501. return self;
  13502. };
  13503. K.prototype = Metamorph.prototype;
  13504. var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, afterFunc, prependFunc, startTagFunc, endTagFunc;
  13505. outerHTMLFunc = function() {
  13506. return this.startTag() + this.innerHTML + this.endTag();
  13507. };
  13508. startTagFunc = function() {
  13509. /*
  13510. * We replace chevron by its hex code in order to prevent escaping problems.
  13511. * Check this thread for more explaination:
  13512. * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript
  13513. */
  13514. return "<script id='" + this.start + "' type='text/x-placeholder'>\x3C/script>";
  13515. };
  13516. endTagFunc = function() {
  13517. /*
  13518. * We replace chevron by its hex code in order to prevent escaping problems.
  13519. * Check this thread for more explaination:
  13520. * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript
  13521. */
  13522. return "<script id='" + this.end + "' type='text/x-placeholder'>\x3C/script>";
  13523. };
  13524. // If we have the W3C range API, this process is relatively straight forward.
  13525. if (supportsRange) {
  13526. // Get a range for the current morph. Optionally include the starting and
  13527. // ending placeholders.
  13528. rangeFor = function(morph, outerToo) {
  13529. var range = document.createRange();
  13530. var before = document.getElementById(morph.start);
  13531. var after = document.getElementById(morph.end);
  13532. if (outerToo) {
  13533. range.setStartBefore(before);
  13534. range.setEndAfter(after);
  13535. } else {
  13536. range.setStartAfter(before);
  13537. range.setEndBefore(after);
  13538. }
  13539. return range;
  13540. };
  13541. htmlFunc = function(html, outerToo) {
  13542. // get a range for the current metamorph object
  13543. var range = rangeFor(this, outerToo);
  13544. // delete the contents of the range, which will be the
  13545. // nodes between the starting and ending placeholder.
  13546. range.deleteContents();
  13547. // create a new document fragment for the HTML
  13548. var fragment = range.createContextualFragment(html);
  13549. // insert the fragment into the range
  13550. range.insertNode(fragment);
  13551. };
  13552. removeFunc = function() {
  13553. // get a range for the current metamorph object including
  13554. // the starting and ending placeholders.
  13555. var range = rangeFor(this, true);
  13556. // delete the entire range.
  13557. range.deleteContents();
  13558. };
  13559. appendToFunc = function(node) {
  13560. var range = document.createRange();
  13561. range.setStart(node);
  13562. range.collapse(false);
  13563. var frag = range.createContextualFragment(this.outerHTML());
  13564. node.appendChild(frag);
  13565. };
  13566. afterFunc = function(html) {
  13567. var range = document.createRange();
  13568. var after = document.getElementById(this.end);
  13569. range.setStartAfter(after);
  13570. range.setEndAfter(after);
  13571. var fragment = range.createContextualFragment(html);
  13572. range.insertNode(fragment);
  13573. };
  13574. prependFunc = function(html) {
  13575. var range = document.createRange();
  13576. var start = document.getElementById(this.start);
  13577. range.setStartAfter(start);
  13578. range.setEndAfter(start);
  13579. var fragment = range.createContextualFragment(html);
  13580. range.insertNode(fragment);
  13581. };
  13582. } else {
  13583. /**
  13584. * This code is mostly taken from jQuery, with one exception. In jQuery's case, we
  13585. * have some HTML and we need to figure out how to convert it into some nodes.
  13586. *
  13587. * In this case, jQuery needs to scan the HTML looking for an opening tag and use
  13588. * that as the key for the wrap map. In our case, we know the parent node, and
  13589. * can use its type as the key for the wrap map.
  13590. **/
  13591. var wrapMap = {
  13592. select: [ 1, "<select multiple='multiple'>", "</select>" ],
  13593. fieldset: [ 1, "<fieldset>", "</fieldset>" ],
  13594. table: [ 1, "<table>", "</table>" ],
  13595. tbody: [ 2, "<table><tbody>", "</tbody></table>" ],
  13596. tr: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
  13597. colgroup: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
  13598. map: [ 1, "<map>", "</map>" ],
  13599. _default: [ 0, "", "" ]
  13600. };
  13601. var findChildById = function(element, id) {
  13602. if (element.getAttribute('id') === id) { return element; }
  13603. var len = element.childNodes.length, idx, node, found;
  13604. for (idx=0; idx<len; idx++) {
  13605. node = element.childNodes[idx];
  13606. found = node.nodeType === 1 && findChildById(node, id);
  13607. if (found) { return found; }
  13608. }
  13609. };
  13610. var setInnerHTML = function(element, html) {
  13611. var matches = [];
  13612. if (movesWhitespace) {
  13613. // Right now we only check for script tags with ids with the
  13614. // goal of targeting morphs.
  13615. html = html.replace(/(\s+)(<script id='([^']+)')/g, function(match, spaces, tag, id) {
  13616. matches.push([id, spaces]);
  13617. return tag;
  13618. });
  13619. }
  13620. element.innerHTML = html;
  13621. // If we have to do any whitespace adjustments do them now
  13622. if (matches.length > 0) {
  13623. var len = matches.length, idx;
  13624. for (idx=0; idx<len; idx++) {
  13625. var script = findChildById(element, matches[idx][0]),
  13626. node = document.createTextNode(matches[idx][1]);
  13627. script.parentNode.insertBefore(node, script);
  13628. }
  13629. }
  13630. };
  13631. /**
  13632. * Given a parent node and some HTML, generate a set of nodes. Return the first
  13633. * node, which will allow us to traverse the rest using nextSibling.
  13634. *
  13635. * We need to do this because innerHTML in IE does not really parse the nodes.
  13636. **/
  13637. var firstNodeFor = function(parentNode, html) {
  13638. var arr = wrapMap[parentNode.tagName.toLowerCase()] || wrapMap._default;
  13639. var depth = arr[0], start = arr[1], end = arr[2];
  13640. if (needsShy) { html = '&shy;'+html; }
  13641. var element = document.createElement('div');
  13642. setInnerHTML(element, start + html + end);
  13643. for (var i=0; i<=depth; i++) {
  13644. element = element.firstChild;
  13645. }
  13646. // Look for &shy; to remove it.
  13647. if (needsShy) {
  13648. var shyElement = element;
  13649. // Sometimes we get nameless elements with the shy inside
  13650. while (shyElement.nodeType === 1 && !shyElement.nodeName) {
  13651. shyElement = shyElement.firstChild;
  13652. }
  13653. // At this point it's the actual unicode character.
  13654. if (shyElement.nodeType === 3 && shyElement.nodeValue.charAt(0) === "\u00AD") {
  13655. shyElement.nodeValue = shyElement.nodeValue.slice(1);
  13656. }
  13657. }
  13658. return element;
  13659. };
  13660. /**
  13661. * In some cases, Internet Explorer can create an anonymous node in
  13662. * the hierarchy with no tagName. You can create this scenario via:
  13663. *
  13664. * div = document.createElement("div");
  13665. * div.innerHTML = "<table>&shy<script></script><tr><td>hi</td></tr></table>";
  13666. * div.firstChild.firstChild.tagName //=> ""
  13667. *
  13668. * If our script markers are inside such a node, we need to find that
  13669. * node and use *it* as the marker.
  13670. **/
  13671. var realNode = function(start) {
  13672. while (start.parentNode.tagName === "") {
  13673. start = start.parentNode;
  13674. }
  13675. return start;
  13676. };
  13677. /**
  13678. * When automatically adding a tbody, Internet Explorer inserts the
  13679. * tbody immediately before the first <tr>. Other browsers create it
  13680. * before the first node, no matter what.
  13681. *
  13682. * This means the the following code:
  13683. *
  13684. * div = document.createElement("div");
  13685. * div.innerHTML = "<table><script id='first'></script><tr><td>hi</td></tr><script id='last'></script></table>
  13686. *
  13687. * Generates the following DOM in IE:
  13688. *
  13689. * + div
  13690. * + table
  13691. * - script id='first'
  13692. * + tbody
  13693. * + tr
  13694. * + td
  13695. * - "hi"
  13696. * - script id='last'
  13697. *
  13698. * Which means that the two script tags, even though they were
  13699. * inserted at the same point in the hierarchy in the original
  13700. * HTML, now have different parents.
  13701. *
  13702. * This code reparents the first script tag by making it the tbody's
  13703. * first child.
  13704. **/
  13705. var fixParentage = function(start, end) {
  13706. if (start.parentNode !== end.parentNode) {
  13707. end.parentNode.insertBefore(start, end.parentNode.firstChild);
  13708. }
  13709. };
  13710. htmlFunc = function(html, outerToo) {
  13711. // get the real starting node. see realNode for details.
  13712. var start = realNode(document.getElementById(this.start));
  13713. var end = document.getElementById(this.end);
  13714. var parentNode = end.parentNode;
  13715. var node, nextSibling, last;
  13716. // make sure that the start and end nodes share the same
  13717. // parent. If not, fix it.
  13718. fixParentage(start, end);
  13719. // remove all of the nodes after the starting placeholder and
  13720. // before the ending placeholder.
  13721. node = start.nextSibling;
  13722. while (node) {
  13723. nextSibling = node.nextSibling;
  13724. last = node === end;
  13725. // if this is the last node, and we want to remove it as well,
  13726. // set the `end` node to the next sibling. This is because
  13727. // for the rest of the function, we insert the new nodes
  13728. // before the end (note that insertBefore(node, null) is
  13729. // the same as appendChild(node)).
  13730. //
  13731. // if we do not want to remove it, just break.
  13732. if (last) {
  13733. if (outerToo) { end = node.nextSibling; } else { break; }
  13734. }
  13735. node.parentNode.removeChild(node);
  13736. // if this is the last node and we didn't break before
  13737. // (because we wanted to remove the outer nodes), break
  13738. // now.
  13739. if (last) { break; }
  13740. node = nextSibling;
  13741. }
  13742. // get the first node for the HTML string, even in cases like
  13743. // tables and lists where a simple innerHTML on a div would
  13744. // swallow some of the content.
  13745. node = firstNodeFor(start.parentNode, html);
  13746. // copy the nodes for the HTML between the starting and ending
  13747. // placeholder.
  13748. while (node) {
  13749. nextSibling = node.nextSibling;
  13750. parentNode.insertBefore(node, end);
  13751. node = nextSibling;
  13752. }
  13753. };
  13754. // remove the nodes in the DOM representing this metamorph.
  13755. //
  13756. // this includes the starting and ending placeholders.
  13757. removeFunc = function() {
  13758. var start = realNode(document.getElementById(this.start));
  13759. var end = document.getElementById(this.end);
  13760. this.html('');
  13761. start.parentNode.removeChild(start);
  13762. end.parentNode.removeChild(end);
  13763. };
  13764. appendToFunc = function(parentNode) {
  13765. var node = firstNodeFor(parentNode, this.outerHTML());
  13766. var nextSibling;
  13767. while (node) {
  13768. nextSibling = node.nextSibling;
  13769. parentNode.appendChild(node);
  13770. node = nextSibling;
  13771. }
  13772. };
  13773. afterFunc = function(html) {
  13774. // get the real starting node. see realNode for details.
  13775. var end = document.getElementById(this.end);
  13776. var insertBefore = end.nextSibling;
  13777. var parentNode = end.parentNode;
  13778. var nextSibling;
  13779. var node;
  13780. // get the first node for the HTML string, even in cases like
  13781. // tables and lists where a simple innerHTML on a div would
  13782. // swallow some of the content.
  13783. node = firstNodeFor(parentNode, html);
  13784. // copy the nodes for the HTML between the starting and ending
  13785. // placeholder.
  13786. while (node) {
  13787. nextSibling = node.nextSibling;
  13788. parentNode.insertBefore(node, insertBefore);
  13789. node = nextSibling;
  13790. }
  13791. };
  13792. prependFunc = function(html) {
  13793. var start = document.getElementById(this.start);
  13794. var parentNode = start.parentNode;
  13795. var nextSibling;
  13796. var node;
  13797. node = firstNodeFor(parentNode, html);
  13798. var insertBefore = start.nextSibling;
  13799. while (node) {
  13800. nextSibling = node.nextSibling;
  13801. parentNode.insertBefore(node, insertBefore);
  13802. node = nextSibling;
  13803. }
  13804. };
  13805. }
  13806. Metamorph.prototype.html = function(html) {
  13807. this.checkRemoved();
  13808. if (html === undefined) { return this.innerHTML; }
  13809. htmlFunc.call(this, html);
  13810. this.innerHTML = html;
  13811. };
  13812. Metamorph.prototype.replaceWith = function(html) {
  13813. this.checkRemoved();
  13814. htmlFunc.call(this, html, true);
  13815. };
  13816. Metamorph.prototype.remove = removeFunc;
  13817. Metamorph.prototype.outerHTML = outerHTMLFunc;
  13818. Metamorph.prototype.appendTo = appendToFunc;
  13819. Metamorph.prototype.after = afterFunc;
  13820. Metamorph.prototype.prepend = prependFunc;
  13821. Metamorph.prototype.startTag = startTagFunc;
  13822. Metamorph.prototype.endTag = endTagFunc;
  13823. Metamorph.prototype.isRemoved = function() {
  13824. var before = document.getElementById(this.start);
  13825. var after = document.getElementById(this.end);
  13826. return !before || !after;
  13827. };
  13828. Metamorph.prototype.checkRemoved = function() {
  13829. if (this.isRemoved()) {
  13830. throw new Error("Cannot perform operations on a Metamorph that is not in the DOM.");
  13831. }
  13832. };
  13833. return Metamorph;
  13834. });
  13835. })();
  13836. (function() {
  13837. /**
  13838. @module ember
  13839. @submodule ember-handlebars
  13840. */
  13841. // Eliminate dependency on any Ember to simplify precompilation workflow
  13842. var objectCreate = Object.create || function(parent) {
  13843. function F() {}
  13844. F.prototype = parent;
  13845. return new F();
  13846. };
  13847. var Handlebars = this.Handlebars || Ember.imports.Handlebars;
  13848. Ember.assert("Ember Handlebars requires Handlebars 1.0.0-rc.3 or greater", Handlebars && Handlebars.VERSION.match(/^1\.0\.[0-9](\.rc\.[23456789]+)?/));
  13849. /**
  13850. Prepares the Handlebars templating library for use inside Ember's view
  13851. system.
  13852. The `Ember.Handlebars` object is the standard Handlebars library, extended to
  13853. use Ember's `get()` method instead of direct property access, which allows
  13854. computed properties to be used inside templates.
  13855. To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`.
  13856. This will return a function that can be used by `Ember.View` for rendering.
  13857. @class Handlebars
  13858. @namespace Ember
  13859. */
  13860. Ember.Handlebars = objectCreate(Handlebars);
  13861. /**
  13862. @class helpers
  13863. @namespace Ember.Handlebars
  13864. */
  13865. Ember.Handlebars.helpers = objectCreate(Handlebars.helpers);
  13866. /**
  13867. Override the the opcode compiler and JavaScript compiler for Handlebars.
  13868. @class Compiler
  13869. @namespace Ember.Handlebars
  13870. @private
  13871. @constructor
  13872. */
  13873. Ember.Handlebars.Compiler = function() {};
  13874. // Handlebars.Compiler doesn't exist in runtime-only
  13875. if (Handlebars.Compiler) {
  13876. Ember.Handlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype);
  13877. }
  13878. Ember.Handlebars.Compiler.prototype.compiler = Ember.Handlebars.Compiler;
  13879. /**
  13880. @class JavaScriptCompiler
  13881. @namespace Ember.Handlebars
  13882. @private
  13883. @constructor
  13884. */
  13885. Ember.Handlebars.JavaScriptCompiler = function() {};
  13886. // Handlebars.JavaScriptCompiler doesn't exist in runtime-only
  13887. if (Handlebars.JavaScriptCompiler) {
  13888. Ember.Handlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype);
  13889. Ember.Handlebars.JavaScriptCompiler.prototype.compiler = Ember.Handlebars.JavaScriptCompiler;
  13890. }
  13891. Ember.Handlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars";
  13892. Ember.Handlebars.JavaScriptCompiler.prototype.initializeBuffer = function() {
  13893. return "''";
  13894. };
  13895. /**
  13896. @private
  13897. Override the default buffer for Ember Handlebars. By default, Handlebars
  13898. creates an empty String at the beginning of each invocation and appends to
  13899. it. Ember's Handlebars overrides this to append to a single shared buffer.
  13900. @method appendToBuffer
  13901. @param string {String}
  13902. */
  13903. Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) {
  13904. return "data.buffer.push("+string+");";
  13905. };
  13906. var prefix = "ember" + (+new Date()), incr = 1;
  13907. /**
  13908. @private
  13909. Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that
  13910. all simple mustaches in Ember's Handlebars will also set up an observer to
  13911. keep the DOM up to date when the underlying property changes.
  13912. @method mustache
  13913. @for Ember.Handlebars.Compiler
  13914. @param mustache
  13915. */
  13916. Ember.Handlebars.Compiler.prototype.mustache = function(mustache) {
  13917. if (mustache.isHelper && mustache.id.string === 'control') {
  13918. mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
  13919. mustache.hash.pairs.push(["controlID", new Handlebars.AST.StringNode(prefix + incr++)]);
  13920. } else if (mustache.params.length || mustache.hash) {
  13921. // no changes required
  13922. } else {
  13923. var id = new Handlebars.AST.IdNode(['_triageMustache']);
  13924. // Update the mustache node to include a hash value indicating whether the original node
  13925. // was escaped. This will allow us to properly escape values when the underlying value
  13926. // changes and we need to re-render the value.
  13927. if(!mustache.escaped) {
  13928. mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
  13929. mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]);
  13930. }
  13931. mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped);
  13932. }
  13933. return Handlebars.Compiler.prototype.mustache.call(this, mustache);
  13934. };
  13935. /**
  13936. Used for precompilation of Ember Handlebars templates. This will not be used
  13937. during normal app execution.
  13938. @method precompile
  13939. @for Ember.Handlebars
  13940. @static
  13941. @param {String} string The template to precompile
  13942. */
  13943. Ember.Handlebars.precompile = function(string) {
  13944. var ast = Handlebars.parse(string);
  13945. var options = {
  13946. knownHelpers: {
  13947. action: true,
  13948. unbound: true,
  13949. bindAttr: true,
  13950. template: true,
  13951. view: true,
  13952. _triageMustache: true
  13953. },
  13954. data: true,
  13955. stringParams: true
  13956. };
  13957. var environment = new Ember.Handlebars.Compiler().compile(ast, options);
  13958. return new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
  13959. };
  13960. // We don't support this for Handlebars runtime-only
  13961. if (Handlebars.compile) {
  13962. /**
  13963. The entry point for Ember Handlebars. This replaces the default
  13964. `Handlebars.compile` and turns on template-local data and String
  13965. parameters.
  13966. @method compile
  13967. @for Ember.Handlebars
  13968. @static
  13969. @param {String} string The template to compile
  13970. @return {Function}
  13971. */
  13972. Ember.Handlebars.compile = function(string) {
  13973. var ast = Handlebars.parse(string);
  13974. var options = { data: true, stringParams: true };
  13975. var environment = new Ember.Handlebars.Compiler().compile(ast, options);
  13976. var templateSpec = new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
  13977. return Ember.Handlebars.template(templateSpec);
  13978. };
  13979. }
  13980. })();
  13981. (function() {
  13982. var slice = Array.prototype.slice;
  13983. /**
  13984. @private
  13985. If a path starts with a reserved keyword, returns the root
  13986. that should be used.
  13987. @method normalizePath
  13988. @for Ember
  13989. @param root {Object}
  13990. @param path {String}
  13991. @param data {Hash}
  13992. */
  13993. var normalizePath = Ember.Handlebars.normalizePath = function(root, path, data) {
  13994. var keywords = (data && data.keywords) || {},
  13995. keyword, isKeyword;
  13996. // Get the first segment of the path. For example, if the
  13997. // path is "foo.bar.baz", returns "foo".
  13998. keyword = path.split('.', 1)[0];
  13999. // Test to see if the first path is a keyword that has been
  14000. // passed along in the view's data hash. If so, we will treat
  14001. // that object as the new root.
  14002. if (keywords.hasOwnProperty(keyword)) {
  14003. // Look up the value in the template's data hash.
  14004. root = keywords[keyword];
  14005. isKeyword = true;
  14006. // Handle cases where the entire path is the reserved
  14007. // word. In that case, return the object itself.
  14008. if (path === keyword) {
  14009. path = '';
  14010. } else {
  14011. // Strip the keyword from the path and look up
  14012. // the remainder from the newly found root.
  14013. path = path.substr(keyword.length+1);
  14014. }
  14015. }
  14016. return { root: root, path: path, isKeyword: isKeyword };
  14017. };
  14018. /**
  14019. Lookup both on root and on window. If the path starts with
  14020. a keyword, the corresponding object will be looked up in the
  14021. template's data hash and used to resolve the path.
  14022. @method get
  14023. @for Ember.Handlebars
  14024. @param {Object} root The object to look up the property on
  14025. @param {String} path The path to be lookedup
  14026. @param {Object} options The template's option hash
  14027. */
  14028. var handlebarsGet = Ember.Handlebars.get = function(root, path, options) {
  14029. var data = options && options.data,
  14030. normalizedPath = normalizePath(root, path, data),
  14031. value;
  14032. // In cases where the path begins with a keyword, change the
  14033. // root to the value represented by that keyword, and ensure
  14034. // the path is relative to it.
  14035. root = normalizedPath.root;
  14036. path = normalizedPath.path;
  14037. value = Ember.get(root, path);
  14038. // If the path starts with a capital letter, look it up on Ember.lookup,
  14039. // which defaults to the `window` object in browsers.
  14040. if (value === undefined && root !== Ember.lookup && Ember.isGlobalPath(path)) {
  14041. value = Ember.get(Ember.lookup, path);
  14042. }
  14043. return value;
  14044. };
  14045. Ember.Handlebars.getPath = Ember.deprecateFunc('`Ember.Handlebars.getPath` has been changed to `Ember.Handlebars.get` for consistency.', Ember.Handlebars.get);
  14046. Ember.Handlebars.resolveParams = function(context, params, options) {
  14047. var resolvedParams = [], types = options.types, param, type;
  14048. for (var i=0, l=params.length; i<l; i++) {
  14049. param = params[i];
  14050. type = types[i];
  14051. if (type === 'ID') {
  14052. resolvedParams.push(handlebarsGet(context, param, options));
  14053. } else {
  14054. resolvedParams.push(param);
  14055. }
  14056. }
  14057. return resolvedParams;
  14058. };
  14059. Ember.Handlebars.resolveHash = function(context, hash, options) {
  14060. var resolvedHash = {}, types = options.hashTypes, type;
  14061. for (var key in hash) {
  14062. if (!hash.hasOwnProperty(key)) { continue; }
  14063. type = types[key];
  14064. if (type === 'ID') {
  14065. resolvedHash[key] = handlebarsGet(context, hash[key], options);
  14066. } else {
  14067. resolvedHash[key] = hash[key];
  14068. }
  14069. }
  14070. return resolvedHash;
  14071. };
  14072. /**
  14073. @private
  14074. Registers a helper in Handlebars that will be called if no property with the
  14075. given name can be found on the current context object, and no helper with
  14076. that name is registered.
  14077. This throws an exception with a more helpful error message so the user can
  14078. track down where the problem is happening.
  14079. @method helperMissing
  14080. @for Ember.Handlebars.helpers
  14081. @param {String} path
  14082. @param {Hash} options
  14083. */
  14084. Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
  14085. var error, view = "";
  14086. error = "%@ Handlebars error: Could not find property '%@' on object %@.";
  14087. if (options.data){
  14088. view = options.data.view;
  14089. }
  14090. throw new Ember.Error(Ember.String.fmt(error, [view, path, this]));
  14091. });
  14092. /**
  14093. Register a bound handlebars helper. Bound helpers behave similarly to regular
  14094. handlebars helpers, with the added ability to re-render when the underlying data
  14095. changes.
  14096. ## Simple example
  14097. ```javascript
  14098. Ember.Handlebars.registerBoundHelper('capitalize', function(value) {
  14099. return value.toUpperCase();
  14100. });
  14101. ```
  14102. The above bound helper can be used inside of templates as follows:
  14103. ```handlebars
  14104. {{capitalize name}}
  14105. ```
  14106. In this case, when the `name` property of the template's context changes,
  14107. the rendered value of the helper will update to reflect this change.
  14108. ## Example with options
  14109. Like normal handlebars helpers, bound helpers have access to the options
  14110. passed into the helper call.
  14111. ```javascript
  14112. Ember.Handlebars.registerBoundHelper('repeat', function(value, options) {
  14113. var count = options.hash.count;
  14114. var a = [];
  14115. while(a.length < count){
  14116. a.push(value);
  14117. }
  14118. return a.join('');
  14119. });
  14120. ```
  14121. This helper could be used in a template as follows:
  14122. ```handlebars
  14123. {{repeat text count=3}}
  14124. ```
  14125. ## Example with bound options
  14126. Bound hash options are also supported. Example:
  14127. ```handlebars
  14128. {{repeat text countBinding="numRepeats"}}
  14129. ```
  14130. In this example, count will be bound to the value of
  14131. the `numRepeats` property on the context. If that property
  14132. changes, the helper will be re-rendered.
  14133. ## Example with extra dependencies
  14134. The `Ember.Handlebars.registerBoundHelper` method takes a variable length
  14135. third parameter which indicates extra dependencies on the passed in value.
  14136. This allows the handlebars helper to update when these dependencies change.
  14137. ```javascript
  14138. Ember.Handlebars.registerBoundHelper('capitalizeName', function(value) {
  14139. return value.get('name').toUpperCase();
  14140. }, 'name');
  14141. ```
  14142. ## Example with multiple bound properties
  14143. `Ember.Handlebars.registerBoundHelper` supports binding to
  14144. multiple properties, e.g.:
  14145. ```javascript
  14146. Ember.Handlebars.registerBoundHelper('concatenate', function() {
  14147. var values = arguments[arguments.length - 1];
  14148. return values.join('||');
  14149. });
  14150. ```
  14151. Which allows for template syntax such as {{concatenate prop1 prop2}} or
  14152. {{concatenate prop1 prop2 prop3}}. If any of the properties change,
  14153. the helpr will re-render. Note that dependency keys cannot be
  14154. using in conjunction with multi-property helpers, since it is ambiguous
  14155. which property the dependent keys would belong to.
  14156. ## Use with unbound helper
  14157. The {{unbound}} helper can be used with bound helper invocations
  14158. to render them in their unbound form, e.g.
  14159. ```handlebars
  14160. {{unbound capitalize name}}
  14161. ```
  14162. In this example, if the name property changes, the helper
  14163. will not re-render.
  14164. @method registerBoundHelper
  14165. @for Ember.Handlebars
  14166. @param {String} name
  14167. @param {Function} function
  14168. @param {String} dependentKeys*
  14169. */
  14170. Ember.Handlebars.registerBoundHelper = function(name, fn) {
  14171. var dependentKeys = slice.call(arguments, 2);
  14172. function helper() {
  14173. var properties = slice.call(arguments, 0, -1),
  14174. numProperties = properties.length,
  14175. options = arguments[arguments.length - 1],
  14176. normalizedProperties = [],
  14177. data = options.data,
  14178. hash = options.hash,
  14179. view = data.view,
  14180. currentContext = (options.contexts && options.contexts[0]) || this,
  14181. normalized,
  14182. pathRoot, path,
  14183. loc, hashOption;
  14184. // Detect bound options (e.g. countBinding="otherCount")
  14185. hash.boundOptions = {};
  14186. for (hashOption in hash) {
  14187. if (!hash.hasOwnProperty(hashOption)) { continue; }
  14188. if (Ember.IS_BINDING.test(hashOption) && typeof hash[hashOption] === 'string') {
  14189. // Lop off 'Binding' suffix.
  14190. hash.boundOptions[hashOption.slice(0, -7)] = hash[hashOption];
  14191. }
  14192. }
  14193. // Expose property names on data.properties object.
  14194. data.properties = [];
  14195. for (loc = 0; loc < numProperties; ++loc) {
  14196. data.properties.push(properties[loc]);
  14197. normalizedProperties.push(normalizePath(currentContext, properties[loc], data));
  14198. }
  14199. if (data.isUnbound) {
  14200. return evaluateUnboundHelper(this, fn, normalizedProperties, options);
  14201. }
  14202. if (dependentKeys.length === 0) {
  14203. return evaluateMultiPropertyBoundHelper(currentContext, fn, normalizedProperties, options);
  14204. }
  14205. Ember.assert("Dependent keys can only be used with single-property helpers.", properties.length === 1);
  14206. normalized = normalizedProperties[0];
  14207. pathRoot = normalized.root;
  14208. path = normalized.path;
  14209. var bindView = new Ember._SimpleHandlebarsView(
  14210. path, pathRoot, !options.hash.unescaped, options.data
  14211. );
  14212. bindView.normalizedValue = function() {
  14213. var value = Ember._SimpleHandlebarsView.prototype.normalizedValue.call(bindView);
  14214. return fn.call(view, value, options);
  14215. };
  14216. view.appendChild(bindView);
  14217. view.registerObserver(pathRoot, path, bindView, rerenderBoundHelperView);
  14218. for (var i=0, l=dependentKeys.length; i<l; i++) {
  14219. view.registerObserver(pathRoot, path + '.' + dependentKeys[i], bindView, rerenderBoundHelperView);
  14220. }
  14221. }
  14222. helper._rawFunction = fn;
  14223. Ember.Handlebars.registerHelper(name, helper);
  14224. };
  14225. /**
  14226. @private
  14227. Renders the unbound form of an otherwise bound helper function.
  14228. @param {Function} fn
  14229. @param {Object} context
  14230. @param {Array} normalizedProperties
  14231. @param {String} options
  14232. */
  14233. function evaluateMultiPropertyBoundHelper(context, fn, normalizedProperties, options) {
  14234. var numProperties = normalizedProperties.length,
  14235. self = this,
  14236. data = options.data,
  14237. view = data.view,
  14238. hash = options.hash,
  14239. boundOptions = hash.boundOptions,
  14240. watchedProperties,
  14241. boundOption, bindView, loc, property, len;
  14242. bindView = new Ember._SimpleHandlebarsView(null, null, !hash.unescaped, data);
  14243. bindView.normalizedValue = function() {
  14244. var args = [], value, boundOption;
  14245. // Copy over bound options.
  14246. for (boundOption in boundOptions) {
  14247. if (!boundOptions.hasOwnProperty(boundOption)) { continue; }
  14248. property = normalizePath(context, boundOptions[boundOption], data);
  14249. bindView.path = property.path;
  14250. bindView.pathRoot = property.root;
  14251. hash[boundOption] = Ember._SimpleHandlebarsView.prototype.normalizedValue.call(bindView);
  14252. }
  14253. for (loc = 0; loc < numProperties; ++loc) {
  14254. property = normalizedProperties[loc];
  14255. bindView.path = property.path;
  14256. bindView.pathRoot = property.root;
  14257. args.push(Ember._SimpleHandlebarsView.prototype.normalizedValue.call(bindView));
  14258. }
  14259. args.push(options);
  14260. return fn.apply(context, args);
  14261. };
  14262. view.appendChild(bindView);
  14263. // Assemble liast of watched properties that'll re-render this helper.
  14264. watchedProperties = [];
  14265. for (boundOption in boundOptions) {
  14266. if (boundOptions.hasOwnProperty(boundOption)) {
  14267. watchedProperties.push(normalizePath(context, boundOptions[boundOption], data));
  14268. }
  14269. }
  14270. watchedProperties = watchedProperties.concat(normalizedProperties);
  14271. // Observe each property.
  14272. for (loc = 0, len = watchedProperties.length; loc < len; ++loc) {
  14273. property = watchedProperties[loc];
  14274. view.registerObserver(property.root, property.path, bindView, rerenderBoundHelperView);
  14275. }
  14276. }
  14277. /**
  14278. @private
  14279. An observer function used with bound helpers which
  14280. will schedule a re-render of the _SimpleHandlebarsView
  14281. connected with the helper.
  14282. */
  14283. function rerenderBoundHelperView() {
  14284. Ember.run.scheduleOnce('render', this, 'rerender');
  14285. }
  14286. /**
  14287. @private
  14288. Renders the unbound form of an otherwise bound helper function.
  14289. @param {Function} fn
  14290. @param {Object} context
  14291. @param {Array} normalizedProperties
  14292. @param {String} options
  14293. */
  14294. function evaluateUnboundHelper(context, fn, normalizedProperties, options) {
  14295. var args = [], hash = options.hash, boundOptions = hash.boundOptions, loc, len, property, boundOption;
  14296. for (boundOption in boundOptions) {
  14297. if (!boundOptions.hasOwnProperty(boundOption)) { continue; }
  14298. hash[boundOption] = Ember.Handlebars.get(context, boundOptions[boundOption], options);
  14299. }
  14300. for(loc = 0, len = normalizedProperties.length; loc < len; ++loc) {
  14301. property = normalizedProperties[loc];
  14302. args.push(Ember.Handlebars.get(context, property.path, options));
  14303. }
  14304. args.push(options);
  14305. return fn.apply(context, args);
  14306. }
  14307. /**
  14308. @private
  14309. Overrides Handlebars.template so that we can distinguish
  14310. user-created, top-level templates from inner contexts.
  14311. @method template
  14312. @for Ember.Handlebars
  14313. @param {String} template spec
  14314. */
  14315. Ember.Handlebars.template = function(spec){
  14316. var t = Handlebars.template(spec);
  14317. t.isTop = true;
  14318. return t;
  14319. };
  14320. })();
  14321. (function() {
  14322. /**
  14323. @method htmlSafe
  14324. @for Ember.String
  14325. @static
  14326. */
  14327. Ember.String.htmlSafe = function(str) {
  14328. return new Handlebars.SafeString(str);
  14329. };
  14330. var htmlSafe = Ember.String.htmlSafe;
  14331. if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
  14332. /**
  14333. See {{#crossLink "Ember.String/htmlSafe"}}{{/crossLink}}
  14334. @method htmlSafe
  14335. @for String
  14336. */
  14337. String.prototype.htmlSafe = function() {
  14338. return htmlSafe(this);
  14339. };
  14340. }
  14341. })();
  14342. (function() {
  14343. Ember.Handlebars.resolvePaths = function(options) {
  14344. var ret = [],
  14345. contexts = options.contexts,
  14346. roots = options.roots,
  14347. data = options.data;
  14348. for (var i=0, l=contexts.length; i<l; i++) {
  14349. ret.push( Ember.Handlebars.get(roots[i], contexts[i], { data: data }) );
  14350. }
  14351. return ret;
  14352. };
  14353. })();
  14354. (function() {
  14355. /*jshint newcap:false*/
  14356. /**
  14357. @module ember
  14358. @submodule ember-handlebars
  14359. */
  14360. var set = Ember.set, get = Ember.get;
  14361. var Metamorph = requireModule('metamorph');
  14362. // DOMManager should just abstract dom manipulation between jquery and metamorph
  14363. var DOMManager = {
  14364. remove: function(view) {
  14365. view.morph.remove();
  14366. },
  14367. prepend: function(view, html) {
  14368. view.morph.prepend(html);
  14369. },
  14370. after: function(view, html) {
  14371. view.morph.after(html);
  14372. },
  14373. html: function(view, html) {
  14374. view.morph.html(html);
  14375. },
  14376. // This is messed up.
  14377. replace: function(view) {
  14378. var morph = view.morph;
  14379. view.transitionTo('preRender');
  14380. Ember.run.schedule('render', this, function() {
  14381. if (view.isDestroying) { return; }
  14382. view.clearRenderedChildren();
  14383. var buffer = view.renderToBuffer();
  14384. view.invokeRecursively(function(view) {
  14385. view.propertyDidChange('element');
  14386. });
  14387. view.triggerRecursively('willInsertElement');
  14388. morph.replaceWith(buffer.string());
  14389. view.transitionTo('inDOM');
  14390. view.triggerRecursively('didInsertElement');
  14391. });
  14392. },
  14393. empty: function(view) {
  14394. view.morph.html("");
  14395. }
  14396. };
  14397. // The `morph` and `outerHTML` properties are internal only
  14398. // and not observable.
  14399. /**
  14400. @class _Metamorph
  14401. @namespace Ember
  14402. @extends Ember.Mixin
  14403. @private
  14404. */
  14405. Ember._Metamorph = Ember.Mixin.create({
  14406. isVirtual: true,
  14407. tagName: '',
  14408. instrumentName: 'render.metamorph',
  14409. init: function() {
  14410. this._super();
  14411. this.morph = Metamorph();
  14412. },
  14413. beforeRender: function(buffer) {
  14414. buffer.push(this.morph.startTag());
  14415. buffer.pushOpeningTag();
  14416. },
  14417. afterRender: function(buffer) {
  14418. buffer.pushClosingTag();
  14419. buffer.push(this.morph.endTag());
  14420. },
  14421. createElement: function() {
  14422. var buffer = this.renderToBuffer();
  14423. this.outerHTML = buffer.string();
  14424. this.clearBuffer();
  14425. },
  14426. domManager: DOMManager
  14427. });
  14428. /**
  14429. @class _MetamorphView
  14430. @namespace Ember
  14431. @extends Ember.View
  14432. @uses Ember._Metamorph
  14433. @private
  14434. */
  14435. Ember._MetamorphView = Ember.View.extend(Ember._Metamorph);
  14436. /**
  14437. @class _SimpleMetamorphView
  14438. @namespace Ember
  14439. @extends Ember.View
  14440. @uses Ember._Metamorph
  14441. @private
  14442. */
  14443. Ember._SimpleMetamorphView = Ember.CoreView.extend(Ember._Metamorph);
  14444. })();
  14445. (function() {
  14446. /*globals Handlebars */
  14447. /*jshint newcap:false*/
  14448. /**
  14449. @module ember
  14450. @submodule ember-handlebars
  14451. */
  14452. var get = Ember.get, set = Ember.set, handlebarsGet = Ember.Handlebars.get;
  14453. var Metamorph = requireModule('metamorph');
  14454. function SimpleHandlebarsView(path, pathRoot, isEscaped, templateData) {
  14455. this.path = path;
  14456. this.pathRoot = pathRoot;
  14457. this.isEscaped = isEscaped;
  14458. this.templateData = templateData;
  14459. this.morph = Metamorph();
  14460. this.state = 'preRender';
  14461. this.updateId = null;
  14462. }
  14463. Ember._SimpleHandlebarsView = SimpleHandlebarsView;
  14464. SimpleHandlebarsView.prototype = {
  14465. isVirtual: true,
  14466. isView: true,
  14467. destroy: function () {
  14468. if (this.updateId) {
  14469. Ember.run.cancel(this.updateId);
  14470. this.updateId = null;
  14471. }
  14472. this.morph = null;
  14473. },
  14474. propertyDidChange: Ember.K,
  14475. normalizedValue: function() {
  14476. var path = this.path,
  14477. pathRoot = this.pathRoot,
  14478. result, templateData;
  14479. // Use the pathRoot as the result if no path is provided. This
  14480. // happens if the path is `this`, which gets normalized into
  14481. // a `pathRoot` of the current Handlebars context and a path
  14482. // of `''`.
  14483. if (path === '') {
  14484. result = pathRoot;
  14485. } else {
  14486. templateData = this.templateData;
  14487. result = handlebarsGet(pathRoot, path, { data: templateData });
  14488. }
  14489. return result;
  14490. },
  14491. renderToBuffer: function(buffer) {
  14492. var string = '';
  14493. string += this.morph.startTag();
  14494. string += this.render();
  14495. string += this.morph.endTag();
  14496. buffer.push(string);
  14497. },
  14498. render: function() {
  14499. // If not invoked via a triple-mustache ({{{foo}}}), escape
  14500. // the content of the template.
  14501. var escape = this.isEscaped;
  14502. var result = this.normalizedValue();
  14503. if (result === null || result === undefined) {
  14504. result = "";
  14505. } else if (!(result instanceof Handlebars.SafeString)) {
  14506. result = String(result);
  14507. }
  14508. if (escape) { result = Handlebars.Utils.escapeExpression(result); }
  14509. return result;
  14510. },
  14511. rerender: function() {
  14512. switch(this.state) {
  14513. case 'preRender':
  14514. case 'destroyed':
  14515. break;
  14516. case 'inBuffer':
  14517. throw new Ember.Error("Something you did tried to replace an {{expression}} before it was inserted into the DOM.");
  14518. case 'hasElement':
  14519. case 'inDOM':
  14520. this.updateId = Ember.run.scheduleOnce('render', this, 'update');
  14521. break;
  14522. }
  14523. return this;
  14524. },
  14525. update: function () {
  14526. this.updateId = null;
  14527. this.morph.html(this.render());
  14528. },
  14529. transitionTo: function(state) {
  14530. this.state = state;
  14531. }
  14532. };
  14533. var states = Ember.View.cloneStates(Ember.View.states), merge = Ember.merge;
  14534. merge(states._default, {
  14535. rerenderIfNeeded: Ember.K
  14536. });
  14537. merge(states.inDOM, {
  14538. rerenderIfNeeded: function(view) {
  14539. if (get(view, 'normalizedValue') !== view._lastNormalizedValue) {
  14540. view.rerender();
  14541. }
  14542. }
  14543. });
  14544. /**
  14545. `Ember._HandlebarsBoundView` is a private view created by the Handlebars
  14546. `{{bind}}` helpers that is used to keep track of bound properties.
  14547. Every time a property is bound using a `{{mustache}}`, an anonymous subclass
  14548. of `Ember._HandlebarsBoundView` is created with the appropriate sub-template
  14549. and context set up. When the associated property changes, just the template
  14550. for this view will re-render.
  14551. @class _HandlebarsBoundView
  14552. @namespace Ember
  14553. @extends Ember._MetamorphView
  14554. @private
  14555. */
  14556. Ember._HandlebarsBoundView = Ember._MetamorphView.extend({
  14557. instrumentName: 'render.boundHandlebars',
  14558. states: states,
  14559. /**
  14560. The function used to determine if the `displayTemplate` or
  14561. `inverseTemplate` should be rendered. This should be a function that takes
  14562. a value and returns a Boolean.
  14563. @property shouldDisplayFunc
  14564. @type Function
  14565. @default null
  14566. */
  14567. shouldDisplayFunc: null,
  14568. /**
  14569. Whether the template rendered by this view gets passed the context object
  14570. of its parent template, or gets passed the value of retrieving `path`
  14571. from the `pathRoot`.
  14572. For example, this is true when using the `{{#if}}` helper, because the
  14573. template inside the helper should look up properties relative to the same
  14574. object as outside the block. This would be `false` when used with `{{#with
  14575. foo}}` because the template should receive the object found by evaluating
  14576. `foo`.
  14577. @property preserveContext
  14578. @type Boolean
  14579. @default false
  14580. */
  14581. preserveContext: false,
  14582. /**
  14583. If `preserveContext` is true, this is the object that will be used
  14584. to render the template.
  14585. @property previousContext
  14586. @type Object
  14587. */
  14588. previousContext: null,
  14589. /**
  14590. The template to render when `shouldDisplayFunc` evaluates to `true`.
  14591. @property displayTemplate
  14592. @type Function
  14593. @default null
  14594. */
  14595. displayTemplate: null,
  14596. /**
  14597. The template to render when `shouldDisplayFunc` evaluates to `false`.
  14598. @property inverseTemplate
  14599. @type Function
  14600. @default null
  14601. */
  14602. inverseTemplate: null,
  14603. /**
  14604. The path to look up on `pathRoot` that is passed to
  14605. `shouldDisplayFunc` to determine which template to render.
  14606. In addition, if `preserveContext` is `false,` the object at this path will
  14607. be passed to the template when rendering.
  14608. @property path
  14609. @type String
  14610. @default null
  14611. */
  14612. path: null,
  14613. /**
  14614. The object from which the `path` will be looked up. Sometimes this is the
  14615. same as the `previousContext`, but in cases where this view has been
  14616. generated for paths that start with a keyword such as `view` or
  14617. `controller`, the path root will be that resolved object.
  14618. @property pathRoot
  14619. @type Object
  14620. */
  14621. pathRoot: null,
  14622. normalizedValue: Ember.computed(function() {
  14623. var path = get(this, 'path'),
  14624. pathRoot = get(this, 'pathRoot'),
  14625. valueNormalizer = get(this, 'valueNormalizerFunc'),
  14626. result, templateData;
  14627. // Use the pathRoot as the result if no path is provided. This
  14628. // happens if the path is `this`, which gets normalized into
  14629. // a `pathRoot` of the current Handlebars context and a path
  14630. // of `''`.
  14631. if (path === '') {
  14632. result = pathRoot;
  14633. } else {
  14634. templateData = get(this, 'templateData');
  14635. result = handlebarsGet(pathRoot, path, { data: templateData });
  14636. }
  14637. return valueNormalizer ? valueNormalizer(result) : result;
  14638. }).property('path', 'pathRoot', 'valueNormalizerFunc').volatile(),
  14639. rerenderIfNeeded: function() {
  14640. this.currentState.rerenderIfNeeded(this);
  14641. },
  14642. /**
  14643. Determines which template to invoke, sets up the correct state based on
  14644. that logic, then invokes the default `Ember.View` `render` implementation.
  14645. This method will first look up the `path` key on `pathRoot`,
  14646. then pass that value to the `shouldDisplayFunc` function. If that returns
  14647. `true,` the `displayTemplate` function will be rendered to DOM. Otherwise,
  14648. `inverseTemplate`, if specified, will be rendered.
  14649. For example, if this `Ember._HandlebarsBoundView` represented the `{{#with
  14650. foo}}` helper, it would look up the `foo` property of its context, and
  14651. `shouldDisplayFunc` would always return true. The object found by looking
  14652. up `foo` would be passed to `displayTemplate`.
  14653. @method render
  14654. @param {Ember.RenderBuffer} buffer
  14655. */
  14656. render: function(buffer) {
  14657. // If not invoked via a triple-mustache ({{{foo}}}), escape
  14658. // the content of the template.
  14659. var escape = get(this, 'isEscaped');
  14660. var shouldDisplay = get(this, 'shouldDisplayFunc'),
  14661. preserveContext = get(this, 'preserveContext'),
  14662. context = get(this, 'previousContext');
  14663. var inverseTemplate = get(this, 'inverseTemplate'),
  14664. displayTemplate = get(this, 'displayTemplate');
  14665. var result = get(this, 'normalizedValue');
  14666. this._lastNormalizedValue = result;
  14667. // First, test the conditional to see if we should
  14668. // render the template or not.
  14669. if (shouldDisplay(result)) {
  14670. set(this, 'template', displayTemplate);
  14671. // If we are preserving the context (for example, if this
  14672. // is an #if block, call the template with the same object.
  14673. if (preserveContext) {
  14674. set(this, '_context', context);
  14675. } else {
  14676. // Otherwise, determine if this is a block bind or not.
  14677. // If so, pass the specified object to the template
  14678. if (displayTemplate) {
  14679. set(this, '_context', result);
  14680. } else {
  14681. // This is not a bind block, just push the result of the
  14682. // expression to the render context and return.
  14683. if (result === null || result === undefined) {
  14684. result = "";
  14685. } else if (!(result instanceof Handlebars.SafeString)) {
  14686. result = String(result);
  14687. }
  14688. if (escape) { result = Handlebars.Utils.escapeExpression(result); }
  14689. buffer.push(result);
  14690. return;
  14691. }
  14692. }
  14693. } else if (inverseTemplate) {
  14694. set(this, 'template', inverseTemplate);
  14695. if (preserveContext) {
  14696. set(this, '_context', context);
  14697. } else {
  14698. set(this, '_context', result);
  14699. }
  14700. } else {
  14701. set(this, 'template', function() { return ''; });
  14702. }
  14703. return this._super(buffer);
  14704. }
  14705. });
  14706. })();
  14707. (function() {
  14708. /**
  14709. @module ember
  14710. @submodule ember-handlebars
  14711. */
  14712. var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
  14713. var handlebarsGet = Ember.Handlebars.get, normalizePath = Ember.Handlebars.normalizePath;
  14714. var forEach = Ember.ArrayPolyfills.forEach;
  14715. var EmberHandlebars = Ember.Handlebars, helpers = EmberHandlebars.helpers;
  14716. // Binds a property into the DOM. This will create a hook in DOM that the
  14717. // KVO system will look for and update if the property changes.
  14718. function bind(property, options, preserveContext, shouldDisplay, valueNormalizer, childProperties) {
  14719. var data = options.data,
  14720. fn = options.fn,
  14721. inverse = options.inverse,
  14722. view = data.view,
  14723. currentContext = this,
  14724. normalized, observer, i;
  14725. normalized = normalizePath(currentContext, property, data);
  14726. // Set up observers for observable objects
  14727. if ('object' === typeof this) {
  14728. if (data.insideGroup) {
  14729. observer = function() {
  14730. Ember.run.once(view, 'rerender');
  14731. };
  14732. var template, context, result = handlebarsGet(currentContext, property, options);
  14733. result = valueNormalizer(result);
  14734. context = preserveContext ? currentContext : result;
  14735. if (shouldDisplay(result)) {
  14736. template = fn;
  14737. } else if (inverse) {
  14738. template = inverse;
  14739. }
  14740. template(context, { data: options.data });
  14741. } else {
  14742. // Create the view that will wrap the output of this template/property
  14743. // and add it to the nearest view's childViews array.
  14744. // See the documentation of Ember._HandlebarsBoundView for more.
  14745. var bindView = view.createChildView(Ember._HandlebarsBoundView, {
  14746. preserveContext: preserveContext,
  14747. shouldDisplayFunc: shouldDisplay,
  14748. valueNormalizerFunc: valueNormalizer,
  14749. displayTemplate: fn,
  14750. inverseTemplate: inverse,
  14751. path: property,
  14752. pathRoot: currentContext,
  14753. previousContext: currentContext,
  14754. isEscaped: !options.hash.unescaped,
  14755. templateData: options.data
  14756. });
  14757. view.appendChild(bindView);
  14758. observer = function() {
  14759. Ember.run.scheduleOnce('render', bindView, 'rerenderIfNeeded');
  14760. };
  14761. }
  14762. // Observes the given property on the context and
  14763. // tells the Ember._HandlebarsBoundView to re-render. If property
  14764. // is an empty string, we are printing the current context
  14765. // object ({{this}}) so updating it is not our responsibility.
  14766. if (normalized.path !== '') {
  14767. view.registerObserver(normalized.root, normalized.path, observer);
  14768. if (childProperties) {
  14769. for (i=0; i<childProperties.length; i++) {
  14770. view.registerObserver(normalized.root, normalized.path+'.'+childProperties[i], observer);
  14771. }
  14772. }
  14773. }
  14774. } else {
  14775. // The object is not observable, so just render it out and
  14776. // be done with it.
  14777. data.buffer.push(handlebarsGet(currentContext, property, options));
  14778. }
  14779. }
  14780. function simpleBind(property, options) {
  14781. var data = options.data,
  14782. view = data.view,
  14783. currentContext = this,
  14784. normalized, observer;
  14785. normalized = normalizePath(currentContext, property, data);
  14786. // Set up observers for observable objects
  14787. if ('object' === typeof this) {
  14788. if (data.insideGroup) {
  14789. observer = function() {
  14790. Ember.run.once(view, 'rerender');
  14791. };
  14792. var result = handlebarsGet(currentContext, property, options);
  14793. if (result === null || result === undefined) { result = ""; }
  14794. data.buffer.push(result);
  14795. } else {
  14796. var bindView = new Ember._SimpleHandlebarsView(
  14797. property, currentContext, !options.hash.unescaped, options.data
  14798. );
  14799. bindView._parentView = view;
  14800. view.appendChild(bindView);
  14801. observer = function() {
  14802. Ember.run.scheduleOnce('render', bindView, 'rerender');
  14803. };
  14804. }
  14805. // Observes the given property on the context and
  14806. // tells the Ember._HandlebarsBoundView to re-render. If property
  14807. // is an empty string, we are printing the current context
  14808. // object ({{this}}) so updating it is not our responsibility.
  14809. if (normalized.path !== '') {
  14810. view.registerObserver(normalized.root, normalized.path, observer);
  14811. }
  14812. } else {
  14813. // The object is not observable, so just render it out and
  14814. // be done with it.
  14815. data.buffer.push(handlebarsGet(currentContext, property, options));
  14816. }
  14817. }
  14818. /**
  14819. @private
  14820. '_triageMustache' is used internally select between a binding and helper for
  14821. the given context. Until this point, it would be hard to determine if the
  14822. mustache is a property reference or a regular helper reference. This triage
  14823. helper resolves that.
  14824. This would not be typically invoked by directly.
  14825. @method _triageMustache
  14826. @for Ember.Handlebars.helpers
  14827. @param {String} property Property/helperID to triage
  14828. @param {Function} fn Context to provide for rendering
  14829. @return {String} HTML string
  14830. */
  14831. EmberHandlebars.registerHelper('_triageMustache', function(property, fn) {
  14832. Ember.assert("You cannot pass more than one argument to the _triageMustache helper", arguments.length <= 2);
  14833. if (helpers[property]) {
  14834. return helpers[property].call(this, fn);
  14835. }
  14836. else {
  14837. return helpers.bind.apply(this, arguments);
  14838. }
  14839. });
  14840. /**
  14841. @private
  14842. `bind` can be used to display a value, then update that value if it
  14843. changes. For example, if you wanted to print the `title` property of
  14844. `content`:
  14845. ```handlebars
  14846. {{bind "content.title"}}
  14847. ```
  14848. This will return the `title` property as a string, then create a new observer
  14849. at the specified path. If it changes, it will update the value in DOM. Note
  14850. that if you need to support IE7 and IE8 you must modify the model objects
  14851. properties using `Ember.get()` and `Ember.set()` for this to work as it
  14852. relies on Ember's KVO system. For all other browsers this will be handled for
  14853. you automatically.
  14854. @method bind
  14855. @for Ember.Handlebars.helpers
  14856. @param {String} property Property to bind
  14857. @param {Function} fn Context to provide for rendering
  14858. @return {String} HTML string
  14859. */
  14860. EmberHandlebars.registerHelper('bind', function(property, options) {
  14861. Ember.assert("You cannot pass more than one argument to the bind helper", arguments.length <= 2);
  14862. var context = (options.contexts && options.contexts[0]) || this;
  14863. if (!options.fn) {
  14864. return simpleBind.call(context, property, options);
  14865. }
  14866. return bind.call(context, property, options, false, function(result) {
  14867. return !Ember.isNone(result);
  14868. });
  14869. });
  14870. /**
  14871. @private
  14872. Use the `boundIf` helper to create a conditional that re-evaluates
  14873. whenever the truthiness of the bound value changes.
  14874. ```handlebars
  14875. {{#boundIf "content.shouldDisplayTitle"}}
  14876. {{content.title}}
  14877. {{/boundIf}}
  14878. ```
  14879. @method boundIf
  14880. @for Ember.Handlebars.helpers
  14881. @param {String} property Property to bind
  14882. @param {Function} fn Context to provide for rendering
  14883. @return {String} HTML string
  14884. */
  14885. EmberHandlebars.registerHelper('boundIf', function(property, fn) {
  14886. var context = (fn.contexts && fn.contexts[0]) || this;
  14887. var func = function(result) {
  14888. var truthy = result && get(result, 'isTruthy');
  14889. if (typeof truthy === 'boolean') { return truthy; }
  14890. if (Ember.isArray(result)) {
  14891. return get(result, 'length') !== 0;
  14892. } else {
  14893. return !!result;
  14894. }
  14895. };
  14896. return bind.call(context, property, fn, true, func, func, ['isTruthy', 'length']);
  14897. });
  14898. /**
  14899. @method with
  14900. @for Ember.Handlebars.helpers
  14901. @param {Function} context
  14902. @param {Hash} options
  14903. @return {String} HTML string
  14904. */
  14905. EmberHandlebars.registerHelper('with', function(context, options) {
  14906. if (arguments.length === 4) {
  14907. var keywordName, path, rootPath, normalized;
  14908. Ember.assert("If you pass more than one argument to the with helper, it must be in the form #with foo as bar", arguments[1] === "as");
  14909. options = arguments[3];
  14910. keywordName = arguments[2];
  14911. path = arguments[0];
  14912. Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop);
  14913. if (Ember.isGlobalPath(path)) {
  14914. Ember.bind(options.data.keywords, keywordName, path);
  14915. } else {
  14916. normalized = normalizePath(this, path, options.data);
  14917. path = normalized.path;
  14918. rootPath = normalized.root;
  14919. // This is a workaround for the fact that you cannot bind separate objects
  14920. // together. When we implement that functionality, we should use it here.
  14921. var contextKey = Ember.$.expando + Ember.guidFor(rootPath);
  14922. options.data.keywords[contextKey] = rootPath;
  14923. // if the path is '' ("this"), just bind directly to the current context
  14924. var contextPath = path ? contextKey + '.' + path : contextKey;
  14925. Ember.bind(options.data.keywords, keywordName, contextPath);
  14926. }
  14927. return bind.call(this, path, options, true, function(result) {
  14928. return !Ember.isNone(result);
  14929. });
  14930. } else {
  14931. Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2);
  14932. Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop);
  14933. return helpers.bind.call(options.contexts[0], context, options);
  14934. }
  14935. });
  14936. /**
  14937. See `boundIf`
  14938. @method if
  14939. @for Ember.Handlebars.helpers
  14940. @param {Function} context
  14941. @param {Hash} options
  14942. @return {String} HTML string
  14943. */
  14944. EmberHandlebars.registerHelper('if', function(context, options) {
  14945. Ember.assert("You must pass exactly one argument to the if helper", arguments.length === 2);
  14946. Ember.assert("You must pass a block to the if helper", options.fn && options.fn !== Handlebars.VM.noop);
  14947. return helpers.boundIf.call(options.contexts[0], context, options);
  14948. });
  14949. /**
  14950. @method unless
  14951. @for Ember.Handlebars.helpers
  14952. @param {Function} context
  14953. @param {Hash} options
  14954. @return {String} HTML string
  14955. */
  14956. EmberHandlebars.registerHelper('unless', function(context, options) {
  14957. Ember.assert("You must pass exactly one argument to the unless helper", arguments.length === 2);
  14958. Ember.assert("You must pass a block to the unless helper", options.fn && options.fn !== Handlebars.VM.noop);
  14959. var fn = options.fn, inverse = options.inverse;
  14960. options.fn = inverse;
  14961. options.inverse = fn;
  14962. return helpers.boundIf.call(options.contexts[0], context, options);
  14963. });
  14964. /**
  14965. `bindAttr` allows you to create a binding between DOM element attributes and
  14966. Ember objects. For example:
  14967. ```handlebars
  14968. <img {{bindAttr src="imageUrl" alt="imageTitle"}}>
  14969. ```
  14970. The above handlebars template will fill the `<img>`'s `src` attribute will
  14971. the value of the property referenced with `"imageUrl"` and its `alt`
  14972. attribute with the value of the property referenced with `"imageTitle"`.
  14973. If the rendering context of this template is the following object:
  14974. ```javascript
  14975. {
  14976. imageUrl: 'http://lolcats.info/haz-a-funny',
  14977. imageTitle: 'A humorous image of a cat'
  14978. }
  14979. ```
  14980. The resulting HTML output will be:
  14981. ```html
  14982. <img src="http://lolcats.info/haz-a-funny" alt="A humorous image of a cat">
  14983. ```
  14984. `bindAttr` cannot redeclare existing DOM element attributes. The use of `src`
  14985. in the following `bindAttr` example will be ignored and the hard coded value
  14986. of `src="/failwhale.gif"` will take precedence:
  14987. ```handlebars
  14988. <img src="/failwhale.gif" {{bindAttr src="imageUrl" alt="imageTitle"}}>
  14989. ```
  14990. ### `bindAttr` and the `class` attribute
  14991. `bindAttr` supports a special syntax for handling a number of cases unique
  14992. to the `class` DOM element attribute. The `class` attribute combines
  14993. multiple discreet values into a single attribute as a space-delimited
  14994. list of strings. Each string can be:
  14995. * a string return value of an object's property.
  14996. * a boolean return value of an object's property
  14997. * a hard-coded value
  14998. A string return value works identically to other uses of `bindAttr`. The
  14999. return value of the property will become the value of the attribute. For
  15000. example, the following view and template:
  15001. ```javascript
  15002. AView = Ember.View.extend({
  15003. someProperty: function(){
  15004. return "aValue";
  15005. }.property()
  15006. })
  15007. ```
  15008. ```handlebars
  15009. <img {{bindAttr class="view.someProperty}}>
  15010. ```
  15011. Result in the following rendered output:
  15012. ```html
  15013. <img class="aValue">
  15014. ```
  15015. A boolean return value will insert a specified class name if the property
  15016. returns `true` and remove the class name if the property returns `false`.
  15017. A class name is provided via the syntax
  15018. `somePropertyName:class-name-if-true`.
  15019. ```javascript
  15020. AView = Ember.View.extend({
  15021. someBool: true
  15022. })
  15023. ```
  15024. ```handlebars
  15025. <img {{bindAttr class="view.someBool:class-name-if-true"}}>
  15026. ```
  15027. Result in the following rendered output:
  15028. ```html
  15029. <img class="class-name-if-true">
  15030. ```
  15031. An additional section of the binding can be provided if you want to
  15032. replace the existing class instead of removing it when the boolean
  15033. value changes:
  15034. ```handlebars
  15035. <img {{bindAttr class="view.someBool:class-name-if-true:class-name-if-false"}}>
  15036. ```
  15037. A hard-coded value can be used by prepending `:` to the desired
  15038. class name: `:class-name-to-always-apply`.
  15039. ```handlebars
  15040. <img {{bindAttr class=":class-name-to-always-apply"}}>
  15041. ```
  15042. Results in the following rendered output:
  15043. ```html
  15044. <img class=":class-name-to-always-apply">
  15045. ```
  15046. All three strategies - string return value, boolean return value, and
  15047. hard-coded value – can be combined in a single declaration:
  15048. ```handlebars
  15049. <img {{bindAttr class=":class-name-to-always-apply view.someBool:class-name-if-true view.someProperty"}}>
  15050. ```
  15051. @method bindAttr
  15052. @for Ember.Handlebars.helpers
  15053. @param {Hash} options
  15054. @return {String} HTML string
  15055. */
  15056. EmberHandlebars.registerHelper('bindAttr', function(options) {
  15057. var attrs = options.hash;
  15058. Ember.assert("You must specify at least one hash argument to bindAttr", !!Ember.keys(attrs).length);
  15059. var view = options.data.view;
  15060. var ret = [];
  15061. var ctx = this;
  15062. // Generate a unique id for this element. This will be added as a
  15063. // data attribute to the element so it can be looked up when
  15064. // the bound property changes.
  15065. var dataId = ++Ember.uuid;
  15066. // Handle classes differently, as we can bind multiple classes
  15067. var classBindings = attrs['class'];
  15068. if (classBindings !== null && classBindings !== undefined) {
  15069. var classResults = EmberHandlebars.bindClasses(this, classBindings, view, dataId, options);
  15070. ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"');
  15071. delete attrs['class'];
  15072. }
  15073. var attrKeys = Ember.keys(attrs);
  15074. // For each attribute passed, create an observer and emit the
  15075. // current value of the property as an attribute.
  15076. forEach.call(attrKeys, function(attr) {
  15077. var path = attrs[attr],
  15078. normalized;
  15079. Ember.assert(fmt("You must provide a String for a bound attribute, not %@", [path]), typeof path === 'string');
  15080. normalized = normalizePath(ctx, path, options.data);
  15081. var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options),
  15082. type = Ember.typeOf(value);
  15083. Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean');
  15084. var observer, invoker;
  15085. observer = function observer() {
  15086. var result = handlebarsGet(ctx, path, options);
  15087. Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]), result === null || result === undefined || typeof result === 'number' || typeof result === 'string' || typeof result === 'boolean');
  15088. var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']");
  15089. // If we aren't able to find the element, it means the element
  15090. // to which we were bound has been removed from the view.
  15091. // In that case, we can assume the template has been re-rendered
  15092. // and we need to clean up the observer.
  15093. if (!elem || elem.length === 0) {
  15094. Ember.removeObserver(normalized.root, normalized.path, invoker);
  15095. return;
  15096. }
  15097. Ember.View.applyAttributeBindings(elem, attr, result);
  15098. };
  15099. invoker = function() {
  15100. Ember.run.scheduleOnce('render', observer);
  15101. };
  15102. // Add an observer to the view for when the property changes.
  15103. // When the observer fires, find the element using the
  15104. // unique data id and update the attribute to the new value.
  15105. if (path !== 'this') {
  15106. view.registerObserver(normalized.root, normalized.path, invoker);
  15107. }
  15108. // if this changes, also change the logic in ember-views/lib/views/view.js
  15109. if ((type === 'string' || (type === 'number' && !isNaN(value)))) {
  15110. ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"');
  15111. } else if (value && type === 'boolean') {
  15112. // The developer controls the attr name, so it should always be safe
  15113. ret.push(attr + '="' + attr + '"');
  15114. }
  15115. }, this);
  15116. // Add the unique identifier
  15117. // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG
  15118. ret.push('data-bindattr-' + dataId + '="' + dataId + '"');
  15119. return new EmberHandlebars.SafeString(ret.join(' '));
  15120. });
  15121. /**
  15122. @private
  15123. Helper that, given a space-separated string of property paths and a context,
  15124. returns an array of class names. Calling this method also has the side
  15125. effect of setting up observers at those property paths, such that if they
  15126. change, the correct class name will be reapplied to the DOM element.
  15127. For example, if you pass the string "fooBar", it will first look up the
  15128. "fooBar" value of the context. If that value is true, it will add the
  15129. "foo-bar" class to the current element (i.e., the dasherized form of
  15130. "fooBar"). If the value is a string, it will add that string as the class.
  15131. Otherwise, it will not add any new class name.
  15132. @method bindClasses
  15133. @for Ember.Handlebars
  15134. @param {Ember.Object} context The context from which to lookup properties
  15135. @param {String} classBindings A string, space-separated, of class bindings
  15136. to use
  15137. @param {Ember.View} view The view in which observers should look for the
  15138. element to update
  15139. @param {Srting} bindAttrId Optional bindAttr id used to lookup elements
  15140. @return {Array} An array of class names to add
  15141. */
  15142. EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId, options) {
  15143. var ret = [], newClass, value, elem;
  15144. // Helper method to retrieve the property from the context and
  15145. // determine which class string to return, based on whether it is
  15146. // a Boolean or not.
  15147. var classStringForPath = function(root, parsedPath, options) {
  15148. var val,
  15149. path = parsedPath.path;
  15150. if (path === 'this') {
  15151. val = root;
  15152. } else if (path === '') {
  15153. val = true;
  15154. } else {
  15155. val = handlebarsGet(root, path, options);
  15156. }
  15157. return Ember.View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName);
  15158. };
  15159. // For each property passed, loop through and setup
  15160. // an observer.
  15161. forEach.call(classBindings.split(' '), function(binding) {
  15162. // Variable in which the old class value is saved. The observer function
  15163. // closes over this variable, so it knows which string to remove when
  15164. // the property changes.
  15165. var oldClass;
  15166. var observer, invoker;
  15167. var parsedPath = Ember.View._parsePropertyPath(binding),
  15168. path = parsedPath.path,
  15169. pathRoot = context,
  15170. normalized;
  15171. if (path !== '' && path !== 'this') {
  15172. normalized = normalizePath(context, path, options.data);
  15173. pathRoot = normalized.root;
  15174. path = normalized.path;
  15175. }
  15176. // Set up an observer on the context. If the property changes, toggle the
  15177. // class name.
  15178. observer = function() {
  15179. // Get the current value of the property
  15180. newClass = classStringForPath(context, parsedPath, options);
  15181. elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$();
  15182. // If we can't find the element anymore, a parent template has been
  15183. // re-rendered and we've been nuked. Remove the observer.
  15184. if (!elem || elem.length === 0) {
  15185. Ember.removeObserver(pathRoot, path, invoker);
  15186. } else {
  15187. // If we had previously added a class to the element, remove it.
  15188. if (oldClass) {
  15189. elem.removeClass(oldClass);
  15190. }
  15191. // If necessary, add a new class. Make sure we keep track of it so
  15192. // it can be removed in the future.
  15193. if (newClass) {
  15194. elem.addClass(newClass);
  15195. oldClass = newClass;
  15196. } else {
  15197. oldClass = null;
  15198. }
  15199. }
  15200. };
  15201. invoker = function() {
  15202. Ember.run.scheduleOnce('render', observer);
  15203. };
  15204. if (path !== '' && path !== 'this') {
  15205. view.registerObserver(pathRoot, path, invoker);
  15206. }
  15207. // We've already setup the observer; now we just need to figure out the
  15208. // correct behavior right now on the first pass through.
  15209. value = classStringForPath(context, parsedPath, options);
  15210. if (value) {
  15211. ret.push(value);
  15212. // Make sure we save the current value so that it can be removed if the
  15213. // observer fires.
  15214. oldClass = value;
  15215. }
  15216. });
  15217. return ret;
  15218. };
  15219. })();
  15220. (function() {
  15221. /*globals Handlebars */
  15222. // TODO: Don't require the entire module
  15223. /**
  15224. @module ember
  15225. @submodule ember-handlebars
  15226. */
  15227. var get = Ember.get, set = Ember.set;
  15228. var PARENT_VIEW_PATH = /^parentView\./;
  15229. var EmberHandlebars = Ember.Handlebars;
  15230. EmberHandlebars.ViewHelper = Ember.Object.create({
  15231. propertiesFromHTMLOptions: function(options, thisContext) {
  15232. var hash = options.hash, data = options.data;
  15233. var extensions = {},
  15234. classes = hash['class'],
  15235. dup = false;
  15236. if (hash.id) {
  15237. extensions.elementId = hash.id;
  15238. dup = true;
  15239. }
  15240. if (classes) {
  15241. classes = classes.split(' ');
  15242. extensions.classNames = classes;
  15243. dup = true;
  15244. }
  15245. if (hash.classBinding) {
  15246. extensions.classNameBindings = hash.classBinding.split(' ');
  15247. dup = true;
  15248. }
  15249. if (hash.classNameBindings) {
  15250. if (extensions.classNameBindings === undefined) extensions.classNameBindings = [];
  15251. extensions.classNameBindings = extensions.classNameBindings.concat(hash.classNameBindings.split(' '));
  15252. dup = true;
  15253. }
  15254. if (hash.attributeBindings) {
  15255. Ember.assert("Setting 'attributeBindings' via Handlebars is not allowed. Please subclass Ember.View and set it there instead.");
  15256. extensions.attributeBindings = null;
  15257. dup = true;
  15258. }
  15259. if (dup) {
  15260. hash = Ember.$.extend({}, hash);
  15261. delete hash.id;
  15262. delete hash['class'];
  15263. delete hash.classBinding;
  15264. }
  15265. // Set the proper context for all bindings passed to the helper. This applies to regular attribute bindings
  15266. // as well as class name bindings. If the bindings are local, make them relative to the current context
  15267. // instead of the view.
  15268. var path;
  15269. // Evaluate the context of regular attribute bindings:
  15270. for (var prop in hash) {
  15271. if (!hash.hasOwnProperty(prop)) { continue; }
  15272. // Test if the property ends in "Binding"
  15273. if (Ember.IS_BINDING.test(prop) && typeof hash[prop] === 'string') {
  15274. path = this.contextualizeBindingPath(hash[prop], data);
  15275. if (path) { hash[prop] = path; }
  15276. }
  15277. }
  15278. // Evaluate the context of class name bindings:
  15279. if (extensions.classNameBindings) {
  15280. for (var b in extensions.classNameBindings) {
  15281. var full = extensions.classNameBindings[b];
  15282. if (typeof full === 'string') {
  15283. // Contextualize the path of classNameBinding so this:
  15284. //
  15285. // classNameBinding="isGreen:green"
  15286. //
  15287. // is converted to this:
  15288. //
  15289. // classNameBinding="_parentView.context.isGreen:green"
  15290. var parsedPath = Ember.View._parsePropertyPath(full);
  15291. path = this.contextualizeBindingPath(parsedPath.path, data);
  15292. if (path) { extensions.classNameBindings[b] = path + parsedPath.classNames; }
  15293. }
  15294. }
  15295. }
  15296. return Ember.$.extend(hash, extensions);
  15297. },
  15298. // Transform bindings from the current context to a context that can be evaluated within the view.
  15299. // Returns null if the path shouldn't be changed.
  15300. //
  15301. // TODO: consider the addition of a prefix that would allow this method to return `path`.
  15302. contextualizeBindingPath: function(path, data) {
  15303. var normalized = Ember.Handlebars.normalizePath(null, path, data);
  15304. if (normalized.isKeyword) {
  15305. return 'templateData.keywords.' + path;
  15306. } else if (Ember.isGlobalPath(path)) {
  15307. return null;
  15308. } else if (path === 'this') {
  15309. return '_parentView.context';
  15310. } else {
  15311. return '_parentView.context.' + path;
  15312. }
  15313. },
  15314. helper: function(thisContext, path, options) {
  15315. var inverse = options.inverse,
  15316. data = options.data,
  15317. view = data.view,
  15318. fn = options.fn,
  15319. hash = options.hash,
  15320. newView;
  15321. if ('string' === typeof path) {
  15322. newView = EmberHandlebars.get(thisContext, path, options);
  15323. Ember.assert("Unable to find view at path '" + path + "'", !!newView);
  15324. } else {
  15325. newView = path;
  15326. }
  15327. Ember.assert(Ember.String.fmt('You must pass a view to the #view helper, not %@ (%@)', [path, newView]), Ember.View.detect(newView) || Ember.View.detectInstance(newView));
  15328. var viewOptions = this.propertiesFromHTMLOptions(options, thisContext);
  15329. var currentView = data.view;
  15330. viewOptions.templateData = options.data;
  15331. var newViewProto = newView.proto ? newView.proto() : newView;
  15332. if (fn) {
  15333. Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newViewProto, 'templateName'));
  15334. viewOptions.template = fn;
  15335. }
  15336. // We only want to override the `_context` computed property if there is
  15337. // no specified controller. See View#_context for more information.
  15338. if (!newViewProto.controller && !newViewProto.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) {
  15339. viewOptions._context = thisContext;
  15340. }
  15341. currentView.appendChild(newView, viewOptions);
  15342. }
  15343. });
  15344. /**
  15345. `{{view}}` inserts a new instance of `Ember.View` into a template passing its
  15346. options to the `Ember.View`'s `create` method and using the supplied block as
  15347. the view's own template.
  15348. An empty `<body>` and the following template:
  15349. ```handlebars
  15350. A span:
  15351. {{#view tagName="span"}}
  15352. hello.
  15353. {{/view}}
  15354. ```
  15355. Will result in HTML structure:
  15356. ```html
  15357. <body>
  15358. <!-- Note: the handlebars template script
  15359. also results in a rendered Ember.View
  15360. which is the outer <div> here -->
  15361. <div class="ember-view">
  15362. A span:
  15363. <span id="ember1" class="ember-view">
  15364. Hello.
  15365. </span>
  15366. </div>
  15367. </body>
  15368. ```
  15369. ### `parentView` setting
  15370. The `parentView` property of the new `Ember.View` instance created through
  15371. `{{view}}` will be set to the `Ember.View` instance of the template where
  15372. `{{view}}` was called.
  15373. ```javascript
  15374. aView = Ember.View.create({
  15375. template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}")
  15376. });
  15377. aView.appendTo('body');
  15378. ```
  15379. Will result in HTML structure:
  15380. ```html
  15381. <div id="ember1" class="ember-view">
  15382. <div id="ember2" class="ember-view">
  15383. my parent: ember1
  15384. </div>
  15385. </div>
  15386. ```
  15387. ### Setting CSS id and class attributes
  15388. The HTML `id` attribute can be set on the `{{view}}`'s resulting element with
  15389. the `id` option. This option will _not_ be passed to `Ember.View.create`.
  15390. ```handlebars
  15391. {{#view tagName="span" id="a-custom-id"}}
  15392. hello.
  15393. {{/view}}
  15394. ```
  15395. Results in the following HTML structure:
  15396. ```html
  15397. <div class="ember-view">
  15398. <span id="a-custom-id" class="ember-view">
  15399. hello.
  15400. </span>
  15401. </div>
  15402. ```
  15403. The HTML `class` attribute can be set on the `{{view}}`'s resulting element
  15404. with the `class` or `classNameBindings` options. The `class` option will
  15405. directly set the CSS `class` attribute and will not be passed to
  15406. `Ember.View.create`. `classNameBindings` will be passed to `create` and use
  15407. `Ember.View`'s class name binding functionality:
  15408. ```handlebars
  15409. {{#view tagName="span" class="a-custom-class"}}
  15410. hello.
  15411. {{/view}}
  15412. ```
  15413. Results in the following HTML structure:
  15414. ```html
  15415. <div class="ember-view">
  15416. <span id="ember2" class="ember-view a-custom-class">
  15417. hello.
  15418. </span>
  15419. </div>
  15420. ```
  15421. ### Supplying a different view class
  15422. `{{view}}` can take an optional first argument before its supplied options to
  15423. specify a path to a custom view class.
  15424. ```handlebars
  15425. {{#view "MyApp.CustomView"}}
  15426. hello.
  15427. {{/view}}
  15428. ```
  15429. The first argument can also be a relative path. Ember will search for the
  15430. view class starting at the `Ember.View` of the template where `{{view}}` was
  15431. used as the root object:
  15432. ```javascript
  15433. MyApp = Ember.Application.create({});
  15434. MyApp.OuterView = Ember.View.extend({
  15435. innerViewClass: Ember.View.extend({
  15436. classNames: ['a-custom-view-class-as-property']
  15437. }),
  15438. template: Ember.Handlebars.compile('{{#view "innerViewClass"}} hi {{/view}}')
  15439. });
  15440. MyApp.OuterView.create().appendTo('body');
  15441. ```
  15442. Will result in the following HTML:
  15443. ```html
  15444. <div id="ember1" class="ember-view">
  15445. <div id="ember2" class="ember-view a-custom-view-class-as-property">
  15446. hi
  15447. </div>
  15448. </div>
  15449. ```
  15450. ### Blockless use
  15451. If you supply a custom `Ember.View` subclass that specifies its own template
  15452. or provide a `templateName` option to `{{view}}` it can be used without
  15453. supplying a block. Attempts to use both a `templateName` option and supply a
  15454. block will throw an error.
  15455. ```handlebars
  15456. {{view "MyApp.ViewWithATemplateDefined"}}
  15457. ```
  15458. ### `viewName` property
  15459. You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance
  15460. will be referenced as a property of its parent view by this name.
  15461. ```javascript
  15462. aView = Ember.View.create({
  15463. template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}')
  15464. });
  15465. aView.appendTo('body');
  15466. aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper
  15467. ```
  15468. @method view
  15469. @for Ember.Handlebars.helpers
  15470. @param {String} path
  15471. @param {Hash} options
  15472. @return {String} HTML string
  15473. */
  15474. EmberHandlebars.registerHelper('view', function(path, options) {
  15475. Ember.assert("The view helper only takes a single argument", arguments.length <= 2);
  15476. // If no path is provided, treat path param as options.
  15477. if (path && path.data && path.data.isRenderData) {
  15478. options = path;
  15479. path = "Ember.View";
  15480. }
  15481. return EmberHandlebars.ViewHelper.helper(this, path, options);
  15482. });
  15483. })();
  15484. (function() {
  15485. /*globals Handlebars */
  15486. // TODO: Don't require all of this module
  15487. /**
  15488. @module ember
  15489. @submodule ember-handlebars
  15490. */
  15491. var get = Ember.get, handlebarsGet = Ember.Handlebars.get, fmt = Ember.String.fmt;
  15492. /**
  15493. `{{collection}}` is a `Ember.Handlebars` helper for adding instances of
  15494. `Ember.CollectionView` to a template. See `Ember.CollectionView` for
  15495. additional information on how a `CollectionView` functions.
  15496. `{{collection}}`'s primary use is as a block helper with a `contentBinding`
  15497. option pointing towards an `Ember.Array`-compatible object. An `Ember.View`
  15498. instance will be created for each item in its `content` property. Each view
  15499. will have its own `content` property set to the appropriate item in the
  15500. collection.
  15501. The provided block will be applied as the template for each item's view.
  15502. Given an empty `<body>` the following template:
  15503. ```handlebars
  15504. {{#collection contentBinding="App.items"}}
  15505. Hi {{view.content.name}}
  15506. {{/collection}}
  15507. ```
  15508. And the following application code
  15509. ```javascript
  15510. App = Ember.Application.create()
  15511. App.items = [
  15512. Ember.Object.create({name: 'Dave'}),
  15513. Ember.Object.create({name: 'Mary'}),
  15514. Ember.Object.create({name: 'Sara'})
  15515. ]
  15516. ```
  15517. Will result in the HTML structure below
  15518. ```html
  15519. <div class="ember-view">
  15520. <div class="ember-view">Hi Dave</div>
  15521. <div class="ember-view">Hi Mary</div>
  15522. <div class="ember-view">Hi Sara</div>
  15523. </div>
  15524. ```
  15525. ### Blockless Use
  15526. If you provide an `itemViewClass` option that has its own `template` you can
  15527. omit the block.
  15528. The following template:
  15529. ```handlebars
  15530. {{collection contentBinding="App.items" itemViewClass="App.AnItemView"}}
  15531. ```
  15532. And application code
  15533. ```javascript
  15534. App = Ember.Application.create();
  15535. App.items = [
  15536. Ember.Object.create({name: 'Dave'}),
  15537. Ember.Object.create({name: 'Mary'}),
  15538. Ember.Object.create({name: 'Sara'})
  15539. ];
  15540. App.AnItemView = Ember.View.extend({
  15541. template: Ember.Handlebars.compile("Greetings {{view.content.name}}")
  15542. });
  15543. ```
  15544. Will result in the HTML structure below
  15545. ```html
  15546. <div class="ember-view">
  15547. <div class="ember-view">Greetings Dave</div>
  15548. <div class="ember-view">Greetings Mary</div>
  15549. <div class="ember-view">Greetings Sara</div>
  15550. </div>
  15551. ```
  15552. ### Specifying a CollectionView subclass
  15553. By default the `{{collection}}` helper will create an instance of
  15554. `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to
  15555. the helper by passing it as the first argument:
  15556. ```handlebars
  15557. {{#collection App.MyCustomCollectionClass contentBinding="App.items"}}
  15558. Hi {{view.content.name}}
  15559. {{/collection}}
  15560. ```
  15561. ### Forwarded `item.*`-named Options
  15562. As with the `{{view}}`, helper options passed to the `{{collection}}` will be
  15563. set on the resulting `Ember.CollectionView` as properties. Additionally,
  15564. options prefixed with `item` will be applied to the views rendered for each
  15565. item (note the camelcasing):
  15566. ```handlebars
  15567. {{#collection contentBinding="App.items"
  15568. itemTagName="p"
  15569. itemClassNames="greeting"}}
  15570. Howdy {{view.content.name}}
  15571. {{/collection}}
  15572. ```
  15573. Will result in the following HTML structure:
  15574. ```html
  15575. <div class="ember-view">
  15576. <p class="ember-view greeting">Howdy Dave</p>
  15577. <p class="ember-view greeting">Howdy Mary</p>
  15578. <p class="ember-view greeting">Howdy Sara</p>
  15579. </div>
  15580. ```
  15581. @method collection
  15582. @for Ember.Handlebars.helpers
  15583. @param {String} path
  15584. @param {Hash} options
  15585. @return {String} HTML string
  15586. @deprecated Use `{{each}}` helper instead.
  15587. */
  15588. Ember.Handlebars.registerHelper('collection', function(path, options) {
  15589. Ember.deprecate("Using the {{collection}} helper without specifying a class has been deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection');
  15590. // If no path is provided, treat path param as options.
  15591. if (path && path.data && path.data.isRenderData) {
  15592. options = path;
  15593. path = undefined;
  15594. Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1);
  15595. } else {
  15596. Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2);
  15597. }
  15598. var fn = options.fn;
  15599. var data = options.data;
  15600. var inverse = options.inverse;
  15601. var view = options.data.view;
  15602. // If passed a path string, convert that into an object.
  15603. // Otherwise, just default to the standard class.
  15604. var collectionClass;
  15605. collectionClass = path ? handlebarsGet(this, path, options) : Ember.CollectionView;
  15606. Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass);
  15607. var hash = options.hash, itemHash = {}, match;
  15608. // Extract item view class if provided else default to the standard class
  15609. var itemViewClass, itemViewPath = hash.itemViewClass;
  15610. var collectionPrototype = collectionClass.proto();
  15611. delete hash.itemViewClass;
  15612. itemViewClass = itemViewPath ? handlebarsGet(collectionPrototype, itemViewPath, options) : collectionPrototype.itemViewClass;
  15613. Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewPath]), !!itemViewClass);
  15614. // Go through options passed to the {{collection}} helper and extract options
  15615. // that configure item views instead of the collection itself.
  15616. for (var prop in hash) {
  15617. if (hash.hasOwnProperty(prop)) {
  15618. match = prop.match(/^item(.)(.*)$/);
  15619. if(match && prop !== 'itemController') {
  15620. // Convert itemShouldFoo -> shouldFoo
  15621. itemHash[match[1].toLowerCase() + match[2]] = hash[prop];
  15622. // Delete from hash as this will end up getting passed to the
  15623. // {{view}} helper method.
  15624. delete hash[prop];
  15625. }
  15626. }
  15627. }
  15628. var tagName = hash.tagName || collectionPrototype.tagName;
  15629. if (fn) {
  15630. itemHash.template = fn;
  15631. delete options.fn;
  15632. }
  15633. var emptyViewClass;
  15634. if (inverse && inverse !== Handlebars.VM.noop) {
  15635. emptyViewClass = get(collectionPrototype, 'emptyViewClass');
  15636. emptyViewClass = emptyViewClass.extend({
  15637. template: inverse,
  15638. tagName: itemHash.tagName
  15639. });
  15640. } else if (hash.emptyViewClass) {
  15641. emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options);
  15642. }
  15643. if (emptyViewClass) { hash.emptyView = emptyViewClass; }
  15644. if(!hash.keyword){
  15645. itemHash._context = Ember.computed.alias('content');
  15646. }
  15647. var viewString = view.toString();
  15648. var viewOptions = Ember.Handlebars.ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this);
  15649. hash.itemViewClass = itemViewClass.extend(viewOptions);
  15650. return Ember.Handlebars.helpers.view.call(this, collectionClass, options);
  15651. });
  15652. })();
  15653. (function() {
  15654. /*globals Handlebars */
  15655. /**
  15656. @module ember
  15657. @submodule ember-handlebars
  15658. */
  15659. var handlebarsGet = Ember.Handlebars.get;
  15660. /**
  15661. `unbound` allows you to output a property without binding. *Important:* The
  15662. output will not be updated if the property changes. Use with caution.
  15663. ```handlebars
  15664. <div>{{unbound somePropertyThatDoesntChange}}</div>
  15665. ```
  15666. `unbound` can also be used in conjunction with a bound helper to
  15667. render it in its unbound form:
  15668. ```handlebars
  15669. <div>{{unbound helperName somePropertyThatDoesntChange}}</div>
  15670. ```
  15671. @method unbound
  15672. @for Ember.Handlebars.helpers
  15673. @param {String} property
  15674. @return {String} HTML string
  15675. */
  15676. Ember.Handlebars.registerHelper('unbound', function(property, fn) {
  15677. var options = arguments[arguments.length - 1], helper, context, out;
  15678. if(arguments.length > 2) {
  15679. // Unbound helper call.
  15680. options.data.isUnbound = true;
  15681. helper = Ember.Handlebars.helpers[arguments[0]] || Ember.Handlebars.helperMissing;
  15682. out = helper.apply(this, Array.prototype.slice.call(arguments, 1));
  15683. delete options.data.isUnbound;
  15684. return out;
  15685. }
  15686. context = (fn.contexts && fn.contexts[0]) || this;
  15687. return handlebarsGet(context, property, fn);
  15688. });
  15689. })();
  15690. (function() {
  15691. /*jshint debug:true*/
  15692. /**
  15693. @module ember
  15694. @submodule ember-handlebars
  15695. */
  15696. var handlebarsGet = Ember.Handlebars.get, normalizePath = Ember.Handlebars.normalizePath;
  15697. /**
  15698. `log` allows you to output the value of a value in the current rendering
  15699. context.
  15700. ```handlebars
  15701. {{log myVariable}}
  15702. ```
  15703. @method log
  15704. @for Ember.Handlebars.helpers
  15705. @param {String} property
  15706. */
  15707. Ember.Handlebars.registerHelper('log', function(property, options) {
  15708. var context = (options.contexts && options.contexts[0]) || this,
  15709. normalized = normalizePath(context, property, options.data),
  15710. pathRoot = normalized.root,
  15711. path = normalized.path,
  15712. value = (path === 'this') ? pathRoot : handlebarsGet(pathRoot, path, options);
  15713. Ember.Logger.log(value);
  15714. });
  15715. /**
  15716. Execute the `debugger` statement in the current context.
  15717. ```handlebars
  15718. {{debugger}}
  15719. ```
  15720. @method debugger
  15721. @for Ember.Handlebars.helpers
  15722. @param {String} property
  15723. */
  15724. Ember.Handlebars.registerHelper('debugger', function() {
  15725. debugger;
  15726. });
  15727. })();
  15728. (function() {
  15729. /**
  15730. @module ember
  15731. @submodule ember-handlebars
  15732. */
  15733. var get = Ember.get, set = Ember.set;
  15734. Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
  15735. init: function() {
  15736. var itemController = get(this, 'itemController');
  15737. var binding;
  15738. if (itemController) {
  15739. var controller = Ember.ArrayController.create();
  15740. set(controller, 'itemController', itemController);
  15741. set(controller, 'container', get(this, 'controller.container'));
  15742. set(controller, '_eachView', this);
  15743. set(controller, 'target', get(this, 'controller'));
  15744. this.disableContentObservers(function() {
  15745. set(this, 'content', controller);
  15746. binding = new Ember.Binding('content', '_eachView.dataSource').oneWay();
  15747. binding.connect(controller);
  15748. });
  15749. set(this, '_arrayController', controller);
  15750. } else {
  15751. this.disableContentObservers(function() {
  15752. binding = new Ember.Binding('content', 'dataSource').oneWay();
  15753. binding.connect(this);
  15754. });
  15755. }
  15756. return this._super();
  15757. },
  15758. disableContentObservers: function(callback) {
  15759. Ember.removeBeforeObserver(this, 'content', null, '_contentWillChange');
  15760. Ember.removeObserver(this, 'content', null, '_contentDidChange');
  15761. callback.apply(this);
  15762. Ember.addBeforeObserver(this, 'content', null, '_contentWillChange');
  15763. Ember.addObserver(this, 'content', null, '_contentDidChange');
  15764. },
  15765. itemViewClass: Ember._MetamorphView,
  15766. emptyViewClass: Ember._MetamorphView,
  15767. createChildView: function(view, attrs) {
  15768. view = this._super(view, attrs);
  15769. // At the moment, if a container view subclass wants
  15770. // to insert keywords, it is responsible for cloning
  15771. // the keywords hash. This will be fixed momentarily.
  15772. var keyword = get(this, 'keyword');
  15773. var content = get(view, 'content');
  15774. if (keyword) {
  15775. var data = get(view, 'templateData');
  15776. data = Ember.copy(data);
  15777. data.keywords = view.cloneKeywords();
  15778. set(view, 'templateData', data);
  15779. // In this case, we do not bind, because the `content` of
  15780. // a #each item cannot change.
  15781. data.keywords[keyword] = content;
  15782. }
  15783. // If {{#each}} is looping over an array of controllers,
  15784. // point each child view at their respective controller.
  15785. if (content && get(content, 'isController')) {
  15786. set(view, 'controller', content);
  15787. }
  15788. return view;
  15789. },
  15790. willDestroy: function() {
  15791. var arrayController = get(this, '_arrayController');
  15792. if (arrayController) {
  15793. arrayController.destroy();
  15794. }
  15795. return this._super();
  15796. }
  15797. });
  15798. var GroupedEach = Ember.Handlebars.GroupedEach = function(context, path, options) {
  15799. var self = this,
  15800. normalized = Ember.Handlebars.normalizePath(context, path, options.data);
  15801. this.context = context;
  15802. this.path = path;
  15803. this.options = options;
  15804. this.template = options.fn;
  15805. this.containingView = options.data.view;
  15806. this.normalizedRoot = normalized.root;
  15807. this.normalizedPath = normalized.path;
  15808. this.content = this.lookupContent();
  15809. this.addContentObservers();
  15810. this.addArrayObservers();
  15811. this.containingView.on('willClearRender', function() {
  15812. self.destroy();
  15813. });
  15814. };
  15815. GroupedEach.prototype = {
  15816. contentWillChange: function() {
  15817. this.removeArrayObservers();
  15818. },
  15819. contentDidChange: function() {
  15820. this.content = this.lookupContent();
  15821. this.addArrayObservers();
  15822. this.rerenderContainingView();
  15823. },
  15824. contentArrayWillChange: Ember.K,
  15825. contentArrayDidChange: function() {
  15826. this.rerenderContainingView();
  15827. },
  15828. lookupContent: function() {
  15829. return Ember.Handlebars.get(this.normalizedRoot, this.normalizedPath, this.options);
  15830. },
  15831. addArrayObservers: function() {
  15832. this.content.addArrayObserver(this, {
  15833. willChange: 'contentArrayWillChange',
  15834. didChange: 'contentArrayDidChange'
  15835. });
  15836. },
  15837. removeArrayObservers: function() {
  15838. this.content.removeArrayObserver(this, {
  15839. willChange: 'contentArrayWillChange',
  15840. didChange: 'contentArrayDidChange'
  15841. });
  15842. },
  15843. addContentObservers: function() {
  15844. Ember.addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange);
  15845. Ember.addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange);
  15846. },
  15847. removeContentObservers: function() {
  15848. Ember.removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange);
  15849. Ember.removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange);
  15850. },
  15851. render: function() {
  15852. var content = this.content,
  15853. contentLength = get(content, 'length'),
  15854. data = this.options.data,
  15855. template = this.template;
  15856. data.insideEach = true;
  15857. for (var i = 0; i < contentLength; i++) {
  15858. template(content.objectAt(i), { data: data });
  15859. }
  15860. },
  15861. rerenderContainingView: function() {
  15862. Ember.run.scheduleOnce('render', this.containingView, 'rerender');
  15863. },
  15864. destroy: function() {
  15865. this.removeContentObservers();
  15866. this.removeArrayObservers();
  15867. }
  15868. };
  15869. /**
  15870. The `{{#each}}` helper loops over elements in a collection, rendering its
  15871. block once for each item. It is an extension of the base Handlebars `{{#each}}`
  15872. helper:
  15873. ```javascript
  15874. Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}];
  15875. ```
  15876. ```handlebars
  15877. {{#each Developers}}
  15878. {{name}}
  15879. {{/each}}
  15880. ```
  15881. `{{each}}` supports an alternative syntax with element naming:
  15882. ```handlebars
  15883. {{#each person in Developers}}
  15884. {{person.name}}
  15885. {{/each}}
  15886. ```
  15887. When looping over objects that do not have properties, `{{this}}` can be used
  15888. to render the object:
  15889. ```javascript
  15890. DeveloperNames = ['Yehuda', 'Tom', 'Paul']
  15891. ```
  15892. ```handlebars
  15893. {{#each DeveloperNames}}
  15894. {{this}}
  15895. {{/each}}
  15896. ```
  15897. ### {{else}} condition
  15898. `{{#each}}` can have a matching `{{else}}`. The contents of this block will render
  15899. if the collection is empty.
  15900. ```
  15901. {{#each person in Developers}}
  15902. {{person.name}}
  15903. {{else}}
  15904. <p>Sorry, nobody is available for this task.</p>
  15905. {{/each}}
  15906. ```
  15907. ### Specifying a View class for items
  15908. If you provide an `itemViewClass` option that references a view class
  15909. with its own `template` you can omit the block.
  15910. The following template:
  15911. ```handlebars
  15912. {{#view App.MyView }}
  15913. {{each view.items itemViewClass="App.AnItemView"}}
  15914. {{/view}}
  15915. ```
  15916. And application code
  15917. ```javascript
  15918. App = Ember.Application.create({
  15919. MyView: Ember.View.extend({
  15920. items: [
  15921. Ember.Object.create({name: 'Dave'}),
  15922. Ember.Object.create({name: 'Mary'}),
  15923. Ember.Object.create({name: 'Sara'})
  15924. ]
  15925. })
  15926. });
  15927. App.AnItemView = Ember.View.extend({
  15928. template: Ember.Handlebars.compile("Greetings {{name}}")
  15929. });
  15930. ```
  15931. Will result in the HTML structure below
  15932. ```html
  15933. <div class="ember-view">
  15934. <div class="ember-view">Greetings Dave</div>
  15935. <div class="ember-view">Greetings Mary</div>
  15936. <div class="ember-view">Greetings Sara</div>
  15937. </div>
  15938. ```
  15939. ### Representing each item with a Controller.
  15940. By default the controller lookup within an `{{#each}}` block will be
  15941. the controller of the template where the `{{#each}}` was used. If each
  15942. item needs to be presented by a custom controller you can provide a
  15943. `itemController` option which references a controller by lookup name.
  15944. Each item in the loop will be wrapped in an instance of this controller
  15945. and the item itself will be set to the `content` property of that controller.
  15946. This is useful in cases where properties of model objects need transformation
  15947. or synthesis for display:
  15948. ```javascript
  15949. App.DeveloperController = Ember.ObjectController.extend({
  15950. isAvailableForHire: function(){
  15951. return !this.get('content.isEmployed') && this.get('content.isSeekingWork');
  15952. }.property('isEmployed', 'isSeekingWork')
  15953. })
  15954. ```
  15955. ```handlebars
  15956. {{#each person in Developers itemController="developer"}}
  15957. {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}}
  15958. {{/each}}
  15959. ```
  15960. @method each
  15961. @for Ember.Handlebars.helpers
  15962. @param [name] {String} name for item (used with `in`)
  15963. @param path {String} path
  15964. @param [options] {Object} Handlebars key/value pairs of options
  15965. @param [options.itemViewClass] {String} a path to a view class used for each item
  15966. @param [options.itemController] {String} name of a controller to be created for each item
  15967. */
  15968. Ember.Handlebars.registerHelper('each', function(path, options) {
  15969. if (arguments.length === 4) {
  15970. Ember.assert("If you pass more than one argument to the each helper, it must be in the form #each foo in bar", arguments[1] === "in");
  15971. var keywordName = arguments[0];
  15972. options = arguments[3];
  15973. path = arguments[2];
  15974. if (path === '') { path = "this"; }
  15975. options.hash.keyword = keywordName;
  15976. }
  15977. options.hash.dataSourceBinding = path;
  15978. // Set up emptyView as a metamorph with no tag
  15979. //options.hash.emptyViewClass = Ember._MetamorphView;
  15980. if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) {
  15981. new Ember.Handlebars.GroupedEach(this, path, options).render();
  15982. } else {
  15983. return Ember.Handlebars.helpers.collection.call(this, 'Ember.Handlebars.EachView', options);
  15984. }
  15985. });
  15986. })();
  15987. (function() {
  15988. /**
  15989. @module ember
  15990. @submodule ember-handlebars
  15991. */
  15992. /**
  15993. `template` allows you to render a template from inside another template.
  15994. This allows you to re-use the same template in multiple places. For example:
  15995. ```html
  15996. <script type="text/x-handlebars" data-template-name="logged_in_user">
  15997. {{#with loggedInUser}}
  15998. Last Login: {{lastLogin}}
  15999. User Info: {{template "user_info"}}
  16000. {{/with}}
  16001. </script>
  16002. ```
  16003. ```html
  16004. <script type="text/x-handlebars" data-template-name="user_info">
  16005. Name: <em>{{name}}</em>
  16006. Karma: <em>{{karma}}</em>
  16007. </script>
  16008. ```
  16009. This helper looks for templates in the global `Ember.TEMPLATES` hash. If you
  16010. add `<script>` tags to your page with the `data-template-name` attribute set,
  16011. they will be compiled and placed in this hash automatically.
  16012. You can also manually register templates by adding them to the hash:
  16013. ```javascript
  16014. Ember.TEMPLATES["my_cool_template"] = Ember.Handlebars.compile('<b>{{user}}</b>');
  16015. ```
  16016. @method template
  16017. @for Ember.Handlebars.helpers
  16018. @param {String} templateName the template to render
  16019. */
  16020. Ember.Handlebars.registerHelper('template', function(name, options) {
  16021. var template = Ember.TEMPLATES[name];
  16022. Ember.assert("Unable to find template with name '"+name+"'.", !!template);
  16023. Ember.TEMPLATES[name](this, { data: options.data });
  16024. });
  16025. Ember.Handlebars.registerHelper('partial', function(name, options) {
  16026. var nameParts = name.split("/"),
  16027. lastPart = nameParts[nameParts.length - 1];
  16028. nameParts[nameParts.length - 1] = "_" + lastPart;
  16029. var underscoredName = nameParts.join("/");
  16030. var template = Ember.TEMPLATES[underscoredName],
  16031. deprecatedTemplate = Ember.TEMPLATES[name];
  16032. Ember.deprecate("You tried to render the partial " + name + ", which should be at '" + underscoredName + "', but Ember found '" + name + "'. Please use a leading underscore in your partials", template);
  16033. Ember.assert("Unable to find partial with name '"+name+"'.", template || deprecatedTemplate);
  16034. template = template || deprecatedTemplate;
  16035. template(this, { data: options.data });
  16036. });
  16037. })();
  16038. (function() {
  16039. /**
  16040. @module ember
  16041. @submodule ember-handlebars
  16042. */
  16043. var get = Ember.get, set = Ember.set;
  16044. /**
  16045. When used in a Handlebars template that is assigned to an `Ember.View`
  16046. instance's `layout` property Ember will render the layout template first,
  16047. inserting the view's own rendered output at the `{{yield}}` location.
  16048. An empty `<body>` and the following application code:
  16049. ```javascript
  16050. AView = Ember.View.extend({
  16051. classNames: ['a-view-with-layout'],
  16052. layout: Ember.Handlebars.compile('<div class="wrapper">{{yield}}</div>'),
  16053. template: Ember.Handlebars.compile('<span>I am wrapped</span>')
  16054. });
  16055. aView = AView.create();
  16056. aView.appendTo('body');
  16057. ```
  16058. Will result in the following HTML output:
  16059. ```html
  16060. <body>
  16061. <div class='ember-view a-view-with-layout'>
  16062. <div class="wrapper">
  16063. <span>I am wrapped</span>
  16064. </div>
  16065. </div>
  16066. </body>
  16067. ```
  16068. The `yield` helper cannot be used outside of a template assigned to an
  16069. `Ember.View`'s `layout` property and will throw an error if attempted.
  16070. ```javascript
  16071. BView = Ember.View.extend({
  16072. classNames: ['a-view-with-layout'],
  16073. template: Ember.Handlebars.compile('{{yield}}')
  16074. });
  16075. bView = BView.create();
  16076. bView.appendTo('body');
  16077. // throws
  16078. // Uncaught Error: assertion failed: You called yield in a template that was not a layout
  16079. ```
  16080. @method yield
  16081. @for Ember.Handlebars.helpers
  16082. @param {Hash} options
  16083. @return {String} HTML string
  16084. */
  16085. Ember.Handlebars.registerHelper('yield', function(options) {
  16086. var view = options.data.view, template;
  16087. while (view && !get(view, 'layout')) {
  16088. view = get(view, 'parentView');
  16089. }
  16090. Ember.assert("You called yield in a template that was not a layout", !!view);
  16091. template = get(view, 'template');
  16092. if (template) { template(this, options); }
  16093. });
  16094. })();
  16095. (function() {
  16096. })();
  16097. (function() {
  16098. })();
  16099. (function() {
  16100. /**
  16101. @module ember
  16102. @submodule ember-handlebars
  16103. */
  16104. var set = Ember.set, get = Ember.get;
  16105. /**
  16106. The `Ember.Checkbox` view class renders a checkbox
  16107. [input](https://developer.mozilla.org/en/HTML/Element/Input) element. It
  16108. allows for binding an Ember property (`checked`) to the status of the
  16109. checkbox.
  16110. Example:
  16111. ```handlebars
  16112. {{view Ember.Checkbox checkedBinding="receiveEmail"}}
  16113. ```
  16114. You can add a `label` tag yourself in the template where the `Ember.Checkbox`
  16115. is being used.
  16116. ```html
  16117. <label>
  16118. {{view Ember.Checkbox classNames="applicaton-specific-checkbox"}}
  16119. Some Title
  16120. </label>
  16121. ```
  16122. The `checked` attribute of an `Ember.Checkbox` object should always be set
  16123. through the Ember object or by interacting with its rendered element
  16124. representation via the mouse, keyboard, or touch. Updating the value of the
  16125. checkbox via jQuery will result in the checked value of the object and its
  16126. element losing synchronization.
  16127. ## Layout and LayoutName properties
  16128. Because HTML `input` elements are self closing `layout` and `layoutName`
  16129. properties will not be applied. See `Ember.View`'s layout section for more
  16130. information.
  16131. @class Checkbox
  16132. @namespace Ember
  16133. @extends Ember.View
  16134. */
  16135. Ember.Checkbox = Ember.View.extend({
  16136. classNames: ['ember-checkbox'],
  16137. tagName: 'input',
  16138. attributeBindings: ['type', 'checked', 'disabled', 'tabindex'],
  16139. type: "checkbox",
  16140. checked: false,
  16141. disabled: false,
  16142. init: function() {
  16143. this._super();
  16144. this.on("change", this, this._updateElementValue);
  16145. },
  16146. _updateElementValue: function() {
  16147. set(this, 'checked', this.$().prop('checked'));
  16148. }
  16149. });
  16150. })();
  16151. (function() {
  16152. /**
  16153. @module ember
  16154. @submodule ember-handlebars
  16155. */
  16156. var get = Ember.get, set = Ember.set;
  16157. /**
  16158. Shared mixin used by `Ember.TextField` and `Ember.TextArea`.
  16159. @class TextSupport
  16160. @namespace Ember
  16161. @extends Ember.Mixin
  16162. @private
  16163. */
  16164. Ember.TextSupport = Ember.Mixin.create({
  16165. value: "",
  16166. attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex'],
  16167. placeholder: null,
  16168. disabled: false,
  16169. maxlength: null,
  16170. insertNewline: Ember.K,
  16171. cancel: Ember.K,
  16172. init: function() {
  16173. this._super();
  16174. this.on("focusOut", this, this._elementValueDidChange);
  16175. this.on("change", this, this._elementValueDidChange);
  16176. this.on("paste", this, this._elementValueDidChange);
  16177. this.on("cut", this, this._elementValueDidChange);
  16178. this.on("input", this, this._elementValueDidChange);
  16179. this.on("keyUp", this, this.interpretKeyEvents);
  16180. },
  16181. interpretKeyEvents: function(event) {
  16182. var map = Ember.TextSupport.KEY_EVENTS;
  16183. var method = map[event.keyCode];
  16184. this._elementValueDidChange();
  16185. if (method) { return this[method](event); }
  16186. },
  16187. _elementValueDidChange: function() {
  16188. set(this, 'value', this.$().val());
  16189. }
  16190. });
  16191. Ember.TextSupport.KEY_EVENTS = {
  16192. 13: 'insertNewline',
  16193. 27: 'cancel'
  16194. };
  16195. })();
  16196. (function() {
  16197. /**
  16198. @module ember
  16199. @submodule ember-handlebars
  16200. */
  16201. var get = Ember.get, set = Ember.set;
  16202. /**
  16203. The `Ember.TextField` view class renders a text
  16204. [input](https://developer.mozilla.org/en/HTML/Element/Input) element. It
  16205. allows for binding Ember properties to the text field contents (`value`),
  16206. live-updating as the user inputs text.
  16207. Example:
  16208. ```handlebars
  16209. {{view Ember.TextField valueBinding="firstName"}}
  16210. ```
  16211. ## Layout and LayoutName properties
  16212. Because HTML `input` elements are self closing `layout` and `layoutName`
  16213. properties will not be applied. See `Ember.View`'s layout section for more
  16214. information.
  16215. ## HTML Attributes
  16216. By default `Ember.TextField` provides support for `type`, `value`, `size`,
  16217. `placeholder`, `disabled`, `maxlength` and `tabindex` attributes on a
  16218. test field. If you need to support more attributes have a look at the
  16219. `attributeBindings` property in `Ember.View`'s HTML Attributes section.
  16220. To globally add support for additional attributes you can reopen
  16221. `Ember.TextField` or `Ember.TextSupport`.
  16222. ```javascript
  16223. Ember.TextSupport.reopen({
  16224. attributeBindings: ["required"]
  16225. })
  16226. ```
  16227. @class TextField
  16228. @namespace Ember
  16229. @extends Ember.View
  16230. @uses Ember.TextSupport
  16231. */
  16232. Ember.TextField = Ember.View.extend(Ember.TextSupport,
  16233. /** @scope Ember.TextField.prototype */ {
  16234. classNames: ['ember-text-field'],
  16235. tagName: "input",
  16236. attributeBindings: ['type', 'value', 'size', 'pattern'],
  16237. /**
  16238. The `value` attribute of the input element. As the user inputs text, this
  16239. property is updated live.
  16240. @property value
  16241. @type String
  16242. @default ""
  16243. */
  16244. value: "",
  16245. /**
  16246. The `type` attribute of the input element.
  16247. @property type
  16248. @type String
  16249. @default "text"
  16250. */
  16251. type: "text",
  16252. /**
  16253. The `size` of the text field in characters.
  16254. @property size
  16255. @type String
  16256. @default null
  16257. */
  16258. size: null,
  16259. /**
  16260. The `pattern` the pattern attribute of input element.
  16261. @property pattern
  16262. @type String
  16263. @default null
  16264. */
  16265. pattern: null,
  16266. /**
  16267. The action to be sent when the user presses the return key.
  16268. This is similar to the `{{action}}` helper, but is fired when
  16269. the user presses the return key when editing a text field, and sends
  16270. the value of the field as the context.
  16271. @property action
  16272. @type String
  16273. @default null
  16274. */
  16275. action: null,
  16276. /**
  16277. Whether they `keyUp` event that triggers an `action` to be sent continues
  16278. propagating to other views.
  16279. By default, when the user presses the return key on their keyboard and
  16280. the text field has an `action` set, the action will be sent to the view's
  16281. controller and the key event will stop propagating.
  16282. If you would like parent views to receive the `keyUp` event even after an
  16283. action has been dispatched, set `bubbles` to true.
  16284. @property bubbles
  16285. @type Boolean
  16286. @default false
  16287. */
  16288. bubbles: false,
  16289. insertNewline: function(event) {
  16290. var controller = get(this, 'controller'),
  16291. action = get(this, 'action');
  16292. if (action) {
  16293. controller.send(action, get(this, 'value'), this);
  16294. if (!get(this, 'bubbles')) {
  16295. event.stopPropagation();
  16296. }
  16297. }
  16298. }
  16299. });
  16300. })();
  16301. (function() {
  16302. /**
  16303. @module ember
  16304. @submodule ember-handlebars
  16305. */
  16306. var get = Ember.get, set = Ember.set;
  16307. /**
  16308. @class Button
  16309. @namespace Ember
  16310. @extends Ember.View
  16311. @uses Ember.TargetActionSupport
  16312. @deprecated
  16313. */
  16314. Ember.Button = Ember.View.extend(Ember.TargetActionSupport, {
  16315. classNames: ['ember-button'],
  16316. classNameBindings: ['isActive'],
  16317. tagName: 'button',
  16318. propagateEvents: false,
  16319. attributeBindings: ['type', 'disabled', 'href', 'tabindex'],
  16320. /**
  16321. @private
  16322. Overrides `TargetActionSupport`'s `targetObject` computed
  16323. property to use Handlebars-specific path resolution.
  16324. @property targetObject
  16325. */
  16326. targetObject: Ember.computed(function() {
  16327. var target = get(this, 'target'),
  16328. root = get(this, 'context'),
  16329. data = get(this, 'templateData');
  16330. if (typeof target !== 'string') { return target; }
  16331. return Ember.Handlebars.get(root, target, { data: data });
  16332. }).property('target'),
  16333. // Defaults to 'button' if tagName is 'input' or 'button'
  16334. type: Ember.computed(function(key) {
  16335. var tagName = this.tagName;
  16336. if (tagName === 'input' || tagName === 'button') { return 'button'; }
  16337. }),
  16338. disabled: false,
  16339. // Allow 'a' tags to act like buttons
  16340. href: Ember.computed(function() {
  16341. return this.tagName === 'a' ? '#' : null;
  16342. }),
  16343. mouseDown: function() {
  16344. if (!get(this, 'disabled')) {
  16345. set(this, 'isActive', true);
  16346. this._mouseDown = true;
  16347. this._mouseEntered = true;
  16348. }
  16349. return get(this, 'propagateEvents');
  16350. },
  16351. mouseLeave: function() {
  16352. if (this._mouseDown) {
  16353. set(this, 'isActive', false);
  16354. this._mouseEntered = false;
  16355. }
  16356. },
  16357. mouseEnter: function() {
  16358. if (this._mouseDown) {
  16359. set(this, 'isActive', true);
  16360. this._mouseEntered = true;
  16361. }
  16362. },
  16363. mouseUp: function(event) {
  16364. if (get(this, 'isActive')) {
  16365. // Actually invoke the button's target and action.
  16366. // This method comes from the Ember.TargetActionSupport mixin.
  16367. this.triggerAction();
  16368. set(this, 'isActive', false);
  16369. }
  16370. this._mouseDown = false;
  16371. this._mouseEntered = false;
  16372. return get(this, 'propagateEvents');
  16373. },
  16374. keyDown: function(event) {
  16375. // Handle space or enter
  16376. if (event.keyCode === 13 || event.keyCode === 32) {
  16377. this.mouseDown();
  16378. }
  16379. },
  16380. keyUp: function(event) {
  16381. // Handle space or enter
  16382. if (event.keyCode === 13 || event.keyCode === 32) {
  16383. this.mouseUp();
  16384. }
  16385. },
  16386. // TODO: Handle proper touch behavior. Including should make inactive when
  16387. // finger moves more than 20x outside of the edge of the button (vs mouse
  16388. // which goes inactive as soon as mouse goes out of edges.)
  16389. touchStart: function(touch) {
  16390. return this.mouseDown(touch);
  16391. },
  16392. touchEnd: function(touch) {
  16393. return this.mouseUp(touch);
  16394. },
  16395. init: function() {
  16396. Ember.deprecate("Ember.Button is deprecated and will be removed from future releases. Consider using the `{{action}}` helper.");
  16397. this._super();
  16398. }
  16399. });
  16400. })();
  16401. (function() {
  16402. /**
  16403. @module ember
  16404. @submodule ember-handlebars
  16405. */
  16406. var get = Ember.get, set = Ember.set;
  16407. /**
  16408. The `Ember.TextArea` view class renders a
  16409. [textarea](https://developer.mozilla.org/en/HTML/Element/textarea) element.
  16410. It allows for binding Ember properties to the text area contents (`value`),
  16411. live-updating as the user inputs text.
  16412. ## Layout and LayoutName properties
  16413. Because HTML `textarea` elements do not contain inner HTML the `layout` and
  16414. `layoutName` properties will not be applied. See `Ember.View`'s layout
  16415. section for more information.
  16416. ## HTML Attributes
  16417. By default `Ember.TextArea` provides support for `rows`, `cols`,
  16418. `placeholder`, `disabled`, `maxlength` and `tabindex` attributes on a
  16419. textarea. If you need to support more attributes have a look at the
  16420. `attributeBindings` property in `Ember.View`'s HTML Attributes section.
  16421. To globally add support for additional attributes you can reopen
  16422. `Ember.TextArea` or `Ember.TextSupport`.
  16423. ```javascript
  16424. Ember.TextSupport.reopen({
  16425. attributeBindings: ["required"]
  16426. })
  16427. ```
  16428. @class TextArea
  16429. @namespace Ember
  16430. @extends Ember.View
  16431. @uses Ember.TextSupport
  16432. */
  16433. Ember.TextArea = Ember.View.extend(Ember.TextSupport, {
  16434. classNames: ['ember-text-area'],
  16435. tagName: "textarea",
  16436. attributeBindings: ['rows', 'cols'],
  16437. rows: null,
  16438. cols: null,
  16439. _updateElementValue: Ember.observer(function() {
  16440. // We do this check so cursor position doesn't get affected in IE
  16441. var value = get(this, 'value'),
  16442. $el = this.$();
  16443. if ($el && value !== $el.val()) {
  16444. $el.val(value);
  16445. }
  16446. }, 'value'),
  16447. init: function() {
  16448. this._super();
  16449. this.on("didInsertElement", this, this._updateElementValue);
  16450. }
  16451. });
  16452. })();
  16453. (function() {
  16454. /*jshint eqeqeq:false */
  16455. /**
  16456. @module ember
  16457. @submodule ember-handlebars
  16458. */
  16459. var set = Ember.set,
  16460. get = Ember.get,
  16461. indexOf = Ember.EnumerableUtils.indexOf,
  16462. indexesOf = Ember.EnumerableUtils.indexesOf,
  16463. replace = Ember.EnumerableUtils.replace,
  16464. isArray = Ember.isArray,
  16465. precompileTemplate = Ember.Handlebars.compile;
  16466. /**
  16467. The `Ember.Select` view class renders a
  16468. [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element,
  16469. allowing the user to choose from a list of options.
  16470. The text and `value` property of each `<option>` element within the
  16471. `<select>` element are populated from the objects in the `Element.Select`'s
  16472. `content` property. The underlying data object of the selected `<option>` is
  16473. stored in the `Element.Select`'s `value` property.
  16474. ### `content` as an array of Strings
  16475. The simplest version of an `Ember.Select` takes an array of strings as its
  16476. `content` property. The string will be used as both the `value` property and
  16477. the inner text of each `<option>` element inside the rendered `<select>`.
  16478. Example:
  16479. ```javascript
  16480. App.names = ["Yehuda", "Tom"];
  16481. ```
  16482. ```handlebars
  16483. {{view Ember.Select contentBinding="App.names"}}
  16484. ```
  16485. Would result in the following HTML:
  16486. ```html
  16487. <select class="ember-select">
  16488. <option value="Yehuda">Yehuda</option>
  16489. <option value="Tom">Tom</option>
  16490. </select>
  16491. ```
  16492. You can control which `<option>` is selected through the `Ember.Select`'s
  16493. `value` property directly or as a binding:
  16494. ```javascript
  16495. App.names = Ember.Object.create({
  16496. selected: 'Tom',
  16497. content: ["Yehuda", "Tom"]
  16498. });
  16499. ```
  16500. ```handlebars
  16501. {{view Ember.Select
  16502. contentBinding="App.names.content"
  16503. valueBinding="App.names.selected"
  16504. }}
  16505. ```
  16506. Would result in the following HTML with the `<option>` for 'Tom' selected:
  16507. ```html
  16508. <select class="ember-select">
  16509. <option value="Yehuda">Yehuda</option>
  16510. <option value="Tom" selected="selected">Tom</option>
  16511. </select>
  16512. ```
  16513. A user interacting with the rendered `<select>` to choose "Yehuda" would
  16514. update the value of `App.names.selected` to "Yehuda".
  16515. ### `content` as an Array of Objects
  16516. An `Ember.Select` can also take an array of JavaScript or Ember objects as
  16517. its `content` property.
  16518. When using objects you need to tell the `Ember.Select` which property should
  16519. be accessed on each object to supply the `value` attribute of the `<option>`
  16520. and which property should be used to supply the element text.
  16521. The `optionValuePath` option is used to specify the path on each object to
  16522. the desired property for the `value` attribute. The `optionLabelPath`
  16523. specifies the path on each object to the desired property for the
  16524. element's text. Both paths must reference each object itself as `content`:
  16525. ```javascript
  16526. App.programmers = [
  16527. Ember.Object.create({firstName: "Yehuda", id: 1}),
  16528. Ember.Object.create({firstName: "Tom", id: 2})
  16529. ];
  16530. ```
  16531. ```handlebars
  16532. {{view Ember.Select
  16533. contentBinding="App.programmers"
  16534. optionValuePath="content.id"
  16535. optionLabelPath="content.firstName"}}
  16536. ```
  16537. Would result in the following HTML:
  16538. ```html
  16539. <select class="ember-select">
  16540. <option value>Please Select</option>
  16541. <option value="1">Yehuda</option>
  16542. <option value="2">Tom</option>
  16543. </select>
  16544. ```
  16545. The `value` attribute of the selected `<option>` within an `Ember.Select`
  16546. can be bound to a property on another object by providing a
  16547. `valueBinding` option:
  16548. ```javascript
  16549. App.programmers = [
  16550. Ember.Object.create({firstName: "Yehuda", id: 1}),
  16551. Ember.Object.create({firstName: "Tom", id: 2})
  16552. ];
  16553. App.currentProgrammer = Ember.Object.create({
  16554. id: 2
  16555. });
  16556. ```
  16557. ```handlebars
  16558. {{view Ember.Select
  16559. contentBinding="App.programmers"
  16560. optionValuePath="content.id"
  16561. optionLabelPath="content.firstName"
  16562. valueBinding="App.currentProgrammer.id"}}
  16563. ```
  16564. Would result in the following HTML with a selected option:
  16565. ```html
  16566. <select class="ember-select">
  16567. <option value>Please Select</option>
  16568. <option value="1">Yehuda</option>
  16569. <option value="2" selected="selected">Tom</option>
  16570. </select>
  16571. ```
  16572. Interacting with the rendered element by selecting the first option
  16573. ('Yehuda') will update the `id` value of `App.currentProgrammer`
  16574. to match the `value` property of the newly selected `<option>`.
  16575. Alternatively, you can control selection through the underlying objects
  16576. used to render each object providing a `selectionBinding`. When the selected
  16577. `<option>` is changed, the property path provided to `selectionBinding`
  16578. will be updated to match the content object of the rendered `<option>`
  16579. element:
  16580. ```javascript
  16581. App.controller = Ember.Object.create({
  16582. selectedPerson: null,
  16583. content: [
  16584. Ember.Object.create({firstName: "Yehuda", id: 1}),
  16585. Ember.Object.create({firstName: "Tom", id: 2})
  16586. ]
  16587. });
  16588. ```
  16589. ```handlebars
  16590. {{view Ember.Select
  16591. contentBinding="App.controller.content"
  16592. optionValuePath="content.id"
  16593. optionLabelPath="content.firstName"
  16594. selectionBinding="App.controller.selectedPerson"}}
  16595. ```
  16596. Would result in the following HTML with a selected option:
  16597. ```html
  16598. <select class="ember-select">
  16599. <option value>Please Select</option>
  16600. <option value="1">Yehuda</option>
  16601. <option value="2" selected="selected">Tom</option>
  16602. </select>
  16603. ```
  16604. Interacting with the rendered element by selecting the first option
  16605. ('Yehuda') will update the `selectedPerson` value of `App.controller`
  16606. to match the content object of the newly selected `<option>`. In this
  16607. case it is the first object in the `App.content.content`
  16608. ### Supplying a Prompt
  16609. A `null` value for the `Ember.Select`'s `value` or `selection` property
  16610. results in there being no `<option>` with a `selected` attribute:
  16611. ```javascript
  16612. App.controller = Ember.Object.create({
  16613. selected: null,
  16614. content: [
  16615. "Yehuda",
  16616. "Tom"
  16617. ]
  16618. });
  16619. ```
  16620. ``` handlebars
  16621. {{view Ember.Select
  16622. contentBinding="App.controller.content"
  16623. valueBinding="App.controller.selected"
  16624. }}
  16625. ```
  16626. Would result in the following HTML:
  16627. ```html
  16628. <select class="ember-select">
  16629. <option value="Yehuda">Yehuda</option>
  16630. <option value="Tom">Tom</option>
  16631. </select>
  16632. ```
  16633. Although `App.controller.selected` is `null` and no `<option>`
  16634. has a `selected` attribute the rendered HTML will display the
  16635. first item as though it were selected. You can supply a string
  16636. value for the `Ember.Select` to display when there is no selection
  16637. with the `prompt` option:
  16638. ```javascript
  16639. App.controller = Ember.Object.create({
  16640. selected: null,
  16641. content: [
  16642. "Yehuda",
  16643. "Tom"
  16644. ]
  16645. });
  16646. ```
  16647. ```handlebars
  16648. {{view Ember.Select
  16649. contentBinding="App.controller.content"
  16650. valueBinding="App.controller.selected"
  16651. prompt="Please select a name"
  16652. }}
  16653. ```
  16654. Would result in the following HTML:
  16655. ```html
  16656. <select class="ember-select">
  16657. <option>Please select a name</option>
  16658. <option value="Yehuda">Yehuda</option>
  16659. <option value="Tom">Tom</option>
  16660. </select>
  16661. ```
  16662. @class Select
  16663. @namespace Ember
  16664. @extends Ember.View
  16665. */
  16666. Ember.Select = Ember.View.extend(
  16667. /** @scope Ember.Select.prototype */ {
  16668. tagName: 'select',
  16669. classNames: ['ember-select'],
  16670. defaultTemplate: Ember.Handlebars.template(function anonymous(Handlebars,depth0,helpers,partials,data) {
  16671. this.compilerInfo = [2,'>= 1.0.0-rc.3'];
  16672. helpers = helpers || Ember.Handlebars.helpers; data = data || {};
  16673. var buffer = '', stack1, hashTypes, escapeExpression=this.escapeExpression, self=this;
  16674. function program1(depth0,data) {
  16675. var buffer = '', hashTypes;
  16676. data.buffer.push("<option value=\"\">");
  16677. hashTypes = {};
  16678. data.buffer.push(escapeExpression(helpers._triageMustache.call(depth0, "view.prompt", {hash:{},contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data})));
  16679. data.buffer.push("</option>");
  16680. return buffer;
  16681. }
  16682. function program3(depth0,data) {
  16683. var hashTypes;
  16684. hashTypes = {'contentBinding': "STRING"};
  16685. data.buffer.push(escapeExpression(helpers.view.call(depth0, "Ember.SelectOption", {hash:{
  16686. 'contentBinding': ("this")
  16687. },contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data})));
  16688. }
  16689. hashTypes = {};
  16690. stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data});
  16691. if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
  16692. hashTypes = {};
  16693. stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data});
  16694. if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
  16695. return buffer;
  16696. }),
  16697. attributeBindings: ['multiple', 'disabled', 'tabindex'],
  16698. /**
  16699. The `multiple` attribute of the select element. Indicates whether multiple
  16700. options can be selected.
  16701. @property multiple
  16702. @type Boolean
  16703. @default false
  16704. */
  16705. multiple: false,
  16706. disabled: false,
  16707. /**
  16708. The list of options.
  16709. If `optionLabelPath` and `optionValuePath` are not overridden, this should
  16710. be a list of strings, which will serve simultaneously as labels and values.
  16711. Otherwise, this should be a list of objects. For instance:
  16712. ```javascript
  16713. Ember.Select.create({
  16714. content: Ember.A([
  16715. { id: 1, firstName: 'Yehuda' },
  16716. { id: 2, firstName: 'Tom' }
  16717. ]),
  16718. optionLabelPath: 'content.firstName',
  16719. optionValuePath: 'content.id'
  16720. });
  16721. ```
  16722. @property content
  16723. @type Array
  16724. @default null
  16725. */
  16726. content: null,
  16727. /**
  16728. When `multiple` is `false`, the element of `content` that is currently
  16729. selected, if any.
  16730. When `multiple` is `true`, an array of such elements.
  16731. @property selection
  16732. @type Object or Array
  16733. @default null
  16734. */
  16735. selection: null,
  16736. /**
  16737. In single selection mode (when `multiple` is `false`), value can be used to
  16738. get the current selection's value or set the selection by it's value.
  16739. It is not currently supported in multiple selection mode.
  16740. @property value
  16741. @type String
  16742. @default null
  16743. */
  16744. value: Ember.computed(function(key, value) {
  16745. if (arguments.length === 2) { return value; }
  16746. var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, '');
  16747. return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection');
  16748. }).property('selection'),
  16749. /**
  16750. If given, a top-most dummy option will be rendered to serve as a user
  16751. prompt.
  16752. @property prompt
  16753. @type String
  16754. @default null
  16755. */
  16756. prompt: null,
  16757. /**
  16758. The path of the option labels. See `content`.
  16759. @property optionLabelPath
  16760. @type String
  16761. @default 'content'
  16762. */
  16763. optionLabelPath: 'content',
  16764. /**
  16765. The path of the option values. See `content`.
  16766. @property optionValuePath
  16767. @type String
  16768. @default 'content'
  16769. */
  16770. optionValuePath: 'content',
  16771. _change: function() {
  16772. if (get(this, 'multiple')) {
  16773. this._changeMultiple();
  16774. } else {
  16775. this._changeSingle();
  16776. }
  16777. },
  16778. selectionDidChange: Ember.observer(function() {
  16779. var selection = get(this, 'selection');
  16780. if (get(this, 'multiple')) {
  16781. if (!isArray(selection)) {
  16782. set(this, 'selection', Ember.A([selection]));
  16783. return;
  16784. }
  16785. this._selectionDidChangeMultiple();
  16786. } else {
  16787. this._selectionDidChangeSingle();
  16788. }
  16789. }, 'selection.@each'),
  16790. valueDidChange: Ember.observer(function() {
  16791. var content = get(this, 'content'),
  16792. value = get(this, 'value'),
  16793. valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''),
  16794. selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')),
  16795. selection;
  16796. if (value !== selectedValue) {
  16797. selection = content.find(function(obj) {
  16798. return value === (valuePath ? get(obj, valuePath) : obj);
  16799. });
  16800. this.set('selection', selection);
  16801. }
  16802. }, 'value'),
  16803. _triggerChange: function() {
  16804. var selection = get(this, 'selection');
  16805. var value = get(this, 'value');
  16806. if (selection) { this.selectionDidChange(); }
  16807. if (value) { this.valueDidChange(); }
  16808. this._change();
  16809. },
  16810. _changeSingle: function() {
  16811. var selectedIndex = this.$()[0].selectedIndex,
  16812. content = get(this, 'content'),
  16813. prompt = get(this, 'prompt');
  16814. if (!get(content, 'length')) { return; }
  16815. if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; }
  16816. if (prompt) { selectedIndex -= 1; }
  16817. set(this, 'selection', content.objectAt(selectedIndex));
  16818. },
  16819. _changeMultiple: function() {
  16820. var options = this.$('option:selected'),
  16821. prompt = get(this, 'prompt'),
  16822. offset = prompt ? 1 : 0,
  16823. content = get(this, 'content'),
  16824. selection = get(this, 'selection');
  16825. if (!content){ return; }
  16826. if (options) {
  16827. var selectedIndexes = options.map(function(){
  16828. return this.index - offset;
  16829. }).toArray();
  16830. var newSelection = content.objectsAt(selectedIndexes);
  16831. if (isArray(selection)) {
  16832. replace(selection, 0, get(selection, 'length'), newSelection);
  16833. } else {
  16834. set(this, 'selection', newSelection);
  16835. }
  16836. }
  16837. },
  16838. _selectionDidChangeSingle: function() {
  16839. var el = this.get('element');
  16840. if (!el) { return; }
  16841. var content = get(this, 'content'),
  16842. selection = get(this, 'selection'),
  16843. selectionIndex = content ? indexOf(content, selection) : -1,
  16844. prompt = get(this, 'prompt');
  16845. if (prompt) { selectionIndex += 1; }
  16846. if (el) { el.selectedIndex = selectionIndex; }
  16847. },
  16848. _selectionDidChangeMultiple: function() {
  16849. var content = get(this, 'content'),
  16850. selection = get(this, 'selection'),
  16851. selectedIndexes = content ? indexesOf(content, selection) : [-1],
  16852. prompt = get(this, 'prompt'),
  16853. offset = prompt ? 1 : 0,
  16854. options = this.$('option'),
  16855. adjusted;
  16856. if (options) {
  16857. options.each(function() {
  16858. adjusted = this.index > -1 ? this.index - offset : -1;
  16859. this.selected = indexOf(selectedIndexes, adjusted) > -1;
  16860. });
  16861. }
  16862. },
  16863. init: function() {
  16864. this._super();
  16865. this.on("didInsertElement", this, this._triggerChange);
  16866. this.on("change", this, this._change);
  16867. }
  16868. });
  16869. Ember.SelectOption = Ember.View.extend({
  16870. tagName: 'option',
  16871. attributeBindings: ['value', 'selected'],
  16872. defaultTemplate: function(context, options) {
  16873. options = { data: options.data, hash: {} };
  16874. Ember.Handlebars.helpers.bind.call(context, "view.label", options);
  16875. },
  16876. init: function() {
  16877. this.labelPathDidChange();
  16878. this.valuePathDidChange();
  16879. this._super();
  16880. },
  16881. selected: Ember.computed(function() {
  16882. var content = get(this, 'content'),
  16883. selection = get(this, 'parentView.selection');
  16884. if (get(this, 'parentView.multiple')) {
  16885. return selection && indexOf(selection, content.valueOf()) > -1;
  16886. } else {
  16887. // Primitives get passed through bindings as objects... since
  16888. // `new Number(4) !== 4`, we use `==` below
  16889. return content == selection;
  16890. }
  16891. }).property('content', 'parentView.selection').volatile(),
  16892. labelPathDidChange: Ember.observer(function() {
  16893. var labelPath = get(this, 'parentView.optionLabelPath');
  16894. if (!labelPath) { return; }
  16895. Ember.defineProperty(this, 'label', Ember.computed(function() {
  16896. return get(this, labelPath);
  16897. }).property(labelPath));
  16898. }, 'parentView.optionLabelPath'),
  16899. valuePathDidChange: Ember.observer(function() {
  16900. var valuePath = get(this, 'parentView.optionValuePath');
  16901. if (!valuePath) { return; }
  16902. Ember.defineProperty(this, 'value', Ember.computed(function() {
  16903. return get(this, valuePath);
  16904. }).property(valuePath));
  16905. }, 'parentView.optionValuePath')
  16906. });
  16907. })();
  16908. (function() {
  16909. })();
  16910. (function() {
  16911. /*globals Handlebars */
  16912. /**
  16913. @module ember
  16914. @submodule ember-handlebars
  16915. */
  16916. /**
  16917. @private
  16918. Find templates stored in the head tag as script tags and make them available
  16919. to `Ember.CoreView` in the global `Ember.TEMPLATES` object. This will be run
  16920. as as jQuery DOM-ready callback.
  16921. Script tags with `text/x-handlebars` will be compiled
  16922. with Ember's Handlebars and are suitable for use as a view's template.
  16923. Those with type `text/x-raw-handlebars` will be compiled with regular
  16924. Handlebars and are suitable for use in views' computed properties.
  16925. @method bootstrap
  16926. @for Ember.Handlebars
  16927. @static
  16928. @param ctx
  16929. */
  16930. Ember.Handlebars.bootstrap = function(ctx) {
  16931. var selectors = 'script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]';
  16932. Ember.$(selectors, ctx)
  16933. .each(function() {
  16934. // Get a reference to the script tag
  16935. var script = Ember.$(this),
  16936. type = script.attr('type');
  16937. var compile = (script.attr('type') === 'text/x-raw-handlebars') ?
  16938. Ember.$.proxy(Handlebars.compile, Handlebars) :
  16939. Ember.$.proxy(Ember.Handlebars.compile, Ember.Handlebars),
  16940. // Get the name of the script, used by Ember.View's templateName property.
  16941. // First look for data-template-name attribute, then fall back to its
  16942. // id if no name is found.
  16943. templateName = script.attr('data-template-name') || script.attr('id') || 'application',
  16944. template = compile(script.html());
  16945. // For templates which have a name, we save them and then remove them from the DOM
  16946. Ember.TEMPLATES[templateName] = template;
  16947. // Remove script tag from DOM
  16948. script.remove();
  16949. });
  16950. };
  16951. function bootstrap() {
  16952. Ember.Handlebars.bootstrap( Ember.$(document) );
  16953. }
  16954. /*
  16955. We tie this to application.load to ensure that we've at least
  16956. attempted to bootstrap at the point that the application is loaded.
  16957. We also tie this to document ready since we're guaranteed that all
  16958. the inline templates are present at this point.
  16959. There's no harm to running this twice, since we remove the templates
  16960. from the DOM after processing.
  16961. */
  16962. Ember.onLoad('application', bootstrap);
  16963. })();
  16964. (function() {
  16965. /**
  16966. Ember Handlebars
  16967. @module ember
  16968. @submodule ember-handlebars
  16969. @requires ember-views
  16970. */
  16971. Ember.runLoadHooks('Ember.Handlebars', Ember.Handlebars);
  16972. })();
  16973. (function() {
  16974. define("route-recognizer",
  16975. [],
  16976. function() {
  16977. "use strict";
  16978. var specials = [
  16979. '/', '.', '*', '+', '?', '|',
  16980. '(', ')', '[', ']', '{', '}', '\\'
  16981. ];
  16982. var escapeRegex = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
  16983. // A Segment represents a segment in the original route description.
  16984. // Each Segment type provides an `eachChar` and `regex` method.
  16985. //
  16986. // The `eachChar` method invokes the callback with one or more character
  16987. // specifications. A character specification consumes one or more input
  16988. // characters.
  16989. //
  16990. // The `regex` method returns a regex fragment for the segment. If the
  16991. // segment is a dynamic of star segment, the regex fragment also includes
  16992. // a capture.
  16993. //
  16994. // A character specification contains:
  16995. //
  16996. // * `validChars`: a String with a list of all valid characters, or
  16997. // * `invalidChars`: a String with a list of all invalid characters
  16998. // * `repeat`: true if the character specification can repeat
  16999. function StaticSegment(string) { this.string = string; }
  17000. StaticSegment.prototype = {
  17001. eachChar: function(callback) {
  17002. var string = this.string, char;
  17003. for (var i=0, l=string.length; i<l; i++) {
  17004. char = string.charAt(i);
  17005. callback({ validChars: char });
  17006. }
  17007. },
  17008. regex: function() {
  17009. return this.string.replace(escapeRegex, '\\$1');
  17010. },
  17011. generate: function() {
  17012. return this.string;
  17013. }
  17014. };
  17015. function DynamicSegment(name) { this.name = name; }
  17016. DynamicSegment.prototype = {
  17017. eachChar: function(callback) {
  17018. callback({ invalidChars: "/", repeat: true });
  17019. },
  17020. regex: function() {
  17021. return "([^/]+)";
  17022. },
  17023. generate: function(params) {
  17024. return params[this.name];
  17025. }
  17026. };
  17027. function StarSegment(name) { this.name = name; }
  17028. StarSegment.prototype = {
  17029. eachChar: function(callback) {
  17030. callback({ invalidChars: "", repeat: true });
  17031. },
  17032. regex: function() {
  17033. return "(.+)";
  17034. },
  17035. generate: function(params) {
  17036. return params[this.name];
  17037. }
  17038. };
  17039. function EpsilonSegment() {}
  17040. EpsilonSegment.prototype = {
  17041. eachChar: function() {},
  17042. regex: function() { return ""; },
  17043. generate: function() { return ""; }
  17044. };
  17045. function parse(route, names, types) {
  17046. // normalize route as not starting with a "/". Recognition will
  17047. // also normalize.
  17048. if (route.charAt(0) === "/") { route = route.substr(1); }
  17049. var segments = route.split("/"), results = [];
  17050. for (var i=0, l=segments.length; i<l; i++) {
  17051. var segment = segments[i], match;
  17052. if (match = segment.match(/^:([^\/]+)$/)) {
  17053. results.push(new DynamicSegment(match[1]));
  17054. names.push(match[1]);
  17055. types.dynamics++;
  17056. } else if (match = segment.match(/^\*([^\/]+)$/)) {
  17057. results.push(new StarSegment(match[1]));
  17058. names.push(match[1]);
  17059. types.stars++;
  17060. } else if(segment === "") {
  17061. results.push(new EpsilonSegment());
  17062. } else {
  17063. results.push(new StaticSegment(segment));
  17064. types.statics++;
  17065. }
  17066. }
  17067. return results;
  17068. }
  17069. // A State has a character specification and (`charSpec`) and a list of possible
  17070. // subsequent states (`nextStates`).
  17071. //
  17072. // If a State is an accepting state, it will also have several additional
  17073. // properties:
  17074. //
  17075. // * `regex`: A regular expression that is used to extract parameters from paths
  17076. // that reached this accepting state.
  17077. // * `handlers`: Information on how to convert the list of captures into calls
  17078. // to registered handlers with the specified parameters
  17079. // * `types`: How many static, dynamic or star segments in this route. Used to
  17080. // decide which route to use if multiple registered routes match a path.
  17081. //
  17082. // Currently, State is implemented naively by looping over `nextStates` and
  17083. // comparing a character specification against a character. A more efficient
  17084. // implementation would use a hash of keys pointing at one or more next states.
  17085. function State(charSpec) {
  17086. this.charSpec = charSpec;
  17087. this.nextStates = [];
  17088. }
  17089. State.prototype = {
  17090. get: function(charSpec) {
  17091. var nextStates = this.nextStates;
  17092. for (var i=0, l=nextStates.length; i<l; i++) {
  17093. var child = nextStates[i];
  17094. var isEqual = child.charSpec.validChars === charSpec.validChars;
  17095. isEqual = isEqual && child.charSpec.invalidChars === charSpec.invalidChars;
  17096. if (isEqual) { return child; }
  17097. }
  17098. },
  17099. put: function(charSpec) {
  17100. var state;
  17101. // If the character specification already exists in a child of the current
  17102. // state, just return that state.
  17103. if (state = this.get(charSpec)) { return state; }
  17104. // Make a new state for the character spec
  17105. state = new State(charSpec);
  17106. // Insert the new state as a child of the current state
  17107. this.nextStates.push(state);
  17108. // If this character specification repeats, insert the new state as a child
  17109. // of itself. Note that this will not trigger an infinite loop because each
  17110. // transition during recognition consumes a character.
  17111. if (charSpec.repeat) {
  17112. state.nextStates.push(state);
  17113. }
  17114. // Return the new state
  17115. return state;
  17116. },
  17117. // Find a list of child states matching the next character
  17118. match: function(char) {
  17119. // DEBUG "Processing `" + char + "`:"
  17120. var nextStates = this.nextStates,
  17121. child, charSpec, chars;
  17122. // DEBUG " " + debugState(this)
  17123. var returned = [];
  17124. for (var i=0, l=nextStates.length; i<l; i++) {
  17125. child = nextStates[i];
  17126. charSpec = child.charSpec;
  17127. if (typeof (chars = charSpec.validChars) !== 'undefined') {
  17128. if (chars.indexOf(char) !== -1) { returned.push(child); }
  17129. } else if (typeof (chars = charSpec.invalidChars) !== 'undefined') {
  17130. if (chars.indexOf(char) === -1) { returned.push(child); }
  17131. }
  17132. }
  17133. return returned;
  17134. }
  17135. /** IF DEBUG
  17136. , debug: function() {
  17137. var charSpec = this.charSpec,
  17138. debug = "[",
  17139. chars = charSpec.validChars || charSpec.invalidChars;
  17140. if (charSpec.invalidChars) { debug += "^"; }
  17141. debug += chars;
  17142. debug += "]";
  17143. if (charSpec.repeat) { debug += "+"; }
  17144. return debug;
  17145. }
  17146. END IF **/
  17147. };
  17148. /** IF DEBUG
  17149. function debug(log) {
  17150. console.log(log);
  17151. }
  17152. function debugState(state) {
  17153. return state.nextStates.map(function(n) {
  17154. if (n.nextStates.length === 0) { return "( " + n.debug() + " [accepting] )"; }
  17155. return "( " + n.debug() + " <then> " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )";
  17156. }).join(", ")
  17157. }
  17158. END IF **/
  17159. // This is a somewhat naive strategy, but should work in a lot of cases
  17160. // A better strategy would properly resolve /posts/:id/new and /posts/edit/:id
  17161. function sortSolutions(states) {
  17162. return states.sort(function(a, b) {
  17163. if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; }
  17164. if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; }
  17165. if (a.types.statics !== b.types.statics) { return a.types.statics - b.types.statics; }
  17166. return 0;
  17167. });
  17168. }
  17169. function recognizeChar(states, char) {
  17170. var nextStates = [];
  17171. for (var i=0, l=states.length; i<l; i++) {
  17172. var state = states[i];
  17173. nextStates = nextStates.concat(state.match(char));
  17174. }
  17175. return nextStates;
  17176. }
  17177. function findHandler(state, path) {
  17178. var handlers = state.handlers, regex = state.regex;
  17179. var captures = path.match(regex), currentCapture = 1;
  17180. var result = [];
  17181. for (var i=0, l=handlers.length; i<l; i++) {
  17182. var handler = handlers[i], names = handler.names, params = {};
  17183. for (var j=0, m=names.length; j<m; j++) {
  17184. params[names[j]] = captures[currentCapture++];
  17185. }
  17186. result.push({ handler: handler.handler, params: params, isDynamic: !!names.length });
  17187. }
  17188. return result;
  17189. }
  17190. function addSegment(currentState, segment) {
  17191. segment.eachChar(function(char) {
  17192. var state;
  17193. currentState = currentState.put(char);
  17194. });
  17195. return currentState;
  17196. }
  17197. // The main interface
  17198. var RouteRecognizer = function() {
  17199. this.rootState = new State();
  17200. this.names = {};
  17201. };
  17202. RouteRecognizer.prototype = {
  17203. add: function(routes, options) {
  17204. var currentState = this.rootState, regex = "^",
  17205. types = { statics: 0, dynamics: 0, stars: 0 },
  17206. handlers = [], allSegments = [], name;
  17207. var isEmpty = true;
  17208. for (var i=0, l=routes.length; i<l; i++) {
  17209. var route = routes[i], names = [];
  17210. var segments = parse(route.path, names, types);
  17211. allSegments = allSegments.concat(segments);
  17212. for (var j=0, m=segments.length; j<m; j++) {
  17213. var segment = segments[j];
  17214. if (segment instanceof EpsilonSegment) { continue; }
  17215. isEmpty = false;
  17216. // Add a "/" for the new segment
  17217. currentState = currentState.put({ validChars: "/" });
  17218. regex += "/";
  17219. // Add a representation of the segment to the NFA and regex
  17220. currentState = addSegment(currentState, segment);
  17221. regex += segment.regex();
  17222. }
  17223. handlers.push({ handler: route.handler, names: names });
  17224. }
  17225. if (isEmpty) {
  17226. currentState = currentState.put({ validChars: "/" });
  17227. regex += "/";
  17228. }
  17229. currentState.handlers = handlers;
  17230. currentState.regex = new RegExp(regex + "$");
  17231. currentState.types = types;
  17232. if (name = options && options.as) {
  17233. this.names[name] = {
  17234. segments: allSegments,
  17235. handlers: handlers
  17236. };
  17237. }
  17238. },
  17239. handlersFor: function(name) {
  17240. var route = this.names[name], result = [];
  17241. if (!route) { throw new Error("There is no route named " + name); }
  17242. for (var i=0, l=route.handlers.length; i<l; i++) {
  17243. result.push(route.handlers[i]);
  17244. }
  17245. return result;
  17246. },
  17247. hasRoute: function(name) {
  17248. return !!this.names[name];
  17249. },
  17250. generate: function(name, params) {
  17251. var route = this.names[name], output = "";
  17252. if (!route) { throw new Error("There is no route named " + name); }
  17253. var segments = route.segments;
  17254. for (var i=0, l=segments.length; i<l; i++) {
  17255. var segment = segments[i];
  17256. if (segment instanceof EpsilonSegment) { continue; }
  17257. output += "/";
  17258. output += segment.generate(params);
  17259. }
  17260. if (output.charAt(0) !== '/') { output = '/' + output; }
  17261. return output;
  17262. },
  17263. recognize: function(path) {
  17264. var states = [ this.rootState ], i, l;
  17265. // DEBUG GROUP path
  17266. var pathLen = path.length;
  17267. if (path.charAt(0) !== "/") { path = "/" + path; }
  17268. if (pathLen > 1 && path.charAt(pathLen - 1) === "/") {
  17269. path = path.substr(0, pathLen - 1);
  17270. }
  17271. for (i=0, l=path.length; i<l; i++) {
  17272. states = recognizeChar(states, path.charAt(i));
  17273. if (!states.length) { break; }
  17274. }
  17275. // END DEBUG GROUP
  17276. var solutions = [];
  17277. for (i=0, l=states.length; i<l; i++) {
  17278. if (states[i].handlers) { solutions.push(states[i]); }
  17279. }
  17280. states = sortSolutions(solutions);
  17281. var state = solutions[0];
  17282. if (state && state.handlers) {
  17283. return findHandler(state, path);
  17284. }
  17285. }
  17286. };
  17287. function Target(path, matcher, delegate) {
  17288. this.path = path;
  17289. this.matcher = matcher;
  17290. this.delegate = delegate;
  17291. }
  17292. Target.prototype = {
  17293. to: function(target, callback) {
  17294. var delegate = this.delegate;
  17295. if (delegate && delegate.willAddRoute) {
  17296. target = delegate.willAddRoute(this.matcher.target, target);
  17297. }
  17298. this.matcher.add(this.path, target);
  17299. if (callback) {
  17300. if (callback.length === 0) { throw new Error("You must have an argument in the function passed to `to`"); }
  17301. this.matcher.addChild(this.path, target, callback, this.delegate);
  17302. }
  17303. }
  17304. };
  17305. function Matcher(target) {
  17306. this.routes = {};
  17307. this.children = {};
  17308. this.target = target;
  17309. }
  17310. Matcher.prototype = {
  17311. add: function(path, handler) {
  17312. this.routes[path] = handler;
  17313. },
  17314. addChild: function(path, target, callback, delegate) {
  17315. var matcher = new Matcher(target);
  17316. this.children[path] = matcher;
  17317. var match = generateMatch(path, matcher, delegate);
  17318. if (delegate && delegate.contextEntered) {
  17319. delegate.contextEntered(target, match);
  17320. }
  17321. callback(match);
  17322. }
  17323. };
  17324. function generateMatch(startingPath, matcher, delegate) {
  17325. return function(path, nestedCallback) {
  17326. var fullPath = startingPath + path;
  17327. if (nestedCallback) {
  17328. nestedCallback(generateMatch(fullPath, matcher, delegate));
  17329. } else {
  17330. return new Target(startingPath + path, matcher, delegate);
  17331. }
  17332. };
  17333. }
  17334. function addRoute(routeArray, path, handler) {
  17335. var len = 0;
  17336. for (var i=0, l=routeArray.length; i<l; i++) {
  17337. len += routeArray[i].path.length;
  17338. }
  17339. path = path.substr(len);
  17340. routeArray.push({ path: path, handler: handler });
  17341. }
  17342. function eachRoute(baseRoute, matcher, callback, binding) {
  17343. var routes = matcher.routes;
  17344. for (var path in routes) {
  17345. if (routes.hasOwnProperty(path)) {
  17346. var routeArray = baseRoute.slice();
  17347. addRoute(routeArray, path, routes[path]);
  17348. if (matcher.children[path]) {
  17349. eachRoute(routeArray, matcher.children[path], callback, binding);
  17350. } else {
  17351. callback.call(binding, routeArray);
  17352. }
  17353. }
  17354. }
  17355. }
  17356. RouteRecognizer.prototype.map = function(callback, addRouteCallback) {
  17357. var matcher = new Matcher();
  17358. callback(generateMatch("", matcher, this.delegate));
  17359. eachRoute([], matcher, function(route) {
  17360. if (addRouteCallback) { addRouteCallback(this, route); }
  17361. else { this.add(route); }
  17362. }, this);
  17363. };
  17364. return RouteRecognizer;
  17365. });
  17366. })();
  17367. (function() {
  17368. define("router",
  17369. ["route-recognizer"],
  17370. function(RouteRecognizer) {
  17371. "use strict";
  17372. /**
  17373. @private
  17374. This file references several internal structures:
  17375. ## `RecognizedHandler`
  17376. * `{String} handler`: A handler name
  17377. * `{Object} params`: A hash of recognized parameters
  17378. ## `UnresolvedHandlerInfo`
  17379. * `{Boolean} isDynamic`: whether a handler has any dynamic segments
  17380. * `{String} name`: the name of a handler
  17381. * `{Object} context`: the active context for the handler
  17382. ## `HandlerInfo`
  17383. * `{Boolean} isDynamic`: whether a handler has any dynamic segments
  17384. * `{String} name`: the original unresolved handler name
  17385. * `{Object} handler`: a handler object
  17386. * `{Object} context`: the active context for the handler
  17387. */
  17388. function Router() {
  17389. this.recognizer = new RouteRecognizer();
  17390. }
  17391. Router.prototype = {
  17392. /**
  17393. The main entry point into the router. The API is essentially
  17394. the same as the `map` method in `route-recognizer`.
  17395. This method extracts the String handler at the last `.to()`
  17396. call and uses it as the name of the whole route.
  17397. @param {Function} callback
  17398. */
  17399. map: function(callback) {
  17400. this.recognizer.delegate = this.delegate;
  17401. this.recognizer.map(callback, function(recognizer, route) {
  17402. var lastHandler = route[route.length - 1].handler;
  17403. var args = [route, { as: lastHandler }];
  17404. recognizer.add.apply(recognizer, args);
  17405. });
  17406. },
  17407. hasRoute: function(route) {
  17408. return this.recognizer.hasRoute(route);
  17409. },
  17410. /**
  17411. The entry point for handling a change to the URL (usually
  17412. via the back and forward button).
  17413. Returns an Array of handlers and the parameters associated
  17414. with those parameters.
  17415. @param {String} url a URL to process
  17416. @return {Array} an Array of `[handler, parameter]` tuples
  17417. */
  17418. handleURL: function(url) {
  17419. var results = this.recognizer.recognize(url),
  17420. objects = [];
  17421. if (!results) {
  17422. throw new Error("No route matched the URL '" + url + "'");
  17423. }
  17424. collectObjects(this, results, 0, []);
  17425. },
  17426. /**
  17427. Hook point for updating the URL.
  17428. @param {String} url a URL to update to
  17429. */
  17430. updateURL: function() {
  17431. throw "updateURL is not implemented";
  17432. },
  17433. /**
  17434. Hook point for replacing the current URL, i.e. with replaceState
  17435. By default this behaves the same as `updateURL`
  17436. @param {String} url a URL to update to
  17437. */
  17438. replaceURL: function(url) {
  17439. this.updateURL(url);
  17440. },
  17441. /**
  17442. Transition into the specified named route.
  17443. If necessary, trigger the exit callback on any handlers
  17444. that are no longer represented by the target route.
  17445. @param {String} name the name of the route
  17446. */
  17447. transitionTo: function(name) {
  17448. var args = Array.prototype.slice.call(arguments, 1);
  17449. doTransition(this, name, this.updateURL, args);
  17450. },
  17451. /**
  17452. Identical to `transitionTo` except that the current URL will be replaced
  17453. if possible.
  17454. This method is intended primarily for use with `replaceState`.
  17455. @param {String} name the name of the route
  17456. */
  17457. replaceWith: function(name) {
  17458. var args = Array.prototype.slice.call(arguments, 1);
  17459. doTransition(this, name, this.replaceURL, args);
  17460. },
  17461. /**
  17462. @private
  17463. This method takes a handler name and a list of contexts and returns
  17464. a serialized parameter hash suitable to pass to `recognizer.generate()`.
  17465. @param {String} handlerName
  17466. @param {Array[Object]} contexts
  17467. @return {Object} a serialized parameter hash
  17468. */
  17469. paramsForHandler: function(handlerName, callback) {
  17470. var output = this._paramsForHandler(handlerName, [].slice.call(arguments, 1));
  17471. return output.params;
  17472. },
  17473. /**
  17474. Take a named route and context objects and generate a
  17475. URL.
  17476. @param {String} name the name of the route to generate
  17477. a URL for
  17478. @param {...Object} objects a list of objects to serialize
  17479. @return {String} a URL
  17480. */
  17481. generate: function(handlerName) {
  17482. var params = this.paramsForHandler.apply(this, arguments);
  17483. return this.recognizer.generate(handlerName, params);
  17484. },
  17485. /**
  17486. @private
  17487. Used internally by `generate` and `transitionTo`.
  17488. */
  17489. _paramsForHandler: function(handlerName, objects, doUpdate) {
  17490. var handlers = this.recognizer.handlersFor(handlerName),
  17491. params = {},
  17492. toSetup = [],
  17493. startIdx = handlers.length,
  17494. objectsToMatch = objects.length,
  17495. object, objectChanged, handlerObj, handler, names, i, len;
  17496. // Find out which handler to start matching at
  17497. for (i=handlers.length-1; i>=0 && objectsToMatch>0; i--) {
  17498. if (handlers[i].names.length) {
  17499. objectsToMatch--;
  17500. startIdx = i;
  17501. }
  17502. }
  17503. if (objectsToMatch > 0) {
  17504. throw "More objects were passed than dynamic segments";
  17505. }
  17506. // Connect the objects to the routes
  17507. for (i=0, len=handlers.length; i<len; i++) {
  17508. handlerObj = handlers[i];
  17509. handler = this.getHandler(handlerObj.handler);
  17510. names = handlerObj.names;
  17511. objectChanged = false;
  17512. // If it's a dynamic segment
  17513. if (names.length) {
  17514. // If we have objects, use them
  17515. if (i >= startIdx) {
  17516. object = objects.shift();
  17517. objectChanged = true;
  17518. // Otherwise use existing context
  17519. } else {
  17520. object = handler.context;
  17521. }
  17522. // Serialize to generate params
  17523. if (handler.serialize) {
  17524. merge(params, handler.serialize(object, names));
  17525. }
  17526. // If it's not a dynamic segment and we're updating
  17527. } else if (doUpdate) {
  17528. // If we've passed the match point we need to deserialize again
  17529. // or if we never had a context
  17530. if (i > startIdx || !handler.hasOwnProperty('context')) {
  17531. if (handler.deserialize) {
  17532. object = handler.deserialize({});
  17533. objectChanged = true;
  17534. }
  17535. // Otherwise use existing context
  17536. } else {
  17537. object = handler.context;
  17538. }
  17539. }
  17540. // Make sure that we update the context here so it's available to
  17541. // subsequent deserialize calls
  17542. if (doUpdate && objectChanged) {
  17543. // TODO: It's a bit awkward to set the context twice, see if we can DRY things up
  17544. setContext(handler, object);
  17545. }
  17546. toSetup.push({
  17547. isDynamic: !!handlerObj.names.length,
  17548. handler: handlerObj.handler,
  17549. name: handlerObj.name,
  17550. context: object
  17551. });
  17552. }
  17553. return { params: params, toSetup: toSetup };
  17554. },
  17555. isActive: function(handlerName) {
  17556. var contexts = [].slice.call(arguments, 1);
  17557. var currentHandlerInfos = this.currentHandlerInfos,
  17558. found = false, names, object, handlerInfo, handlerObj;
  17559. for (var i=currentHandlerInfos.length-1; i>=0; i--) {
  17560. handlerInfo = currentHandlerInfos[i];
  17561. if (handlerInfo.name === handlerName) { found = true; }
  17562. if (found) {
  17563. if (contexts.length === 0) { break; }
  17564. if (handlerInfo.isDynamic) {
  17565. object = contexts.pop();
  17566. if (handlerInfo.context !== object) { return false; }
  17567. }
  17568. }
  17569. }
  17570. return contexts.length === 0 && found;
  17571. },
  17572. trigger: function(name) {
  17573. var args = [].slice.call(arguments);
  17574. trigger(this, args);
  17575. }
  17576. };
  17577. function merge(hash, other) {
  17578. for (var prop in other) {
  17579. if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; }
  17580. }
  17581. }
  17582. function isCurrent(currentHandlerInfos, handlerName) {
  17583. return currentHandlerInfos[currentHandlerInfos.length - 1].name === handlerName;
  17584. }
  17585. /**
  17586. @private
  17587. This function is called the first time the `collectObjects`
  17588. function encounters a promise while converting URL parameters
  17589. into objects.
  17590. It triggers the `enter` and `setup` methods on the `loading`
  17591. handler.
  17592. @param {Router} router
  17593. */
  17594. function loading(router) {
  17595. if (!router.isLoading) {
  17596. router.isLoading = true;
  17597. var handler = router.getHandler('loading');
  17598. if (handler) {
  17599. if (handler.enter) { handler.enter(); }
  17600. if (handler.setup) { handler.setup(); }
  17601. }
  17602. }
  17603. }
  17604. /**
  17605. @private
  17606. This function is called if a promise was previously
  17607. encountered once all promises are resolved.
  17608. It triggers the `exit` method on the `loading` handler.
  17609. @param {Router} router
  17610. */
  17611. function loaded(router) {
  17612. router.isLoading = false;
  17613. var handler = router.getHandler('loading');
  17614. if (handler && handler.exit) { handler.exit(); }
  17615. }
  17616. /**
  17617. @private
  17618. This function is called if any encountered promise
  17619. is rejected.
  17620. It triggers the `exit` method on the `loading` handler,
  17621. the `enter` method on the `failure` handler, and the
  17622. `setup` method on the `failure` handler with the
  17623. `error`.
  17624. @param {Router} router
  17625. @param {Object} error the reason for the promise
  17626. rejection, to pass into the failure handler's
  17627. `setup` method.
  17628. */
  17629. function failure(router, error) {
  17630. loaded(router);
  17631. var handler = router.getHandler('failure');
  17632. if (handler && handler.setup) { handler.setup(error); }
  17633. }
  17634. /**
  17635. @private
  17636. */
  17637. function doTransition(router, name, method, args) {
  17638. var output = router._paramsForHandler(name, args, true);
  17639. var params = output.params, toSetup = output.toSetup;
  17640. var url = router.recognizer.generate(name, params);
  17641. method.call(router, url);
  17642. setupContexts(router, toSetup);
  17643. }
  17644. /**
  17645. @private
  17646. This function is called after a URL change has been handled
  17647. by `router.handleURL`.
  17648. Takes an Array of `RecognizedHandler`s, and converts the raw
  17649. params hashes into deserialized objects by calling deserialize
  17650. on the handlers. This process builds up an Array of
  17651. `HandlerInfo`s. It then calls `setupContexts` with the Array.
  17652. If the `deserialize` method on a handler returns a promise
  17653. (i.e. has a method called `then`), this function will pause
  17654. building up the `HandlerInfo` Array until the promise is
  17655. resolved. It will use the resolved value as the context of
  17656. `HandlerInfo`.
  17657. */
  17658. function collectObjects(router, results, index, objects) {
  17659. if (results.length === index) {
  17660. loaded(router);
  17661. setupContexts(router, objects);
  17662. return;
  17663. }
  17664. var result = results[index];
  17665. var handler = router.getHandler(result.handler);
  17666. var object = handler.deserialize && handler.deserialize(result.params);
  17667. if (object && typeof object.then === 'function') {
  17668. loading(router);
  17669. // The chained `then` means that we can also catch errors that happen in `proceed`
  17670. object.then(proceed).then(null, function(error) {
  17671. failure(router, error);
  17672. });
  17673. } else {
  17674. proceed(object);
  17675. }
  17676. function proceed(value) {
  17677. if (handler.context !== object) {
  17678. setContext(handler, object);
  17679. }
  17680. var updatedObjects = objects.concat([{
  17681. context: value,
  17682. handler: result.handler,
  17683. isDynamic: result.isDynamic
  17684. }]);
  17685. collectObjects(router, results, index + 1, updatedObjects);
  17686. }
  17687. }
  17688. /**
  17689. @private
  17690. Takes an Array of `UnresolvedHandlerInfo`s, resolves the handler names
  17691. into handlers, and then figures out what to do with each of the handlers.
  17692. For example, consider the following tree of handlers. Each handler is
  17693. followed by the URL segment it handles.
  17694. ```
  17695. |~index ("/")
  17696. | |~posts ("/posts")
  17697. | | |-showPost ("/:id")
  17698. | | |-newPost ("/new")
  17699. | | |-editPost ("/edit")
  17700. | |~about ("/about/:id")
  17701. ```
  17702. Consider the following transitions:
  17703. 1. A URL transition to `/posts/1`.
  17704. 1. Triggers the `deserialize` callback on the
  17705. `index`, `posts`, and `showPost` handlers
  17706. 2. Triggers the `enter` callback on the same
  17707. 3. Triggers the `setup` callback on the same
  17708. 2. A direct transition to `newPost`
  17709. 1. Triggers the `exit` callback on `showPost`
  17710. 2. Triggers the `enter` callback on `newPost`
  17711. 3. Triggers the `setup` callback on `newPost`
  17712. 3. A direct transition to `about` with a specified
  17713. context object
  17714. 1. Triggers the `exit` callback on `newPost`
  17715. and `posts`
  17716. 2. Triggers the `serialize` callback on `about`
  17717. 3. Triggers the `enter` callback on `about`
  17718. 4. Triggers the `setup` callback on `about`
  17719. @param {Router} router
  17720. @param {Array[UnresolvedHandlerInfo]} handlerInfos
  17721. */
  17722. function setupContexts(router, handlerInfos) {
  17723. resolveHandlers(router, handlerInfos);
  17724. var partition =
  17725. partitionHandlers(router.currentHandlerInfos || [], handlerInfos);
  17726. router.currentHandlerInfos = handlerInfos;
  17727. eachHandler(partition.exited, function(handler, context) {
  17728. delete handler.context;
  17729. if (handler.exit) { handler.exit(); }
  17730. });
  17731. eachHandler(partition.updatedContext, function(handler, context) {
  17732. setContext(handler, context);
  17733. if (handler.setup) { handler.setup(context); }
  17734. });
  17735. var aborted = false;
  17736. eachHandler(partition.entered, function(handler, context) {
  17737. if (aborted) { return; }
  17738. if (handler.enter) { handler.enter(); }
  17739. setContext(handler, context);
  17740. if (handler.setup) {
  17741. if (false === handler.setup(context)) {
  17742. aborted = true;
  17743. }
  17744. }
  17745. });
  17746. if (router.didTransition) {
  17747. router.didTransition(handlerInfos);
  17748. }
  17749. }
  17750. /**
  17751. @private
  17752. Iterates over an array of `HandlerInfo`s, passing the handler
  17753. and context into the callback.
  17754. @param {Array[HandlerInfo]} handlerInfos
  17755. @param {Function(Object, Object)} callback
  17756. */
  17757. function eachHandler(handlerInfos, callback) {
  17758. for (var i=0, l=handlerInfos.length; i<l; i++) {
  17759. var handlerInfo = handlerInfos[i],
  17760. handler = handlerInfo.handler,
  17761. context = handlerInfo.context;
  17762. callback(handler, context);
  17763. }
  17764. }
  17765. /**
  17766. @private
  17767. Updates the `handler` field in each element in an Array of
  17768. `UnresolvedHandlerInfo`s from a handler name to a resolved handler.
  17769. When done, the Array will contain `HandlerInfo` structures.
  17770. @param {Router} router
  17771. @param {Array[UnresolvedHandlerInfo]} handlerInfos
  17772. */
  17773. function resolveHandlers(router, handlerInfos) {
  17774. var handlerInfo;
  17775. for (var i=0, l=handlerInfos.length; i<l; i++) {
  17776. handlerInfo = handlerInfos[i];
  17777. handlerInfo.name = handlerInfo.handler;
  17778. handlerInfo.handler = router.getHandler(handlerInfo.handler);
  17779. }
  17780. }
  17781. /**
  17782. @private
  17783. This function is called when transitioning from one URL to
  17784. another to determine which handlers are not longer active,
  17785. which handlers are newly active, and which handlers remain
  17786. active but have their context changed.
  17787. Take a list of old handlers and new handlers and partition
  17788. them into four buckets:
  17789. * unchanged: the handler was active in both the old and
  17790. new URL, and its context remains the same
  17791. * updated context: the handler was active in both the
  17792. old and new URL, but its context changed. The handler's
  17793. `setup` method, if any, will be called with the new
  17794. context.
  17795. * exited: the handler was active in the old URL, but is
  17796. no longer active.
  17797. * entered: the handler was not active in the old URL, but
  17798. is now active.
  17799. The PartitionedHandlers structure has three fields:
  17800. * `updatedContext`: a list of `HandlerInfo` objects that
  17801. represent handlers that remain active but have a changed
  17802. context
  17803. * `entered`: a list of `HandlerInfo` objects that represent
  17804. handlers that are newly active
  17805. * `exited`: a list of `HandlerInfo` objects that are no
  17806. longer active.
  17807. @param {Array[HandlerInfo]} oldHandlers a list of the handler
  17808. information for the previous URL (or `[]` if this is the
  17809. first handled transition)
  17810. @param {Array[HandlerInfo]} newHandlers a list of the handler
  17811. information for the new URL
  17812. @return {Partition}
  17813. */
  17814. function partitionHandlers(oldHandlers, newHandlers) {
  17815. var handlers = {
  17816. updatedContext: [],
  17817. exited: [],
  17818. entered: []
  17819. };
  17820. var handlerChanged, contextChanged, i, l;
  17821. for (i=0, l=newHandlers.length; i<l; i++) {
  17822. var oldHandler = oldHandlers[i], newHandler = newHandlers[i];
  17823. if (!oldHandler || oldHandler.handler !== newHandler.handler) {
  17824. handlerChanged = true;
  17825. }
  17826. if (handlerChanged) {
  17827. handlers.entered.push(newHandler);
  17828. if (oldHandler) { handlers.exited.unshift(oldHandler); }
  17829. } else if (contextChanged || oldHandler.context !== newHandler.context) {
  17830. contextChanged = true;
  17831. handlers.updatedContext.push(newHandler);
  17832. }
  17833. }
  17834. for (i=newHandlers.length, l=oldHandlers.length; i<l; i++) {
  17835. handlers.exited.unshift(oldHandlers[i]);
  17836. }
  17837. return handlers;
  17838. }
  17839. function trigger(router, args) {
  17840. var currentHandlerInfos = router.currentHandlerInfos;
  17841. var name = args.shift();
  17842. if (!currentHandlerInfos) {
  17843. throw new Error("Could not trigger event '" + name + "'. There are no active handlers");
  17844. }
  17845. for (var i=currentHandlerInfos.length-1; i>=0; i--) {
  17846. var handlerInfo = currentHandlerInfos[i],
  17847. handler = handlerInfo.handler;
  17848. if (handler.events && handler.events[name]) {
  17849. handler.events[name].apply(handler, args);
  17850. return;
  17851. }
  17852. }
  17853. throw new Error("Nothing handled the event '" + name + "'.");
  17854. }
  17855. function setContext(handler, context) {
  17856. handler.context = context;
  17857. if (handler.contextDidChange) { handler.contextDidChange(); }
  17858. }
  17859. return Router;
  17860. });
  17861. })();
  17862. (function() {
  17863. /**
  17864. @module ember
  17865. @submodule ember-routing
  17866. */
  17867. function DSL(name) {
  17868. this.parent = name;
  17869. this.matches = [];
  17870. }
  17871. DSL.prototype = {
  17872. resource: function(name, options, callback) {
  17873. if (arguments.length === 2 && typeof options === 'function') {
  17874. callback = options;
  17875. options = {};
  17876. }
  17877. if (arguments.length === 1) {
  17878. options = {};
  17879. }
  17880. if (typeof options.path !== 'string') {
  17881. options.path = "/" + name;
  17882. }
  17883. if (callback) {
  17884. var dsl = new DSL(name);
  17885. callback.call(dsl);
  17886. this.push(options.path, name, dsl.generate());
  17887. } else {
  17888. this.push(options.path, name);
  17889. }
  17890. },
  17891. push: function(url, name, callback) {
  17892. if (url === "" || url === "/") { this.explicitIndex = true; }
  17893. this.matches.push([url, name, callback]);
  17894. },
  17895. route: function(name, options) {
  17896. Ember.assert("You must use `this.resource` to nest", typeof options !== 'function');
  17897. options = options || {};
  17898. if (typeof options.path !== 'string') {
  17899. options.path = "/" + name;
  17900. }
  17901. if (this.parent && this.parent !== 'application') {
  17902. name = this.parent + "." + name;
  17903. }
  17904. this.push(options.path, name);
  17905. },
  17906. generate: function() {
  17907. var dslMatches = this.matches;
  17908. if (!this.explicitIndex) {
  17909. this.route("index", { path: "/" });
  17910. }
  17911. return function(match) {
  17912. for (var i=0, l=dslMatches.length; i<l; i++) {
  17913. var dslMatch = dslMatches[i];
  17914. match(dslMatch[0]).to(dslMatch[1], dslMatch[2]);
  17915. }
  17916. };
  17917. }
  17918. };
  17919. DSL.map = function(callback) {
  17920. var dsl = new DSL();
  17921. callback.call(dsl);
  17922. return dsl;
  17923. };
  17924. Ember.RouterDSL = DSL;
  17925. })();
  17926. (function() {
  17927. /**
  17928. @module ember
  17929. @submodule ember-routing
  17930. */
  17931. Ember.controllerFor = function(container, controllerName, context) {
  17932. return container.lookup('controller:' + controllerName) ||
  17933. Ember.generateController(container, controllerName, context);
  17934. };
  17935. Ember.generateController = function(container, controllerName, context) {
  17936. var controller;
  17937. if (context && Ember.isArray(context)) {
  17938. controller = Ember.ArrayController.extend({
  17939. content: context
  17940. });
  17941. } else if (context) {
  17942. controller = Ember.ObjectController.extend({
  17943. content: context
  17944. });
  17945. } else {
  17946. controller = Ember.Controller.extend();
  17947. }
  17948. controller.toString = function() {
  17949. return "(generated " + controllerName + " controller)";
  17950. };
  17951. container.register('controller', controllerName, controller);
  17952. return container.lookup('controller:' + controllerName);
  17953. };
  17954. })();
  17955. (function() {
  17956. /**
  17957. @module ember
  17958. @submodule ember-routing
  17959. */
  17960. var Router = requireModule("router");
  17961. var get = Ember.get, set = Ember.set, classify = Ember.String.classify;
  17962. var DefaultView = Ember._MetamorphView;
  17963. function setupLocation(router) {
  17964. var location = get(router, 'location'),
  17965. rootURL = get(router, 'rootURL');
  17966. if ('string' === typeof location) {
  17967. location = set(router, 'location', Ember.Location.create({
  17968. implementation: location
  17969. }));
  17970. if (typeof rootURL === 'string') {
  17971. set(location, 'rootURL', rootURL);
  17972. }
  17973. }
  17974. }
  17975. /**
  17976. The `Ember.Router` class manages the application state and URLs. Refer to
  17977. the [routing guide](http://emberjs.com/guides/routing/) for documentation.
  17978. @class Router
  17979. @namespace Ember
  17980. @extends Ember.Object
  17981. */
  17982. Ember.Router = Ember.Object.extend({
  17983. location: 'hash',
  17984. init: function() {
  17985. this.router = this.constructor.router;
  17986. this._activeViews = {};
  17987. setupLocation(this);
  17988. },
  17989. url: Ember.computed(function() {
  17990. return get(this, 'location').getURL();
  17991. }),
  17992. startRouting: function() {
  17993. this.router = this.router || this.constructor.map(Ember.K);
  17994. var router = this.router,
  17995. location = get(this, 'location'),
  17996. container = this.container,
  17997. self = this;
  17998. setupRouter(this, router, location);
  17999. container.register('view', 'default', DefaultView);
  18000. container.register('view', 'toplevel', Ember.View.extend());
  18001. location.onUpdateURL(function(url) {
  18002. self.handleURL(url);
  18003. });
  18004. this.handleURL(location.getURL());
  18005. },
  18006. didTransition: function(infos) {
  18007. // Don't do any further action here if we redirected
  18008. for (var i=0, l=infos.length; i<l; i++) {
  18009. if (infos[i].handler.redirected) { return; }
  18010. }
  18011. var appController = this.container.lookup('controller:application'),
  18012. path = routePath(infos);
  18013. set(appController, 'currentPath', path);
  18014. this.notifyPropertyChange('url');
  18015. if (get(this, 'namespace').LOG_TRANSITIONS) {
  18016. Ember.Logger.log("Transitioned into '" + path + "'");
  18017. }
  18018. },
  18019. handleURL: function(url) {
  18020. this.router.handleURL(url);
  18021. this.notifyPropertyChange('url');
  18022. },
  18023. transitionTo: function(name) {
  18024. var args = [].slice.call(arguments);
  18025. doTransition(this, 'transitionTo', args);
  18026. },
  18027. replaceWith: function() {
  18028. var args = [].slice.call(arguments);
  18029. doTransition(this, 'replaceWith', args);
  18030. },
  18031. generate: function() {
  18032. var url = this.router.generate.apply(this.router, arguments);
  18033. return this.location.formatURL(url);
  18034. },
  18035. isActive: function(routeName) {
  18036. var router = this.router;
  18037. return router.isActive.apply(router, arguments);
  18038. },
  18039. send: function(name, context) {
  18040. this.router.trigger.apply(this.router, arguments);
  18041. },
  18042. hasRoute: function(route) {
  18043. return this.router.hasRoute(route);
  18044. },
  18045. _lookupActiveView: function(templateName) {
  18046. var active = this._activeViews[templateName];
  18047. return active && active[0];
  18048. },
  18049. _connectActiveView: function(templateName, view) {
  18050. var existing = this._activeViews[templateName];
  18051. if (existing) {
  18052. existing[0].off('willDestroyElement', this, existing[1]);
  18053. }
  18054. var disconnect = function() {
  18055. delete this._activeViews[templateName];
  18056. };
  18057. this._activeViews[templateName] = [view, disconnect];
  18058. view.one('willDestroyElement', this, disconnect);
  18059. }
  18060. });
  18061. Ember.Router.reopenClass({
  18062. defaultFailureHandler: {
  18063. setup: function(error) {
  18064. Ember.Logger.error('Error while loading route:', error);
  18065. // Using setTimeout allows us to escape from the Promise's try/catch block
  18066. setTimeout(function() { throw error; });
  18067. }
  18068. }
  18069. });
  18070. function getHandlerFunction(router) {
  18071. var seen = {}, container = router.container;
  18072. return function(name) {
  18073. var handler = container.lookup('route:' + name);
  18074. if (seen[name]) { return handler; }
  18075. seen[name] = true;
  18076. if (!handler) {
  18077. if (name === 'loading') { return {}; }
  18078. if (name === 'failure') { return router.constructor.defaultFailureHandler; }
  18079. container.register('route', name, Ember.Route.extend());
  18080. handler = container.lookup('route:' + name);
  18081. }
  18082. handler.routeName = name;
  18083. return handler;
  18084. };
  18085. }
  18086. function handlerIsActive(router, handlerName) {
  18087. var handler = router.container.lookup('route:' + handlerName),
  18088. currentHandlerInfos = router.router.currentHandlerInfos,
  18089. handlerInfo;
  18090. for (var i=0, l=currentHandlerInfos.length; i<l; i++) {
  18091. handlerInfo = currentHandlerInfos[i];
  18092. if (handlerInfo.handler === handler) { return true; }
  18093. }
  18094. return false;
  18095. }
  18096. function routePath(handlerInfos) {
  18097. var path = [];
  18098. for (var i=1, l=handlerInfos.length; i<l; i++) {
  18099. var name = handlerInfos[i].name,
  18100. nameParts = name.split(".");
  18101. path.push(nameParts[nameParts.length - 1]);
  18102. }
  18103. return path.join(".");
  18104. }
  18105. function setupRouter(emberRouter, router, location) {
  18106. var lastURL;
  18107. router.getHandler = getHandlerFunction(emberRouter);
  18108. var doUpdateURL = function() {
  18109. location.setURL(lastURL);
  18110. };
  18111. router.updateURL = function(path) {
  18112. lastURL = path;
  18113. Ember.run.once(doUpdateURL);
  18114. };
  18115. if (location.replaceURL) {
  18116. var doReplaceURL = function() {
  18117. location.replaceURL(lastURL);
  18118. };
  18119. router.replaceURL = function(path) {
  18120. lastURL = path;
  18121. Ember.run.once(doReplaceURL);
  18122. };
  18123. }
  18124. router.didTransition = function(infos) {
  18125. emberRouter.didTransition(infos);
  18126. };
  18127. }
  18128. function doTransition(router, method, args) {
  18129. var passedName = args[0], name;
  18130. if (!router.router.hasRoute(args[0])) {
  18131. name = args[0] = passedName + '.index';
  18132. } else {
  18133. name = passedName;
  18134. }
  18135. Ember.assert("The route " + passedName + " was not found", router.router.hasRoute(name));
  18136. router.router[method].apply(router.router, args);
  18137. router.notifyPropertyChange('url');
  18138. }
  18139. Ember.Router.reopenClass({
  18140. map: function(callback) {
  18141. var router = this.router = new Router();
  18142. var dsl = Ember.RouterDSL.map(function() {
  18143. this.resource('application', { path: "/" }, function() {
  18144. callback.call(this);
  18145. });
  18146. });
  18147. router.map(dsl.generate());
  18148. return router;
  18149. }
  18150. });
  18151. })();
  18152. (function() {
  18153. /**
  18154. @module ember
  18155. @submodule ember-routing
  18156. */
  18157. var get = Ember.get, set = Ember.set,
  18158. classify = Ember.String.classify,
  18159. decamelize = Ember.String.decamelize;
  18160. /**
  18161. The `Ember.Route` class is used to define individual routes. Refer to
  18162. the [routing guide](http://emberjs.com/guides/routing/) for documentation.
  18163. @class Route
  18164. @namespace Ember
  18165. @extends Ember.Object
  18166. */
  18167. Ember.Route = Ember.Object.extend({
  18168. /**
  18169. @private
  18170. @method exit
  18171. */
  18172. exit: function() {
  18173. this.deactivate();
  18174. teardownView(this);
  18175. },
  18176. /**
  18177. @private
  18178. @method enter
  18179. */
  18180. enter: function() {
  18181. this.activate();
  18182. },
  18183. /**
  18184. The collection of functions keyed by name available on this route as
  18185. action targets.
  18186. These functions will be invoked when a matching `{{action}}` is triggered
  18187. from within a template and the application's current route is this route.
  18188. Events can also be invoked from other parts of your application via `Route#send`.
  18189. The context of event will be the this route.
  18190. @see {Ember.Route#send}
  18191. @see {Handlebars.helpers.action}
  18192. @property events
  18193. @type Hash
  18194. @default null
  18195. */
  18196. events: null,
  18197. /**
  18198. This hook is executed when the router completely exits this route. It is
  18199. not executed when the model for the route changes.
  18200. @method deactivate
  18201. */
  18202. deactivate: Ember.K,
  18203. /**
  18204. This hook is executed when the router enters the route for the first time.
  18205. It is not executed when the model for the route changes.
  18206. @method activate
  18207. */
  18208. activate: Ember.K,
  18209. /**
  18210. Transition into another route. Optionally supply a model for the
  18211. route in question. The model will be serialized into the URL
  18212. using the `serialize` hook.
  18213. @method transitionTo
  18214. @param {String} name the name of the route
  18215. @param {...Object} models the
  18216. */
  18217. transitionTo: function() {
  18218. if (this._checkingRedirect) { this.redirected = true; }
  18219. return this.router.transitionTo.apply(this.router, arguments);
  18220. },
  18221. /**
  18222. Transition into another route while replacing the current URL if
  18223. possible. Identical to `transitionTo` in all other respects.
  18224. @method replaceWith
  18225. @param {String} name the name of the route
  18226. @param {...Object} models the
  18227. */
  18228. replaceWith: function() {
  18229. if (this._checkingRedirect) { this.redirected = true; }
  18230. return this.router.replaceWith.apply(this.router, arguments);
  18231. },
  18232. send: function() {
  18233. return this.router.send.apply(this.router, arguments);
  18234. },
  18235. /**
  18236. @private
  18237. This hook is the entry point for router.js
  18238. @method setup
  18239. */
  18240. setup: function(context) {
  18241. this.redirected = false;
  18242. this._checkingRedirect = true;
  18243. this.redirect(context);
  18244. this._checkingRedirect = false;
  18245. if (this.redirected) { return false; }
  18246. var controller = this.controllerFor(this.routeName, context);
  18247. if (controller) {
  18248. this.controller = controller;
  18249. set(controller, 'model', context);
  18250. }
  18251. if (this.setupControllers) {
  18252. Ember.deprecate("Ember.Route.setupControllers is deprecated. Please use Ember.Route.setupController(controller, model) instead.");
  18253. this.setupControllers(controller, context);
  18254. } else {
  18255. this.setupController(controller, context);
  18256. }
  18257. if (this.renderTemplates) {
  18258. Ember.deprecate("Ember.Route.renderTemplates is deprecated. Please use Ember.Route.renderTemplate(controller, model) instead.");
  18259. this.renderTemplates(context);
  18260. } else {
  18261. this.renderTemplate(controller, context);
  18262. }
  18263. },
  18264. /**
  18265. A hook you can implement to optionally redirect to another route.
  18266. If you call `this.transitionTo` from inside of this hook, this route
  18267. will not be entered in favor of the other hook.
  18268. @method redirect
  18269. @param {Object} model the model for this route
  18270. */
  18271. redirect: Ember.K,
  18272. /**
  18273. @private
  18274. The hook called by `router.js` to convert parameters into the context
  18275. for this handler. The public Ember hook is `model`.
  18276. @method deserialize
  18277. */
  18278. deserialize: function(params) {
  18279. var model = this.model(params);
  18280. return this.currentModel = model;
  18281. },
  18282. /**
  18283. @private
  18284. Called when the context is changed by router.js.
  18285. */
  18286. contextDidChange: function() {
  18287. this.currentModel = this.context;
  18288. },
  18289. /**
  18290. A hook you can implement to convert the URL into the model for
  18291. this route.
  18292. ```js
  18293. App.Route.map(function(match) {
  18294. match("/posts/:post_id").to("post");
  18295. });
  18296. ```
  18297. The model for the `post` route is `App.Post.find(params.post_id)`.
  18298. By default, if your route has a dynamic segment ending in `_id`:
  18299. * The model class is determined from the segment (`post_id`'s
  18300. class is `App.Post`)
  18301. * The find method is called on the model class with the value of
  18302. the dynamic segment.
  18303. @method model
  18304. @param {Object} params the parameters extracted from the URL
  18305. */
  18306. model: function(params) {
  18307. var match, name, sawParams, value;
  18308. for (var prop in params) {
  18309. if (match = prop.match(/^(.*)_id$/)) {
  18310. name = match[1];
  18311. value = params[prop];
  18312. }
  18313. sawParams = true;
  18314. }
  18315. if (!name && sawParams) { return params; }
  18316. else if (!name) { return; }
  18317. var className = classify(name),
  18318. namespace = this.router.namespace,
  18319. modelClass = namespace[className];
  18320. Ember.assert("You used the dynamic segment " + name + "_id in your router, but " + namespace + "." + className + " did not exist and you did not override your state's `model` hook.", modelClass);
  18321. return modelClass.find(value);
  18322. },
  18323. /**
  18324. A hook you can implement to convert the route's model into parameters
  18325. for the URL.
  18326. ```js
  18327. App.Route.map(function(match) {
  18328. match("/posts/:post_id").to("post");
  18329. });
  18330. App.PostRoute = Ember.Route.extend({
  18331. model: function(params) {
  18332. // the server returns `{ id: 12 }`
  18333. return jQuery.getJSON("/posts/" + params.post_id);
  18334. },
  18335. serialize: function(model) {
  18336. // this will make the URL `/posts/12`
  18337. return { post_id: model.id };
  18338. }
  18339. });
  18340. ```
  18341. The default `serialize` method inserts the model's `id` into the
  18342. route's dynamic segment (in this case, `:post_id`).
  18343. This method is called when `transitionTo` is called with a context
  18344. in order to populate the URL.
  18345. @method serialize
  18346. @param {Object} model the route's model
  18347. @param {Array} params an Array of parameter names for the current
  18348. route (in the example, `['post_id']`.
  18349. @return {Object} the serialized parameters
  18350. */
  18351. serialize: function(model, params) {
  18352. if (params.length !== 1) { return; }
  18353. var name = params[0], object = {};
  18354. if (/_id$/.test(name)) {
  18355. object[name] = get(model, 'id');
  18356. } else {
  18357. object[name] = model;
  18358. }
  18359. return object;
  18360. },
  18361. /**
  18362. A hook you can use to setup the controller for the current route.
  18363. This method is called with the controller for the current route and the
  18364. model supplied by the `model` hook.
  18365. ```js
  18366. App.Route.map(function(match) {
  18367. match("/posts/:post_id").to("post");
  18368. });
  18369. ```
  18370. For the `post` route, the controller is `App.PostController`.
  18371. By default, the `setupController` hook sets the `content` property of
  18372. the controller to the `model`.
  18373. If no explicit controller is defined, the route will automatically create
  18374. an appropriate controller for the model:
  18375. * if the model is an `Ember.Array` (including record arrays from Ember
  18376. Data), the controller is an `Ember.ArrayController`.
  18377. * otherwise, the controller is an `Ember.ObjectController`.
  18378. This means that your template will get a proxy for the model as its
  18379. context, and you can act as though the model itself was the context.
  18380. @method setupController
  18381. */
  18382. setupController: Ember.K,
  18383. /**
  18384. Returns the controller for a particular route.
  18385. ```js
  18386. App.PostRoute = Ember.Route.extend({
  18387. setupController: function(controller, post) {
  18388. this._super(controller, post);
  18389. this.controllerFor('posts').set('currentPost', post);
  18390. }
  18391. });
  18392. ```
  18393. By default, the controller for `post` is the shared instance of
  18394. `App.PostController`.
  18395. @method controllerFor
  18396. @param {String} name the name of the route
  18397. @param {Object} model the model associated with the route (optional)
  18398. @return {Ember.Controller}
  18399. */
  18400. controllerFor: function(name, model) {
  18401. var container = this.router.container,
  18402. controller = container.lookup('controller:' + name);
  18403. if (!controller) {
  18404. model = model || this.modelFor(name);
  18405. Ember.assert("You are trying to look up a controller that you did not define, and for which Ember does not know the model.\n\nThis is not a controller for a route, so you must explicitly define the controller ("+this.router.namespace.toString() + "." + Ember.String.capitalize(Ember.String.camelize(name))+"Controller) or pass a model as the second parameter to `controllerFor`, so that Ember knows which type of controller to create for you.", model || this.container.lookup('route:' + name));
  18406. controller = Ember.generateController(container, name, model);
  18407. }
  18408. return controller;
  18409. },
  18410. /**
  18411. Returns the current model for a given route.
  18412. This is the object returned by the `model` hook of the route
  18413. in question.
  18414. @method modelFor
  18415. @param {String} name the name of the route
  18416. @return {Object} the model object
  18417. */
  18418. modelFor: function(name) {
  18419. var route = this.container.lookup('route:' + name);
  18420. return route && route.currentModel;
  18421. },
  18422. /**
  18423. A hook you can use to render the template for the current route.
  18424. This method is called with the controller for the current route and the
  18425. model supplied by the `model` hook. By default, it renders the route's
  18426. template, configured with the controller for the route.
  18427. This method can be overridden to set up and render additional or
  18428. alternative templates.
  18429. @method renderTemplate
  18430. @param {Object} controller the route's controller
  18431. @param {Object} model the route's model
  18432. */
  18433. renderTemplate: function(controller, model) {
  18434. this.render();
  18435. },
  18436. /**
  18437. Renders a template into an outlet.
  18438. This method has a number of defaults, based on the name of the
  18439. route specified in the router.
  18440. For example:
  18441. ```js
  18442. App.Router.map(function(match) {
  18443. match("/").to("index");
  18444. match("/posts/:post_id").to("post");
  18445. });
  18446. App.PostRoute = App.Route.extend({
  18447. renderTemplate: function() {
  18448. this.render();
  18449. }
  18450. });
  18451. ```
  18452. The name of the `PostRoute`, as defined by the router, is `post`.
  18453. By default, render will:
  18454. * render the `post` template
  18455. * with the `post` view (`PostView`) for event handling, if one exists
  18456. * and the `post` controller (`PostController`), if one exists
  18457. * into the `main` outlet of the `application` template
  18458. You can override this behavior:
  18459. ```js
  18460. App.PostRoute = App.Route.extend({
  18461. renderTemplate: function() {
  18462. this.render('myPost', { // the template to render
  18463. into: 'index', // the template to render into
  18464. outlet: 'detail', // the name of the outlet in that template
  18465. controller: 'blogPost' // the controller to use for the template
  18466. });
  18467. }
  18468. });
  18469. ```
  18470. Remember that the controller's `content` will be the route's model. In
  18471. this case, the default model will be `App.Post.find(params.post_id)`.
  18472. @method render
  18473. @param {String} name the name of the template to render
  18474. @param {Object} options the options
  18475. */
  18476. render: function(name, options) {
  18477. if (typeof name === 'object' && !options) {
  18478. options = name;
  18479. name = this.routeName;
  18480. }
  18481. name = name ? name.replace(/\//g, '.') : this.routeName;
  18482. var container = this.container,
  18483. view = container.lookup('view:' + name),
  18484. template = container.lookup('template:' + name);
  18485. if (!view && !template) { return; }
  18486. options = normalizeOptions(this, name, template, options);
  18487. view = setupView(view, container, options);
  18488. if (options.outlet === 'main') { this.lastRenderedTemplate = name; }
  18489. appendView(this, view, options);
  18490. },
  18491. willDestroy: function() {
  18492. teardownView(this);
  18493. }
  18494. });
  18495. function parentRoute(route) {
  18496. var handlerInfos = route.router.router.currentHandlerInfos;
  18497. var parent, current;
  18498. for (var i=0, l=handlerInfos.length; i<l; i++) {
  18499. current = handlerInfos[i].handler;
  18500. if (current === route) { return parent; }
  18501. parent = current;
  18502. }
  18503. }
  18504. function parentTemplate(route, isRecursive) {
  18505. var parent = parentRoute(route), template;
  18506. if (!parent) { return; }
  18507. Ember.warn("The immediate parent route did not render into the main outlet and the default 'into' option may not be expected", !isRecursive);
  18508. if (template = parent.lastRenderedTemplate) {
  18509. return template;
  18510. } else {
  18511. return parentTemplate(parent, true);
  18512. }
  18513. }
  18514. function normalizeOptions(route, name, template, options) {
  18515. options = options || {};
  18516. options.into = options.into ? options.into.replace(/\//g, '.') : parentTemplate(route);
  18517. options.outlet = options.outlet || 'main';
  18518. options.name = name;
  18519. options.template = template;
  18520. Ember.assert("An outlet ("+options.outlet+") was specified but this view will render at the root level.", options.outlet === 'main' || options.into);
  18521. var controller = options.controller, namedController;
  18522. if (options.controller) {
  18523. controller = options.controller;
  18524. } else if (namedController = route.container.lookup('controller:' + name)) {
  18525. controller = namedController;
  18526. } else {
  18527. controller = route.routeName;
  18528. }
  18529. if (typeof controller === 'string') {
  18530. controller = route.container.lookup('controller:' + controller);
  18531. }
  18532. options.controller = controller;
  18533. return options;
  18534. }
  18535. function setupView(view, container, options) {
  18536. var defaultView = options.into ? 'view:default' : 'view:toplevel';
  18537. view = view || container.lookup(defaultView);
  18538. if (!get(view, 'templateName')) {
  18539. set(view, 'template', options.template);
  18540. set(view, '_debugTemplateName', options.name);
  18541. }
  18542. set(view, 'renderedName', options.name);
  18543. set(view, 'controller', options.controller);
  18544. return view;
  18545. }
  18546. function appendView(route, view, options) {
  18547. if (options.into) {
  18548. var parentView = route.router._lookupActiveView(options.into);
  18549. route.teardownView = teardownOutlet(parentView, options.outlet);
  18550. parentView.connectOutlet(options.outlet, view);
  18551. } else {
  18552. var rootElement = get(route, 'router.namespace.rootElement');
  18553. route.router._connectActiveView(options.name, view);
  18554. route.teardownView = teardownTopLevel(view);
  18555. view.appendTo(rootElement);
  18556. }
  18557. }
  18558. function teardownTopLevel(view) {
  18559. return function() { view.destroy(); };
  18560. }
  18561. function teardownOutlet(parentView, outlet) {
  18562. return function() { parentView.disconnectOutlet(outlet); };
  18563. }
  18564. function teardownView(route) {
  18565. if (route.teardownView) { route.teardownView(); }
  18566. delete route.teardownView;
  18567. delete route.lastRenderedTemplate;
  18568. }
  18569. })();
  18570. (function() {
  18571. })();
  18572. (function() {
  18573. /**
  18574. @module ember
  18575. @submodule ember-routing
  18576. */
  18577. var get = Ember.get, set = Ember.set;
  18578. Ember.onLoad('Ember.Handlebars', function(Handlebars) {
  18579. var resolveParams = Ember.Handlebars.resolveParams,
  18580. isSimpleClick = Ember.ViewUtils.isSimpleClick;
  18581. function fullRouteName(router, name) {
  18582. if (!router.hasRoute(name)) {
  18583. name = name + '.index';
  18584. }
  18585. return name;
  18586. }
  18587. function resolvedPaths(options) {
  18588. var types = options.options.types.slice(1),
  18589. data = options.options.data;
  18590. return resolveParams(options.context, options.params, { types: types, data: data });
  18591. }
  18592. function args(linkView, router, route) {
  18593. var passedRouteName = route || linkView.namedRoute, routeName;
  18594. routeName = fullRouteName(router, passedRouteName);
  18595. Ember.assert("The route " + passedRouteName + " was not found", router.hasRoute(routeName));
  18596. var ret = [ routeName ];
  18597. return ret.concat(resolvedPaths(linkView.parameters));
  18598. }
  18599. var LinkView = Ember.View.extend({
  18600. tagName: 'a',
  18601. namedRoute: null,
  18602. currentWhen: null,
  18603. title: null,
  18604. activeClass: 'active',
  18605. replace: false,
  18606. attributeBindings: ['href', 'title'],
  18607. classNameBindings: 'active',
  18608. // Even though this isn't a virtual view, we want to treat it as if it is
  18609. // so that you can access the parent with {{view.prop}}
  18610. concreteView: Ember.computed(function() {
  18611. return get(this, 'parentView');
  18612. }).property('parentView').volatile(),
  18613. active: Ember.computed(function() {
  18614. var router = this.get('router'),
  18615. params = resolvedPaths(this.parameters),
  18616. currentWithIndex = this.currentWhen + '.index',
  18617. isActive = router.isActive.apply(router, [this.currentWhen].concat(params)) ||
  18618. router.isActive.apply(router, [currentWithIndex].concat(params));
  18619. if (isActive) { return get(this, 'activeClass'); }
  18620. }).property('namedRoute', 'router.url'),
  18621. router: Ember.computed(function() {
  18622. return this.get('controller').container.lookup('router:main');
  18623. }),
  18624. click: function(event) {
  18625. if (!isSimpleClick(event)) { return true; }
  18626. event.preventDefault();
  18627. if (this.bubbles === false) { event.stopPropagation(); }
  18628. var router = this.get('router');
  18629. if (this.get('replace')) {
  18630. router.replaceWith.apply(router, args(this, router));
  18631. } else {
  18632. router.transitionTo.apply(router, args(this, router));
  18633. }
  18634. },
  18635. href: Ember.computed(function() {
  18636. var router = this.get('router');
  18637. return router.generate.apply(router, args(this, router));
  18638. })
  18639. });
  18640. LinkView.toString = function() { return "LinkView"; };
  18641. /**
  18642. @method linkTo
  18643. @for Ember.Handlebars.helpers
  18644. @param {String} routeName
  18645. @param {Object} [context]*
  18646. @return {String} HTML string
  18647. */
  18648. Ember.Handlebars.registerHelper('linkTo', function(name) {
  18649. var options = [].slice.call(arguments, -1)[0];
  18650. var params = [].slice.call(arguments, 1, -1);
  18651. var hash = options.hash;
  18652. hash.namedRoute = name;
  18653. hash.currentWhen = hash.currentWhen || name;
  18654. hash.parameters = {
  18655. context: this,
  18656. options: options,
  18657. params: params
  18658. };
  18659. return Ember.Handlebars.helpers.view.call(this, LinkView, options);
  18660. });
  18661. });
  18662. })();
  18663. (function() {
  18664. /**
  18665. @module ember
  18666. @submodule ember-routing
  18667. */
  18668. var get = Ember.get, set = Ember.set;
  18669. Ember.onLoad('Ember.Handlebars', function(Handlebars) {
  18670. /**
  18671. @module ember
  18672. @submodule ember-handlebars
  18673. */
  18674. Handlebars.OutletView = Ember.ContainerView.extend(Ember._Metamorph);
  18675. /**
  18676. The `outlet` helper allows you to specify that the current
  18677. view's controller will fill in the view for a given area.
  18678. ``` handlebars
  18679. {{outlet}}
  18680. ```
  18681. By default, when the the current controller's `view` property changes, the
  18682. outlet will replace its current view with the new view. You can set the
  18683. `view` property directly, but it's normally best to use `connectOutlet`.
  18684. ``` javascript
  18685. # Instantiate App.PostsView and assign to `view`, so as to render into outlet.
  18686. controller.connectOutlet('posts');
  18687. ```
  18688. You can also specify a particular name other than `view`:
  18689. ``` handlebars
  18690. {{outlet masterView}}
  18691. {{outlet detailView}}
  18692. ```
  18693. Then, you can control several outlets from a single controller.
  18694. ``` javascript
  18695. # Instantiate App.PostsView and assign to controller.masterView.
  18696. controller.connectOutlet('masterView', 'posts');
  18697. # Also, instantiate App.PostInfoView and assign to controller.detailView.
  18698. controller.connectOutlet('detailView', 'postInfo');
  18699. ```
  18700. @method outlet
  18701. @for Ember.Handlebars.helpers
  18702. @param {String} property the property on the controller
  18703. that holds the view for this outlet
  18704. */
  18705. Handlebars.registerHelper('outlet', function(property, options) {
  18706. var outletSource;
  18707. if (property && property.data && property.data.isRenderData) {
  18708. options = property;
  18709. property = 'main';
  18710. }
  18711. outletSource = options.data.view;
  18712. while (!(outletSource.get('template.isTop'))){
  18713. outletSource = outletSource.get('_parentView');
  18714. }
  18715. options.data.view.set('outletSource', outletSource);
  18716. options.hash.currentViewBinding = '_view.outletSource._outlets.' + property;
  18717. return Handlebars.helpers.view.call(this, Handlebars.OutletView, options);
  18718. });
  18719. });
  18720. })();
  18721. (function() {
  18722. /**
  18723. @module ember
  18724. @submodule ember-routing
  18725. */
  18726. var get = Ember.get, set = Ember.set;
  18727. Ember.onLoad('Ember.Handlebars', function(Handlebars) {
  18728. /**
  18729. Renders the named template in the current context using the singleton
  18730. instance of the same-named controller.
  18731. If a view class with the same name exists, uses the view class.
  18732. If a `model` is specified, it becomes the model for that controller.
  18733. The default target for `{{action}}`s in the rendered template is the
  18734. named controller.
  18735. @method action
  18736. @for Ember.Handlebars.helpers
  18737. @param {String} actionName
  18738. @param {Object?} model
  18739. @param {Hash} options
  18740. */
  18741. Ember.Handlebars.registerHelper('render', function(name, contextString, options) {
  18742. Ember.assert("You must pass a template to render", arguments.length >= 2);
  18743. var container, router, controller, view, context;
  18744. if (arguments.length === 2) {
  18745. options = contextString;
  18746. contextString = undefined;
  18747. }
  18748. if (typeof contextString === 'string') {
  18749. context = Ember.Handlebars.get(options.contexts[1], contextString, options);
  18750. }
  18751. name = name.replace(/\//g, '.');
  18752. container = options.data.keywords.controller.container;
  18753. router = container.lookup('router:main');
  18754. Ember.assert("This view is already rendered", !router || !router._lookupActiveView(name));
  18755. view = container.lookup('view:' + name) || container.lookup('view:default');
  18756. if (controller = options.hash.controller) {
  18757. controller = container.lookup('controller:' + controller);
  18758. } else {
  18759. controller = Ember.controllerFor(container, name, context);
  18760. }
  18761. if (controller && context) {
  18762. controller.set('model', context);
  18763. }
  18764. var root = options.contexts[1];
  18765. if (root) {
  18766. view.registerObserver(root, contextString, function() {
  18767. controller.set('model', Ember.Handlebars.get(root, contextString, options));
  18768. });
  18769. }
  18770. controller.set('target', options.data.keywords.controller);
  18771. options.hash.viewName = Ember.String.camelize(name);
  18772. options.hash.template = container.lookup('template:' + name);
  18773. options.hash.controller = controller;
  18774. if (router) {
  18775. router._connectActiveView(name, view);
  18776. }
  18777. Ember.Handlebars.helpers.view.call(this, view, options);
  18778. });
  18779. });
  18780. })();
  18781. (function() {
  18782. /**
  18783. @module ember
  18784. @submodule ember-routing
  18785. */
  18786. Ember.onLoad('Ember.Handlebars', function(Handlebars) {
  18787. var resolveParams = Ember.Handlebars.resolveParams,
  18788. isSimpleClick = Ember.ViewUtils.isSimpleClick;
  18789. var EmberHandlebars = Ember.Handlebars,
  18790. handlebarsGet = EmberHandlebars.get,
  18791. SafeString = EmberHandlebars.SafeString,
  18792. get = Ember.get,
  18793. a_slice = Array.prototype.slice;
  18794. function args(options, actionName) {
  18795. var ret = [];
  18796. if (actionName) { ret.push(actionName); }
  18797. var types = options.options.types.slice(1),
  18798. data = options.options.data;
  18799. return ret.concat(resolveParams(options.context, options.params, { types: types, data: data }));
  18800. }
  18801. var ActionHelper = EmberHandlebars.ActionHelper = {
  18802. registeredActions: {}
  18803. };
  18804. ActionHelper.registerAction = function(actionName, options) {
  18805. var actionId = (++Ember.uuid).toString();
  18806. ActionHelper.registeredActions[actionId] = {
  18807. eventName: options.eventName,
  18808. handler: function(event) {
  18809. if (!isSimpleClick(event)) { return true; }
  18810. event.preventDefault();
  18811. if (options.bubbles === false) {
  18812. event.stopPropagation();
  18813. }
  18814. var view = options.view,
  18815. contexts = options.contexts,
  18816. target = options.target;
  18817. if (target.target) {
  18818. target = handlebarsGet(target.root, target.target, target.options);
  18819. } else {
  18820. target = target.root;
  18821. }
  18822. Ember.run(function() {
  18823. if (target.send) {
  18824. target.send.apply(target, args(options.parameters, actionName));
  18825. } else {
  18826. Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function');
  18827. target[actionName].apply(target, args(options.parameters));
  18828. }
  18829. });
  18830. }
  18831. };
  18832. options.view.on('willClearRender', function() {
  18833. delete ActionHelper.registeredActions[actionId];
  18834. });
  18835. return actionId;
  18836. };
  18837. /**
  18838. The `{{action}}` helper registers an HTML element within a template for DOM
  18839. event handling and forwards that interaction to the view's controller
  18840. or supplied `target` option (see 'Specifying a Target').
  18841. If the view's controller does not implement the event, the event is sent
  18842. to the current route, and it bubbles up the route hierarchy from there.
  18843. User interaction with that element will invoke the supplied action name on
  18844. the appropriate target.
  18845. Given the following Handlebars template on the page
  18846. ```handlebars
  18847. <script type="text/x-handlebars" data-template-name='a-template'>
  18848. <div {{action anActionName}}>
  18849. click me
  18850. </div>
  18851. </script>
  18852. ```
  18853. And application code
  18854. ```javascript
  18855. AController = Ember.Controller.extend({
  18856. anActionName: function() {}
  18857. });
  18858. AView = Ember.View.extend({
  18859. controller: AController.create(),
  18860. templateName: 'a-template'
  18861. });
  18862. aView = AView.create();
  18863. aView.appendTo('body');
  18864. ```
  18865. Will results in the following rendered HTML
  18866. ```html
  18867. <div class="ember-view">
  18868. <div data-ember-action="1">
  18869. click me
  18870. </div>
  18871. </div>
  18872. ```
  18873. Clicking "click me" will trigger the `anActionName` method of the
  18874. `AController`. In this case, no additional parameters will be passed.
  18875. If you provide additional parameters to the helper:
  18876. ```handlebars
  18877. <button {{action 'edit' post}}>Edit</button>
  18878. ```
  18879. Those parameters will be passed along as arguments to the JavaScript
  18880. function implementing the action.
  18881. ### Event Propagation
  18882. Events triggered through the action helper will automatically have
  18883. `.preventDefault()` called on them. You do not need to do so in your event
  18884. handlers.
  18885. To also disable bubbling, pass `bubbles=false` to the helper:
  18886. ```handlebars
  18887. <button {{action 'edit' post bubbles=false}}>Edit</button>
  18888. ```
  18889. If you need the default handler to trigger you should either register your
  18890. own event handler, or use event methods on your view class. See `Ember.View`
  18891. 'Responding to Browser Events' for more information.
  18892. ### Specifying DOM event type
  18893. By default the `{{action}}` helper registers for DOM `click` events. You can
  18894. supply an `on` option to the helper to specify a different DOM event name:
  18895. ```handlebars
  18896. <script type="text/x-handlebars" data-template-name='a-template'>
  18897. <div {{action anActionName on="doubleClick"}}>
  18898. click me
  18899. </div>
  18900. </script>
  18901. ```
  18902. See `Ember.View` 'Responding to Browser Events' for a list of
  18903. acceptable DOM event names.
  18904. NOTE: Because `{{action}}` depends on Ember's event dispatch system it will
  18905. only function if an `Ember.EventDispatcher` instance is available. An
  18906. `Ember.EventDispatcher` instance will be created when a new `Ember.Application`
  18907. is created. Having an instance of `Ember.Application` will satisfy this
  18908. requirement.
  18909. ### Specifying a Target
  18910. There are several possible target objects for `{{action}}` helpers:
  18911. In a typical Ember application, where views are managed through use of the
  18912. `{{outlet}}` helper, actions will bubble to the current controller, then
  18913. to the current route, and then up the route hierarchy.
  18914. Alternatively, a `target` option can be provided to the helper to change
  18915. which object will receive the method call. This option must be a path
  18916. path to an object, accessible in the current context:
  18917. ```handlebars
  18918. <script type="text/x-handlebars" data-template-name='a-template'>
  18919. <div {{action anActionName target="MyApplication.someObject"}}>
  18920. click me
  18921. </div>
  18922. </script>
  18923. ```
  18924. Clicking "click me" in the rendered HTML of the above template will trigger
  18925. the `anActionName` method of the object at `MyApplication.someObject`.
  18926. If an action's target does not implement a method that matches the supplied
  18927. action name an error will be thrown.
  18928. ```handlebars
  18929. <script type="text/x-handlebars" data-template-name='a-template'>
  18930. <div {{action aMethodNameThatIsMissing}}>
  18931. click me
  18932. </div>
  18933. </script>
  18934. ```
  18935. With the following application code
  18936. ```javascript
  18937. AView = Ember.View.extend({
  18938. templateName; 'a-template',
  18939. // note: no method 'aMethodNameThatIsMissing'
  18940. anActionName: function(event) {}
  18941. });
  18942. aView = AView.create();
  18943. aView.appendTo('body');
  18944. ```
  18945. Will throw `Uncaught TypeError: Cannot call method 'call' of undefined` when
  18946. "click me" is clicked.
  18947. ### Additional Parameters
  18948. You may specify additional parameters to the `{{action}}` helper. These
  18949. parameters are passed along as the arguments to the JavaScript function
  18950. implementing the action.
  18951. ```handlebars
  18952. <script type="text/x-handlebars" data-template-name='a-template'>
  18953. {{#each person in people}}
  18954. <div {{action edit person}}>
  18955. click me
  18956. </div>
  18957. {{/each}}
  18958. </script>
  18959. ```
  18960. Clicking "click me" will trigger the `edit` method on the current view's
  18961. controller with the current person as a parameter.
  18962. @method action
  18963. @for Ember.Handlebars.helpers
  18964. @param {String} actionName
  18965. @param {Object} [context]*
  18966. @param {Hash} options
  18967. */
  18968. EmberHandlebars.registerHelper('action', function(actionName) {
  18969. var options = arguments[arguments.length - 1],
  18970. contexts = a_slice.call(arguments, 1, -1);
  18971. var hash = options.hash,
  18972. view = options.data.view,
  18973. controller, link;
  18974. // create a hash to pass along to registerAction
  18975. var action = {
  18976. eventName: hash.on || "click"
  18977. };
  18978. action.parameters = {
  18979. context: this,
  18980. options: options,
  18981. params: contexts
  18982. };
  18983. action.view = view = get(view, 'concreteView');
  18984. var root, target;
  18985. if (hash.target) {
  18986. root = this;
  18987. target = hash.target;
  18988. } else if (controller = options.data.keywords.controller) {
  18989. root = controller;
  18990. }
  18991. action.target = { root: root, target: target, options: options };
  18992. action.bubbles = hash.bubbles;
  18993. var actionId = ActionHelper.registerAction(actionName, action);
  18994. return new SafeString('data-ember-action="' + actionId + '"');
  18995. });
  18996. });
  18997. })();
  18998. (function() {
  18999. /**
  19000. @module ember
  19001. @submodule ember-routing
  19002. */
  19003. if (Ember.ENV.EXPERIMENTAL_CONTROL_HELPER) {
  19004. var get = Ember.get, set = Ember.set;
  19005. /**
  19006. The control helper is currently under development and is considered experimental.
  19007. To enable it, set `ENV.EXPERIMENTAL_CONTROL_HELPER = true` before requiring Ember.
  19008. @method control
  19009. @for Ember.Handlebars.helpers
  19010. @param {String} path
  19011. @param {String} modelPath
  19012. @param {Hash} options
  19013. @return {String} HTML string
  19014. */
  19015. Ember.Handlebars.registerHelper('control', function(path, modelPath, options) {
  19016. if (arguments.length === 2) {
  19017. options = modelPath;
  19018. modelPath = undefined;
  19019. }
  19020. var model;
  19021. if (modelPath) {
  19022. model = Ember.Handlebars.get(this, modelPath, options);
  19023. }
  19024. var controller = options.data.keywords.controller,
  19025. view = options.data.keywords.view,
  19026. children = get(controller, '_childContainers'),
  19027. controlID = options.hash.controlID,
  19028. container, subContainer;
  19029. if (children.hasOwnProperty(controlID)) {
  19030. subContainer = children[controlID];
  19031. } else {
  19032. container = get(controller, 'container'),
  19033. subContainer = container.child();
  19034. children[controlID] = subContainer;
  19035. }
  19036. var normalizedPath = path.replace(/\//g, '.');
  19037. var childView = subContainer.lookup('view:' + normalizedPath) || subContainer.lookup('view:default'),
  19038. childController = subContainer.lookup('controller:' + normalizedPath),
  19039. childTemplate = subContainer.lookup('template:' + path);
  19040. Ember.assert("Could not find controller for path: " + normalizedPath, childController);
  19041. Ember.assert("Could not find view for path: " + normalizedPath, childView);
  19042. set(childController, 'target', controller);
  19043. set(childController, 'model', model);
  19044. options.hash.template = childTemplate;
  19045. options.hash.controller = childController;
  19046. function observer() {
  19047. var model = Ember.Handlebars.get(this, modelPath, options);
  19048. set(childController, 'model', model);
  19049. childView.rerender();
  19050. }
  19051. Ember.addObserver(this, modelPath, observer);
  19052. childView.one('willDestroyElement', this, function() {
  19053. Ember.removeObserver(this, modelPath, observer);
  19054. });
  19055. Ember.Handlebars.helpers.view.call(this, childView, options);
  19056. });
  19057. }
  19058. })();
  19059. (function() {
  19060. })();
  19061. (function() {
  19062. /**
  19063. @module ember
  19064. @submodule ember-routing
  19065. */
  19066. var get = Ember.get, set = Ember.set;
  19067. Ember.ControllerMixin.reopen({
  19068. transitionToRoute: function() {
  19069. // target may be either another controller or a router
  19070. var target = get(this, 'target'),
  19071. method = target.transitionToRoute || target.transitionTo;
  19072. return method.apply(target, arguments);
  19073. },
  19074. transitionTo: function() {
  19075. Ember.deprecate("transitionTo is deprecated. Please use transitionToRoute.");
  19076. return this.transitionToRoute.apply(this, arguments);
  19077. },
  19078. replaceRoute: function() {
  19079. // target may be either another controller or a router
  19080. var target = get(this, 'target'),
  19081. method = target.replaceRoute || target.replaceWith;
  19082. return method.apply(target, arguments);
  19083. },
  19084. replaceWith: function() {
  19085. Ember.deprecate("replaceWith is deprecated. Please use replaceRoute.");
  19086. return this.replaceRoute.apply(this, arguments);
  19087. }
  19088. });
  19089. })();
  19090. (function() {
  19091. /**
  19092. @module ember
  19093. @submodule ember-routing
  19094. */
  19095. var get = Ember.get, set = Ember.set;
  19096. Ember.View.reopen({
  19097. init: function() {
  19098. set(this, '_outlets', {});
  19099. this._super();
  19100. },
  19101. connectOutlet: function(outletName, view) {
  19102. var outlets = get(this, '_outlets'),
  19103. container = get(this, 'container'),
  19104. router = container && container.lookup('router:main'),
  19105. renderedName = get(view, 'renderedName');
  19106. set(outlets, outletName, view);
  19107. if (router && renderedName) {
  19108. router._connectActiveView(renderedName, view);
  19109. }
  19110. },
  19111. disconnectOutlet: function(outletName) {
  19112. var outlets = get(this, '_outlets');
  19113. set(outlets, outletName, null);
  19114. }
  19115. });
  19116. })();
  19117. (function() {
  19118. })();
  19119. (function() {
  19120. /**
  19121. @module ember
  19122. @submodule ember-routing
  19123. */
  19124. var get = Ember.get, set = Ember.set;
  19125. /*
  19126. This file implements the `location` API used by Ember's router.
  19127. That API is:
  19128. getURL: returns the current URL
  19129. setURL(path): sets the current URL
  19130. replaceURL(path): replace the current URL (optional)
  19131. onUpdateURL(callback): triggers the callback when the URL changes
  19132. formatURL(url): formats `url` to be placed into `href` attribute
  19133. Calling setURL or replaceURL will not trigger onUpdateURL callbacks.
  19134. TODO: This should perhaps be moved so that it's visible in the doc output.
  19135. */
  19136. /**
  19137. Ember.Location returns an instance of the correct implementation of
  19138. the `location` API.
  19139. You can pass it a `implementation` ('hash', 'history', 'none') to force a
  19140. particular implementation.
  19141. @class Location
  19142. @namespace Ember
  19143. @static
  19144. */
  19145. Ember.Location = {
  19146. create: function(options) {
  19147. var implementation = options && options.implementation;
  19148. Ember.assert("Ember.Location.create: you must specify a 'implementation' option", !!implementation);
  19149. var implementationClass = this.implementations[implementation];
  19150. Ember.assert("Ember.Location.create: " + implementation + " is not a valid implementation", !!implementationClass);
  19151. return implementationClass.create.apply(implementationClass, arguments);
  19152. },
  19153. registerImplementation: function(name, implementation) {
  19154. this.implementations[name] = implementation;
  19155. },
  19156. implementations: {}
  19157. };
  19158. })();
  19159. (function() {
  19160. /**
  19161. @module ember
  19162. @submodule ember-routing
  19163. */
  19164. var get = Ember.get, set = Ember.set;
  19165. /**
  19166. Ember.NoneLocation does not interact with the browser. It is useful for
  19167. testing, or when you need to manage state with your Router, but temporarily
  19168. don't want it to muck with the URL (for example when you embed your
  19169. application in a larger page).
  19170. @class NoneLocation
  19171. @namespace Ember
  19172. @extends Ember.Object
  19173. */
  19174. Ember.NoneLocation = Ember.Object.extend({
  19175. path: '',
  19176. getURL: function() {
  19177. return get(this, 'path');
  19178. },
  19179. setURL: function(path) {
  19180. set(this, 'path', path);
  19181. },
  19182. onUpdateURL: function(callback) {
  19183. this.updateCallback = callback;
  19184. },
  19185. handleURL: function(url) {
  19186. set(this, 'path', url);
  19187. this.updateCallback(url);
  19188. },
  19189. formatURL: function(url) {
  19190. // The return value is not overly meaningful, but we do not want to throw
  19191. // errors when test code renders templates containing {{action href=true}}
  19192. // helpers.
  19193. return url;
  19194. }
  19195. });
  19196. Ember.Location.registerImplementation('none', Ember.NoneLocation);
  19197. })();
  19198. (function() {
  19199. /**
  19200. @module ember
  19201. @submodule ember-routing
  19202. */
  19203. var get = Ember.get, set = Ember.set;
  19204. /**
  19205. Ember.HashLocation implements the location API using the browser's
  19206. hash. At present, it relies on a hashchange event existing in the
  19207. browser.
  19208. @class HashLocation
  19209. @namespace Ember
  19210. @extends Ember.Object
  19211. */
  19212. Ember.HashLocation = Ember.Object.extend({
  19213. init: function() {
  19214. set(this, 'location', get(this, 'location') || window.location);
  19215. },
  19216. /**
  19217. @private
  19218. Returns the current `location.hash`, minus the '#' at the front.
  19219. @method getURL
  19220. */
  19221. getURL: function() {
  19222. return get(this, 'location').hash.substr(1);
  19223. },
  19224. /**
  19225. @private
  19226. Set the `location.hash` and remembers what was set. This prevents
  19227. `onUpdateURL` callbacks from triggering when the hash was set by
  19228. `HashLocation`.
  19229. @method setURL
  19230. @param path {String}
  19231. */
  19232. setURL: function(path) {
  19233. get(this, 'location').hash = path;
  19234. set(this, 'lastSetURL', path);
  19235. },
  19236. /**
  19237. @private
  19238. Register a callback to be invoked when the hash changes. These
  19239. callbacks will execute when the user presses the back or forward
  19240. button, but not after `setURL` is invoked.
  19241. @method onUpdateURL
  19242. @param callback {Function}
  19243. */
  19244. onUpdateURL: function(callback) {
  19245. var self = this;
  19246. var guid = Ember.guidFor(this);
  19247. Ember.$(window).bind('hashchange.ember-location-'+guid, function() {
  19248. Ember.run(function() {
  19249. var path = location.hash.substr(1);
  19250. if (get(self, 'lastSetURL') === path) { return; }
  19251. set(self, 'lastSetURL', null);
  19252. callback(location.hash.substr(1));
  19253. });
  19254. });
  19255. },
  19256. /**
  19257. @private
  19258. Given a URL, formats it to be placed into the page as part
  19259. of an element's `href` attribute.
  19260. This is used, for example, when using the {{action}} helper
  19261. to generate a URL based on an event.
  19262. @method formatURL
  19263. @param url {String}
  19264. */
  19265. formatURL: function(url) {
  19266. return '#'+url;
  19267. },
  19268. willDestroy: function() {
  19269. var guid = Ember.guidFor(this);
  19270. Ember.$(window).unbind('hashchange.ember-location-'+guid);
  19271. }
  19272. });
  19273. Ember.Location.registerImplementation('hash', Ember.HashLocation);
  19274. })();
  19275. (function() {
  19276. /**
  19277. @module ember
  19278. @submodule ember-routing
  19279. */
  19280. var get = Ember.get, set = Ember.set;
  19281. var popstateReady = false;
  19282. /**
  19283. Ember.HistoryLocation implements the location API using the browser's
  19284. history.pushState API.
  19285. @class HistoryLocation
  19286. @namespace Ember
  19287. @extends Ember.Object
  19288. */
  19289. Ember.HistoryLocation = Ember.Object.extend({
  19290. init: function() {
  19291. set(this, 'location', get(this, 'location') || window.location);
  19292. this.initState();
  19293. },
  19294. /**
  19295. @private
  19296. Used to set state on first call to setURL
  19297. @method initState
  19298. */
  19299. initState: function() {
  19300. this.replaceState(this.formatURL(this.getURL()));
  19301. set(this, 'history', window.history);
  19302. },
  19303. /**
  19304. Will be pre-pended to path upon state change
  19305. @property rootURL
  19306. @default '/'
  19307. */
  19308. rootURL: '/',
  19309. /**
  19310. @private
  19311. Returns the current `location.pathname` without rootURL
  19312. @method getURL
  19313. */
  19314. getURL: function() {
  19315. var rootURL = get(this, 'rootURL'),
  19316. url = get(this, 'location').pathname;
  19317. rootURL = rootURL.replace(/\/$/, '');
  19318. url = url.replace(rootURL, '');
  19319. return url;
  19320. },
  19321. /**
  19322. @private
  19323. Uses `history.pushState` to update the url without a page reload.
  19324. @method setURL
  19325. @param path {String}
  19326. */
  19327. setURL: function(path) {
  19328. path = this.formatURL(path);
  19329. if (this.getState() && this.getState().path !== path) {
  19330. popstateReady = true;
  19331. this.pushState(path);
  19332. }
  19333. },
  19334. /**
  19335. @private
  19336. Uses `history.replaceState` to update the url without a page reload
  19337. or history modification.
  19338. @method replaceURL
  19339. @param path {String}
  19340. */
  19341. replaceURL: function(path) {
  19342. path = this.formatURL(path);
  19343. if (this.getState() && this.getState().path !== path) {
  19344. popstateReady = true;
  19345. this.replaceState(path);
  19346. }
  19347. },
  19348. /**
  19349. @private
  19350. Get the current `history.state`
  19351. @method getState
  19352. */
  19353. getState: function() {
  19354. return get(this, 'history').state;
  19355. },
  19356. /**
  19357. @private
  19358. Pushes a new state
  19359. @method pushState
  19360. @param path {String}
  19361. */
  19362. pushState: function(path) {
  19363. window.history.pushState({ path: path }, null, path);
  19364. },
  19365. /**
  19366. @private
  19367. Replaces the current state
  19368. @method replaceState
  19369. @param path {String}
  19370. */
  19371. replaceState: function(path) {
  19372. window.history.replaceState({ path: path }, null, path);
  19373. },
  19374. /**
  19375. @private
  19376. Register a callback to be invoked whenever the browser
  19377. history changes, including using forward and back buttons.
  19378. @method onUpdateURL
  19379. @param callback {Function}
  19380. */
  19381. onUpdateURL: function(callback) {
  19382. var guid = Ember.guidFor(this),
  19383. self = this;
  19384. Ember.$(window).bind('popstate.ember-location-'+guid, function(e) {
  19385. if(!popstateReady) {
  19386. return;
  19387. }
  19388. callback(self.getURL());
  19389. });
  19390. },
  19391. /**
  19392. @private
  19393. Used when using `{{action}}` helper. The url is always appended to the rootURL.
  19394. @method formatURL
  19395. @param url {String}
  19396. */
  19397. formatURL: function(url) {
  19398. var rootURL = get(this, 'rootURL');
  19399. if (url !== '') {
  19400. rootURL = rootURL.replace(/\/$/, '');
  19401. }
  19402. return rootURL + url;
  19403. },
  19404. willDestroy: function() {
  19405. var guid = Ember.guidFor(this);
  19406. Ember.$(window).unbind('popstate.ember-location-'+guid);
  19407. }
  19408. });
  19409. Ember.Location.registerImplementation('history', Ember.HistoryLocation);
  19410. })();
  19411. (function() {
  19412. })();
  19413. (function() {
  19414. /**
  19415. Ember Routing
  19416. @module ember
  19417. @submodule ember-routing
  19418. @requires ember-states
  19419. @requires ember-views
  19420. */
  19421. })();
  19422. (function() {
  19423. function visit(vertex, fn, visited, path) {
  19424. var name = vertex.name,
  19425. vertices = vertex.incoming,
  19426. names = vertex.incomingNames,
  19427. len = names.length,
  19428. i;
  19429. if (!visited) {
  19430. visited = {};
  19431. }
  19432. if (!path) {
  19433. path = [];
  19434. }
  19435. if (visited.hasOwnProperty(name)) {
  19436. return;
  19437. }
  19438. path.push(name);
  19439. visited[name] = true;
  19440. for (i = 0; i < len; i++) {
  19441. visit(vertices[names[i]], fn, visited, path);
  19442. }
  19443. fn(vertex, path);
  19444. path.pop();
  19445. }
  19446. function DAG() {
  19447. this.names = [];
  19448. this.vertices = {};
  19449. }
  19450. DAG.prototype.add = function(name) {
  19451. if (!name) { return; }
  19452. if (this.vertices.hasOwnProperty(name)) {
  19453. return this.vertices[name];
  19454. }
  19455. var vertex = {
  19456. name: name, incoming: {}, incomingNames: [], hasOutgoing: false, value: null
  19457. };
  19458. this.vertices[name] = vertex;
  19459. this.names.push(name);
  19460. return vertex;
  19461. };
  19462. DAG.prototype.map = function(name, value) {
  19463. this.add(name).value = value;
  19464. };
  19465. DAG.prototype.addEdge = function(fromName, toName) {
  19466. if (!fromName || !toName || fromName === toName) {
  19467. return;
  19468. }
  19469. var from = this.add(fromName), to = this.add(toName);
  19470. if (to.incoming.hasOwnProperty(fromName)) {
  19471. return;
  19472. }
  19473. function checkCycle(vertex, path) {
  19474. if (vertex.name === toName) {
  19475. throw new Error("cycle detected: " + toName + " <- " + path.join(" <- "));
  19476. }
  19477. }
  19478. visit(from, checkCycle);
  19479. from.hasOutgoing = true;
  19480. to.incoming[fromName] = from;
  19481. to.incomingNames.push(fromName);
  19482. };
  19483. DAG.prototype.topsort = function(fn) {
  19484. var visited = {},
  19485. vertices = this.vertices,
  19486. names = this.names,
  19487. len = names.length,
  19488. i, vertex;
  19489. for (i = 0; i < len; i++) {
  19490. vertex = vertices[names[i]];
  19491. if (!vertex.hasOutgoing) {
  19492. visit(vertex, fn, visited);
  19493. }
  19494. }
  19495. };
  19496. DAG.prototype.addEdges = function(name, value, before, after) {
  19497. var i;
  19498. this.map(name, value);
  19499. if (before) {
  19500. if (typeof before === 'string') {
  19501. this.addEdge(name, before);
  19502. } else {
  19503. for (i = 0; i < before.length; i++) {
  19504. this.addEdge(name, before[i]);
  19505. }
  19506. }
  19507. }
  19508. if (after) {
  19509. if (typeof after === 'string') {
  19510. this.addEdge(after, name);
  19511. } else {
  19512. for (i = 0; i < after.length; i++) {
  19513. this.addEdge(after[i], name);
  19514. }
  19515. }
  19516. }
  19517. };
  19518. Ember.DAG = DAG;
  19519. })();
  19520. (function() {
  19521. /**
  19522. @module ember
  19523. @submodule ember-application
  19524. */
  19525. var get = Ember.get, set = Ember.set,
  19526. classify = Ember.String.classify,
  19527. decamelize = Ember.String.decamelize;
  19528. /**
  19529. An instance of `Ember.Application` is the starting point for every Ember
  19530. application. It helps to instantiate, initialize and coordinate the many
  19531. objects that make up your app.
  19532. Each Ember app has one and only one `Ember.Application` object. In fact, the
  19533. very first thing you should do in your application is create the instance:
  19534. ```javascript
  19535. window.App = Ember.Application.create();
  19536. ```
  19537. Typically, the application object is the only global variable. All other
  19538. classes in your app should be properties on the `Ember.Application` instance,
  19539. which highlights its first role: a global namespace.
  19540. For example, if you define a view class, it might look like this:
  19541. ```javascript
  19542. App.MyView = Ember.View.extend();
  19543. ```
  19544. By default, calling `Ember.Application.create()` will automatically initialize
  19545. your application by calling the `Ember.Application.initialize()` method. If
  19546. you need to delay initialization, you can call your app's `deferReadiness()`
  19547. method. When you are ready for your app to be initialized, call its
  19548. `advanceReadiness()` method.
  19549. Because `Ember.Application` inherits from `Ember.Namespace`, any classes
  19550. you create will have useful string representations when calling `toString()`.
  19551. See the `Ember.Namespace` documentation for more information.
  19552. While you can think of your `Ember.Application` as a container that holds the
  19553. other classes in your application, there are several other responsibilities
  19554. going on under-the-hood that you may want to understand.
  19555. ### Event Delegation
  19556. Ember uses a technique called _event delegation_. This allows the framework
  19557. to set up a global, shared event listener instead of requiring each view to
  19558. do it manually. For example, instead of each view registering its own
  19559. `mousedown` listener on its associated element, Ember sets up a `mousedown`
  19560. listener on the `body`.
  19561. If a `mousedown` event occurs, Ember will look at the target of the event and
  19562. start walking up the DOM node tree, finding corresponding views and invoking
  19563. their `mouseDown` method as it goes.
  19564. `Ember.Application` has a number of default events that it listens for, as
  19565. well as a mapping from lowercase events to camel-cased view method names. For
  19566. example, the `keypress` event causes the `keyPress` method on the view to be
  19567. called, the `dblclick` event causes `doubleClick` to be called, and so on.
  19568. If there is a browser event that Ember does not listen for by default, you
  19569. can specify custom events and their corresponding view method names by
  19570. setting the application's `customEvents` property:
  19571. ```javascript
  19572. App = Ember.Application.create({
  19573. customEvents: {
  19574. // add support for the loadedmetadata media
  19575. // player event
  19576. 'loadedmetadata': "loadedMetadata"
  19577. }
  19578. });
  19579. ```
  19580. By default, the application sets up these event listeners on the document
  19581. body. However, in cases where you are embedding an Ember application inside
  19582. an existing page, you may want it to set up the listeners on an element
  19583. inside the body.
  19584. For example, if only events inside a DOM element with the ID of `ember-app`
  19585. should be delegated, set your application's `rootElement` property:
  19586. ```javascript
  19587. window.App = Ember.Application.create({
  19588. rootElement: '#ember-app'
  19589. });
  19590. ```
  19591. The `rootElement` can be either a DOM element or a jQuery-compatible selector
  19592. string. Note that *views appended to the DOM outside the root element will
  19593. not receive events.* If you specify a custom root element, make sure you only
  19594. append views inside it!
  19595. To learn more about the advantages of event delegation and the Ember view
  19596. layer, and a list of the event listeners that are setup by default, visit the
  19597. [Ember View Layer guide](http://emberjs.com/guides/view_layer#toc_event-delegation).
  19598. ### Initializers
  19599. Libraries on top of Ember can register additional initializers, like so:
  19600. ```javascript
  19601. Ember.Application.initializer({
  19602. name: "store",
  19603. initialize: function(container, application) {
  19604. container.register('store', 'main', application.Store);
  19605. }
  19606. });
  19607. ```
  19608. ### Routing
  19609. In addition to creating your application's router, `Ember.Application` is
  19610. also responsible for telling the router when to start routing. Transitions
  19611. between routes can be logged with the LOG_TRANSITIONS flag:
  19612. ```javascript
  19613. window.App = Ember.Application.create({
  19614. LOG_TRANSITIONS: true
  19615. });
  19616. ```
  19617. By default, the router will begin trying to translate the current URL into
  19618. application state once the browser emits the `DOMContentReady` event. If you
  19619. need to defer routing, you can call the application's `deferReadiness()`
  19620. method. Once routing can begin, call the `advanceReadiness()` method.
  19621. If there is any setup required before routing begins, you can implement a
  19622. `ready()` method on your app that will be invoked immediately before routing
  19623. begins.
  19624. To begin routing, you must have at a minimum a top-level controller and view.
  19625. You define these as `App.ApplicationController` and `App.ApplicationView`,
  19626. respectively. Your application will not work if you do not define these two
  19627. mandatory classes. For example:
  19628. ```javascript
  19629. App.ApplicationView = Ember.View.extend({
  19630. templateName: 'application'
  19631. });
  19632. App.ApplicationController = Ember.Controller.extend();
  19633. ```
  19634. @class Application
  19635. @namespace Ember
  19636. @extends Ember.Namespace
  19637. */
  19638. var Application = Ember.Application = Ember.Namespace.extend({
  19639. /**
  19640. The root DOM element of the Application. This can be specified as an
  19641. element or a
  19642. [jQuery-compatible selector string](http://api.jquery.com/category/selectors/).
  19643. This is the element that will be passed to the Application's,
  19644. `eventDispatcher`, which sets up the listeners for event delegation. Every
  19645. view in your application should be a child of the element you specify here.
  19646. @property rootElement
  19647. @type DOMElement
  19648. @default 'body'
  19649. */
  19650. rootElement: 'body',
  19651. /**
  19652. The `Ember.EventDispatcher` responsible for delegating events to this
  19653. application's views.
  19654. The event dispatcher is created by the application at initialization time
  19655. and sets up event listeners on the DOM element described by the
  19656. application's `rootElement` property.
  19657. See the documentation for `Ember.EventDispatcher` for more information.
  19658. @property eventDispatcher
  19659. @type Ember.EventDispatcher
  19660. @default null
  19661. */
  19662. eventDispatcher: null,
  19663. /**
  19664. The DOM events for which the event dispatcher should listen.
  19665. By default, the application's `Ember.EventDispatcher` listens
  19666. for a set of standard DOM events, such as `mousedown` and
  19667. `keyup`, and delegates them to your application's `Ember.View`
  19668. instances.
  19669. If you would like additional events to be delegated to your
  19670. views, set your `Ember.Application`'s `customEvents` property
  19671. to a hash containing the DOM event name as the key and the
  19672. corresponding view method name as the value. For example:
  19673. ```javascript
  19674. App = Ember.Application.create({
  19675. customEvents: {
  19676. // add support for the loadedmetadata media
  19677. // player event
  19678. 'loadedmetadata': "loadedMetadata"
  19679. }
  19680. });
  19681. ```
  19682. @property customEvents
  19683. @type Object
  19684. @default null
  19685. */
  19686. customEvents: null,
  19687. isInitialized: false,
  19688. // Start off the number of deferrals at 1. This will be
  19689. // decremented by the Application's own `initialize` method.
  19690. _readinessDeferrals: 1,
  19691. init: function() {
  19692. if (!this.$) { this.$ = Ember.$; }
  19693. this.__container__ = this.buildContainer();
  19694. this.Router = this.Router || this.defaultRouter();
  19695. if (this.Router) { this.Router.namespace = this; }
  19696. this._super();
  19697. this.deferUntilDOMReady();
  19698. this.scheduleInitialize();
  19699. Ember.debug('-------------------------------');
  19700. Ember.debug('Ember.VERSION : ' + Ember.VERSION);
  19701. Ember.debug('Handlebars.VERSION : ' + Ember.Handlebars.VERSION);
  19702. Ember.debug('jQuery.VERSION : ' + Ember.$().jquery);
  19703. Ember.debug('-------------------------------');
  19704. },
  19705. /**
  19706. @private
  19707. Build the container for the current application.
  19708. Also register a default application view in case the application
  19709. itself does not.
  19710. @method buildContainer
  19711. @return {Ember.Container} the configured container
  19712. */
  19713. buildContainer: function() {
  19714. var container = this.__container__ = Application.buildContainer(this);
  19715. return container;
  19716. },
  19717. /**
  19718. @private
  19719. If the application has not opted out of routing and has not explicitly
  19720. defined a router, supply a default router for the application author
  19721. to configure.
  19722. This allows application developers to do:
  19723. ```javascript
  19724. App = Ember.Application.create();
  19725. App.Router.map(function(match) {
  19726. match("/").to("index");
  19727. });
  19728. ```
  19729. @method defaultRouter
  19730. @return {Ember.Router} the default router
  19731. */
  19732. defaultRouter: function() {
  19733. // Create a default App.Router if one was not supplied to make
  19734. // it possible to do App.Router.map(...) without explicitly
  19735. // creating a router first.
  19736. if (this.router === undefined) {
  19737. return Ember.Router.extend();
  19738. }
  19739. },
  19740. /**
  19741. @private
  19742. Defer Ember readiness until DOM readiness. By default, Ember
  19743. will wait for both DOM readiness and application initialization,
  19744. as well as any deferrals registered by initializers.
  19745. @method deferUntilDOMReady
  19746. */
  19747. deferUntilDOMReady: function() {
  19748. this.deferReadiness();
  19749. var self = this;
  19750. this.$().ready(function() {
  19751. self.advanceReadiness();
  19752. });
  19753. },
  19754. /**
  19755. @private
  19756. Automatically initialize the application once the DOM has
  19757. become ready.
  19758. The initialization itself is deferred using Ember.run.once,
  19759. which ensures that application loading finishes before
  19760. booting.
  19761. If you are asynchronously loading code, you should call
  19762. `deferReadiness()` to defer booting, and then call
  19763. `advanceReadiness()` once all of your code has finished
  19764. loading.
  19765. @method scheduleInitialize
  19766. */
  19767. scheduleInitialize: function() {
  19768. var self = this;
  19769. this.$().ready(function() {
  19770. if (self.isDestroyed || self.isInitialized) return;
  19771. Ember.run.once(self, 'initialize');
  19772. });
  19773. },
  19774. /**
  19775. Use this to defer readiness until some condition is true.
  19776. Example:
  19777. ```javascript
  19778. App = Ember.Application.create();
  19779. App.deferReadiness();
  19780. jQuery.getJSON("/auth-token", function(token) {
  19781. App.token = token;
  19782. App.advanceReadiness();
  19783. });
  19784. ```
  19785. This allows you to perform asynchronous setup logic and defer
  19786. booting your application until the setup has finished.
  19787. However, if the setup requires a loading UI, it might be better
  19788. to use the router for this purpose.
  19789. @method deferReadiness
  19790. */
  19791. deferReadiness: function() {
  19792. Ember.assert("You cannot defer readiness since the `ready()` hook has already been called.", this._readinessDeferrals > 0);
  19793. this._readinessDeferrals++;
  19794. },
  19795. /**
  19796. @method advanceReadiness
  19797. @see {Ember.Application#deferReadiness}
  19798. */
  19799. advanceReadiness: function() {
  19800. this._readinessDeferrals--;
  19801. if (this._readinessDeferrals === 0) {
  19802. Ember.run.once(this, this.didBecomeReady);
  19803. }
  19804. },
  19805. /**
  19806. registers a factory for later injection
  19807. Example:
  19808. ```javascript
  19809. App = Ember.Application.create();
  19810. App.Person = Ember.Object.extend({});
  19811. App.Orange = Ember.Object.extend({});
  19812. App.Email = Ember.Object.extend({});
  19813. App.register('model:user', App.Person, {singleton: false });
  19814. App.register('fruit:favorite', App.Orange);
  19815. App.register('communication:main', App.Email, {singleton: false});
  19816. ```
  19817. @method register
  19818. @param type {String}
  19819. @param name {String}
  19820. @param factory {String}
  19821. @param options {String} (optional)
  19822. **/
  19823. register: function() {
  19824. var container = this.__container__;
  19825. container.register.apply(container, arguments);
  19826. },
  19827. /**
  19828. defines an injection or typeInjection
  19829. Example:
  19830. ```javascript
  19831. App.inject(<full_name or type>, <property name>, <full_name>)
  19832. App.inject('model:user', 'email', 'model:email')
  19833. App.inject('model', 'source', 'source:main')
  19834. ```
  19835. @method inject
  19836. @param factoryNameOrType {String}
  19837. @param property {String}
  19838. @param injectionName {String}
  19839. **/
  19840. inject: function(){
  19841. var container = this.__container__;
  19842. container.injection.apply(container, arguments);
  19843. },
  19844. /**
  19845. @private
  19846. Initialize the application. This happens automatically.
  19847. Run any initializers and run the application load hook. These hooks may
  19848. choose to defer readiness. For example, an authentication hook might want
  19849. to defer readiness until the auth token has been retrieved.
  19850. @method initialize
  19851. */
  19852. initialize: function() {
  19853. Ember.assert("Application initialize may only be called once", !this.isInitialized);
  19854. Ember.assert("Cannot initialize a destroyed application", !this.isDestroyed);
  19855. this.isInitialized = true;
  19856. // At this point, the App.Router must already be assigned
  19857. this.__container__.register('router', 'main', this.Router);
  19858. this.runInitializers();
  19859. Ember.runLoadHooks('application', this);
  19860. // At this point, any initializers or load hooks that would have wanted
  19861. // to defer readiness have fired. In general, advancing readiness here
  19862. // will proceed to didBecomeReady.
  19863. this.advanceReadiness();
  19864. return this;
  19865. },
  19866. reset: function() {
  19867. get(this, '__container__').destroy();
  19868. this.buildContainer();
  19869. this.isInitialized = false;
  19870. this.initialize();
  19871. this.startRouting();
  19872. },
  19873. /**
  19874. @private
  19875. @method runInitializers
  19876. */
  19877. runInitializers: function() {
  19878. var initializers = get(this.constructor, 'initializers'),
  19879. container = this.__container__,
  19880. graph = new Ember.DAG(),
  19881. namespace = this,
  19882. properties, i, initializer;
  19883. for (i=0; i<initializers.length; i++) {
  19884. initializer = initializers[i];
  19885. graph.addEdges(initializer.name, initializer.initialize, initializer.before, initializer.after);
  19886. }
  19887. graph.topsort(function (vertex) {
  19888. var initializer = vertex.value;
  19889. initializer(container, namespace);
  19890. });
  19891. },
  19892. /**
  19893. @private
  19894. @method didBecomeReady
  19895. */
  19896. didBecomeReady: function() {
  19897. this.setupEventDispatcher();
  19898. this.ready(); // user hook
  19899. this.startRouting();
  19900. if (!Ember.testing) {
  19901. // Eagerly name all classes that are already loaded
  19902. Ember.Namespace.processAll();
  19903. Ember.BOOTED = true;
  19904. }
  19905. },
  19906. /**
  19907. @private
  19908. Setup up the event dispatcher to receive events on the
  19909. application's `rootElement` with any registered
  19910. `customEvents`.
  19911. @method setupEventDispatcher
  19912. */
  19913. setupEventDispatcher: function() {
  19914. var eventDispatcher = this.createEventDispatcher(),
  19915. customEvents = get(this, 'customEvents');
  19916. eventDispatcher.setup(customEvents);
  19917. },
  19918. /**
  19919. @private
  19920. Create an event dispatcher for the application's `rootElement`.
  19921. @method createEventDispatcher
  19922. */
  19923. createEventDispatcher: function() {
  19924. var rootElement = get(this, 'rootElement'),
  19925. eventDispatcher = Ember.EventDispatcher.create({
  19926. rootElement: rootElement
  19927. });
  19928. set(this, 'eventDispatcher', eventDispatcher);
  19929. return eventDispatcher;
  19930. },
  19931. /**
  19932. @private
  19933. If the application has a router, use it to route to the current URL, and
  19934. trigger a new call to `route` whenever the URL changes.
  19935. @method startRouting
  19936. @property router {Ember.Router}
  19937. */
  19938. startRouting: function() {
  19939. var router = this.__container__.lookup('router:main');
  19940. if (!router) { return; }
  19941. router.startRouting();
  19942. },
  19943. handleURL: function(url) {
  19944. var router = this.__container__.lookup('router:main');
  19945. router.handleURL(url);
  19946. },
  19947. /**
  19948. Called when the Application has become ready.
  19949. The call will be delayed until the DOM has become ready.
  19950. @event ready
  19951. */
  19952. ready: Ember.K,
  19953. willDestroy: function() {
  19954. Ember.BOOTED = false;
  19955. var eventDispatcher = get(this, 'eventDispatcher');
  19956. if (eventDispatcher) { eventDispatcher.destroy(); }
  19957. get(this, '__container__').destroy();
  19958. },
  19959. initializer: function(options) {
  19960. this.constructor.initializer(options);
  19961. }
  19962. });
  19963. Ember.Application.reopenClass({
  19964. concatenatedProperties: ['initializers'],
  19965. initializers: Ember.A(),
  19966. initializer: function(initializer) {
  19967. var initializers = get(this, 'initializers');
  19968. Ember.assert("The initializer '" + initializer.name + "' has already been registered", !initializers.findProperty('name', initializers.name));
  19969. Ember.assert("An injection cannot be registered with both a before and an after", !(initializer.before && initializer.after));
  19970. Ember.assert("An injection cannot be registered without an injection function", Ember.canInvoke(initializer, 'initialize'));
  19971. initializers.push(initializer);
  19972. },
  19973. /**
  19974. @private
  19975. This creates a container with the default Ember naming conventions.
  19976. It also configures the container:
  19977. * registered views are created every time they are looked up (they are
  19978. not singletons)
  19979. * registered templates are not factories; the registered value is
  19980. returned directly.
  19981. * the router receives the application as its `namespace` property
  19982. * all controllers receive the router as their `target` and `controllers`
  19983. properties
  19984. * all controllers receive the application as their `namespace` property
  19985. * the application view receives the application controller as its
  19986. `controller` property
  19987. * the application view receives the application template as its
  19988. `defaultTemplate` property
  19989. @method buildContainer
  19990. @static
  19991. @param {Ember.Application} namespace the application to build the
  19992. container for.
  19993. @return {Ember.Container} the built container
  19994. */
  19995. buildContainer: function(namespace) {
  19996. var container = new Ember.Container();
  19997. Ember.Container.defaultContainer = Ember.Container.defaultContainer || container;
  19998. container.set = Ember.set;
  19999. container.resolver = resolverFor(namespace);
  20000. container.optionsForType('view', { singleton: false });
  20001. container.optionsForType('template', { instantiate: false });
  20002. container.register('application', 'main', namespace, { instantiate: false });
  20003. container.injection('router:main', 'namespace', 'application:main');
  20004. container.typeInjection('controller', 'target', 'router:main');
  20005. container.typeInjection('controller', 'namespace', 'application:main');
  20006. container.typeInjection('route', 'router', 'router:main');
  20007. return container;
  20008. }
  20009. });
  20010. /**
  20011. @private
  20012. This function defines the default lookup rules for container lookups:
  20013. * templates are looked up on `Ember.TEMPLATES`
  20014. * other names are looked up on the application after classifying the name.
  20015. For example, `controller:post` looks up `App.PostController` by default.
  20016. * if the default lookup fails, look for registered classes on the container
  20017. This allows the application to register default injections in the container
  20018. that could be overridden by the normal naming convention.
  20019. @param {Ember.Namespace} namespace the namespace to look for classes
  20020. @return {any} the resolved value for a given lookup
  20021. */
  20022. function resolverFor(namespace) {
  20023. return function(fullName) {
  20024. var nameParts = fullName.split(":"),
  20025. type = nameParts[0], name = nameParts[1];
  20026. if (type === 'template') {
  20027. var templateName = name.replace(/\./g, '/');
  20028. if (Ember.TEMPLATES[templateName]) {
  20029. return Ember.TEMPLATES[templateName];
  20030. }
  20031. templateName = decamelize(templateName);
  20032. if (Ember.TEMPLATES[templateName]) {
  20033. return Ember.TEMPLATES[templateName];
  20034. }
  20035. }
  20036. if (type === 'controller' || type === 'route' || type === 'view') {
  20037. name = name.replace(/\./g, '_');
  20038. }
  20039. var className = classify(name) + classify(type);
  20040. var factory = get(namespace, className);
  20041. if (factory) { return factory; }
  20042. };
  20043. }
  20044. Ember.runLoadHooks('Ember.Application', Ember.Application);
  20045. })();
  20046. (function() {
  20047. })();
  20048. (function() {
  20049. /**
  20050. @module ember
  20051. @submodule ember-routing
  20052. */
  20053. var get = Ember.get, set = Ember.set;
  20054. var ControllersProxy = Ember.Object.extend({
  20055. controller: null,
  20056. unknownProperty: function(controllerName) {
  20057. var controller = get(this, 'controller'),
  20058. needs = get(controller, 'needs'),
  20059. container = controller.get('container'),
  20060. dependency;
  20061. for (var i=0, l=needs.length; i<l; i++) {
  20062. dependency = needs[i];
  20063. if (dependency === controllerName) {
  20064. return container.lookup('controller:' + controllerName);
  20065. }
  20066. }
  20067. }
  20068. });
  20069. function verifyDependencies(controller) {
  20070. var needs = get(controller, 'needs'),
  20071. container = get(controller, 'container'),
  20072. dependency, satisfied = true;
  20073. for (var i=0, l=needs.length; i<l; i++) {
  20074. dependency = needs[i];
  20075. if (dependency.indexOf(':') === -1) {
  20076. dependency = "controller:" + dependency;
  20077. }
  20078. if (!container.has(dependency)) {
  20079. satisfied = false;
  20080. Ember.assert(controller + " needs " + dependency + " but it does not exist", false);
  20081. }
  20082. }
  20083. return satisfied;
  20084. }
  20085. Ember.ControllerMixin.reopen({
  20086. concatenatedProperties: ['needs'],
  20087. needs: [],
  20088. init: function() {
  20089. this._super.apply(this, arguments);
  20090. // Structure asserts to still do verification but not string concat in production
  20091. if(!verifyDependencies(this)) {
  20092. Ember.assert("Missing dependencies", false);
  20093. }
  20094. },
  20095. controllerFor: function(controllerName) {
  20096. Ember.deprecate("Controller#controllerFor is depcrecated, please use Controller#needs instead");
  20097. var container = get(this, 'container');
  20098. return container.lookup('controller:' + controllerName);
  20099. },
  20100. controllers: Ember.computed(function() {
  20101. return ControllersProxy.create({ controller: this });
  20102. })
  20103. });
  20104. })();
  20105. (function() {
  20106. })();
  20107. (function() {
  20108. /**
  20109. Ember Application
  20110. @module ember
  20111. @submodule ember-application
  20112. @requires ember-views, ember-states, ember-routing
  20113. */
  20114. })();
  20115. (function() {
  20116. var get = Ember.get, set = Ember.set;
  20117. /**
  20118. @module ember
  20119. @submodule ember-states
  20120. */
  20121. /**
  20122. @class State
  20123. @namespace Ember
  20124. @extends Ember.Object
  20125. @uses Ember.Evented
  20126. */
  20127. Ember.State = Ember.Object.extend(Ember.Evented,
  20128. /** @scope Ember.State.prototype */{
  20129. isState: true,
  20130. /**
  20131. A reference to the parent state.
  20132. @property parentState
  20133. @type Ember.State
  20134. */
  20135. parentState: null,
  20136. start: null,
  20137. /**
  20138. The name of this state.
  20139. @property name
  20140. @type String
  20141. */
  20142. name: null,
  20143. /**
  20144. The full path to this state.
  20145. @property path
  20146. @type String
  20147. */
  20148. path: Ember.computed(function() {
  20149. var parentPath = get(this, 'parentState.path'),
  20150. path = get(this, 'name');
  20151. if (parentPath) {
  20152. path = parentPath + '.' + path;
  20153. }
  20154. return path;
  20155. }),
  20156. /**
  20157. @private
  20158. Override the default event firing from `Ember.Evented` to
  20159. also call methods with the given name.
  20160. @method trigger
  20161. @param name
  20162. */
  20163. trigger: function(name) {
  20164. if (this[name]) {
  20165. this[name].apply(this, [].slice.call(arguments, 1));
  20166. }
  20167. this._super.apply(this, arguments);
  20168. },
  20169. init: function() {
  20170. var states = get(this, 'states'), foundStates;
  20171. set(this, 'childStates', Ember.A());
  20172. set(this, 'eventTransitions', get(this, 'eventTransitions') || {});
  20173. var name, value, transitionTarget;
  20174. // As a convenience, loop over the properties
  20175. // of this state and look for any that are other
  20176. // Ember.State instances or classes, and move them
  20177. // to the `states` hash. This avoids having to
  20178. // create an explicit separate hash.
  20179. if (!states) {
  20180. states = {};
  20181. for (name in this) {
  20182. if (name === "constructor") { continue; }
  20183. if (value = this[name]) {
  20184. if (transitionTarget = value.transitionTarget) {
  20185. this.eventTransitions[name] = transitionTarget;
  20186. }
  20187. this.setupChild(states, name, value);
  20188. }
  20189. }
  20190. set(this, 'states', states);
  20191. } else {
  20192. for (name in states) {
  20193. this.setupChild(states, name, states[name]);
  20194. }
  20195. }
  20196. set(this, 'pathsCache', {});
  20197. set(this, 'pathsCacheNoContext', {});
  20198. },
  20199. setupChild: function(states, name, value) {
  20200. if (!value) { return false; }
  20201. if (value.isState) {
  20202. set(value, 'name', name);
  20203. } else if (Ember.State.detect(value)) {
  20204. value = value.create({
  20205. name: name
  20206. });
  20207. }
  20208. if (value.isState) {
  20209. set(value, 'parentState', this);
  20210. get(this, 'childStates').pushObject(value);
  20211. states[name] = value;
  20212. return value;
  20213. }
  20214. },
  20215. lookupEventTransition: function(name) {
  20216. var path, state = this;
  20217. while(state && !path) {
  20218. path = state.eventTransitions[name];
  20219. state = state.get('parentState');
  20220. }
  20221. return path;
  20222. },
  20223. /**
  20224. A Boolean value indicating whether the state is a leaf state
  20225. in the state hierarchy. This is `false` if the state has child
  20226. states; otherwise it is true.
  20227. @property isLeaf
  20228. @type Boolean
  20229. */
  20230. isLeaf: Ember.computed(function() {
  20231. return !get(this, 'childStates').length;
  20232. }),
  20233. /**
  20234. A boolean value indicating whether the state takes a context.
  20235. By default we assume all states take contexts.
  20236. @property hasContext
  20237. @default true
  20238. */
  20239. hasContext: true,
  20240. /**
  20241. This is the default transition event.
  20242. @event setup
  20243. @param {Ember.StateManager} manager
  20244. @param context
  20245. @see Ember.StateManager#transitionEvent
  20246. */
  20247. setup: Ember.K,
  20248. /**
  20249. This event fires when the state is entered.
  20250. @event enter
  20251. @param {Ember.StateManager} manager
  20252. */
  20253. enter: Ember.K,
  20254. /**
  20255. This event fires when the state is exited.
  20256. @event exit
  20257. @param {Ember.StateManager} manager
  20258. */
  20259. exit: Ember.K
  20260. });
  20261. Ember.State.reopenClass({
  20262. /**
  20263. Creates an action function for transitioning to the named state while
  20264. preserving context.
  20265. The following example StateManagers are equivalent:
  20266. ```javascript
  20267. aManager = Ember.StateManager.create({
  20268. stateOne: Ember.State.create({
  20269. changeToStateTwo: Ember.State.transitionTo('stateTwo')
  20270. }),
  20271. stateTwo: Ember.State.create({})
  20272. })
  20273. bManager = Ember.StateManager.create({
  20274. stateOne: Ember.State.create({
  20275. changeToStateTwo: function(manager, context){
  20276. manager.transitionTo('stateTwo', context)
  20277. }
  20278. }),
  20279. stateTwo: Ember.State.create({})
  20280. })
  20281. ```
  20282. @method transitionTo
  20283. @static
  20284. @param {String} target
  20285. */
  20286. transitionTo: function(target) {
  20287. var transitionFunction = function(stateManager, contextOrEvent) {
  20288. var contexts = [], transitionArgs,
  20289. Event = Ember.$ && Ember.$.Event;
  20290. if (contextOrEvent && (Event && contextOrEvent instanceof Event)) {
  20291. if (contextOrEvent.hasOwnProperty('contexts')) {
  20292. contexts = contextOrEvent.contexts.slice();
  20293. }
  20294. }
  20295. else {
  20296. contexts = [].slice.call(arguments, 1);
  20297. }
  20298. contexts.unshift(target);
  20299. stateManager.transitionTo.apply(stateManager, contexts);
  20300. };
  20301. transitionFunction.transitionTarget = target;
  20302. return transitionFunction;
  20303. }
  20304. });
  20305. })();
  20306. (function() {
  20307. /**
  20308. @module ember
  20309. @submodule ember-states
  20310. */
  20311. var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
  20312. var arrayForEach = Ember.ArrayPolyfills.forEach;
  20313. /**
  20314. A Transition takes the enter, exit and resolve states and normalizes
  20315. them:
  20316. * takes any passed in contexts into consideration
  20317. * adds in `initialState`s
  20318. @class Transition
  20319. @private
  20320. */
  20321. var Transition = function(raw) {
  20322. this.enterStates = raw.enterStates.slice();
  20323. this.exitStates = raw.exitStates.slice();
  20324. this.resolveState = raw.resolveState;
  20325. this.finalState = raw.enterStates[raw.enterStates.length - 1] || raw.resolveState;
  20326. };
  20327. Transition.prototype = {
  20328. /**
  20329. Normalize the passed in enter, exit and resolve states.
  20330. This process also adds `finalState` and `contexts` to the Transition object.
  20331. @method normalize
  20332. @param {Ember.StateManager} manager the state manager running the transition
  20333. @param {Array} contexts a list of contexts passed into `transitionTo`
  20334. */
  20335. normalize: function(manager, contexts) {
  20336. this.matchContextsToStates(contexts);
  20337. this.addInitialStates();
  20338. this.removeUnchangedContexts(manager);
  20339. return this;
  20340. },
  20341. /**
  20342. Match each of the contexts passed to `transitionTo` to a state.
  20343. This process may also require adding additional enter and exit
  20344. states if there are more contexts than enter states.
  20345. @method matchContextsToStates
  20346. @param {Array} contexts a list of contexts passed into `transitionTo`
  20347. */
  20348. matchContextsToStates: function(contexts) {
  20349. var stateIdx = this.enterStates.length - 1,
  20350. matchedContexts = [],
  20351. state,
  20352. context;
  20353. // Next, we will match the passed in contexts to the states they
  20354. // represent.
  20355. //
  20356. // First, assign a context to each enter state in reverse order. If
  20357. // any contexts are left, add a parent state to the list of states
  20358. // to enter and exit, and assign a context to the parent state.
  20359. //
  20360. // If there are still contexts left when the state manager is
  20361. // reached, raise an exception.
  20362. //
  20363. // This allows the following:
  20364. //
  20365. // |- root
  20366. // | |- post
  20367. // | | |- comments
  20368. // | |- about (* current state)
  20369. //
  20370. // For `transitionTo('post.comments', post, post.get('comments')`,
  20371. // the first context (`post`) will be assigned to `root.post`, and
  20372. // the second context (`post.get('comments')`) will be assigned
  20373. // to `root.post.comments`.
  20374. //
  20375. // For the following:
  20376. //
  20377. // |- root
  20378. // | |- post
  20379. // | | |- index (* current state)
  20380. // | | |- comments
  20381. //
  20382. // For `transitionTo('post.comments', otherPost, otherPost.get('comments')`,
  20383. // the `<root.post>` state will be added to the list of enter and exit
  20384. // states because its context has changed.
  20385. while (contexts.length > 0) {
  20386. if (stateIdx >= 0) {
  20387. state = this.enterStates[stateIdx--];
  20388. } else {
  20389. if (this.enterStates.length) {
  20390. state = get(this.enterStates[0], 'parentState');
  20391. if (!state) { throw "Cannot match all contexts to states"; }
  20392. } else {
  20393. // If re-entering the current state with a context, the resolve
  20394. // state will be the current state.
  20395. state = this.resolveState;
  20396. }
  20397. this.enterStates.unshift(state);
  20398. this.exitStates.unshift(state);
  20399. }
  20400. // in routers, only states with dynamic segments have a context
  20401. if (get(state, 'hasContext')) {
  20402. context = contexts.pop();
  20403. } else {
  20404. context = null;
  20405. }
  20406. matchedContexts.unshift(context);
  20407. }
  20408. this.contexts = matchedContexts;
  20409. },
  20410. /**
  20411. Add any `initialState`s to the list of enter states.
  20412. @method addInitialStates
  20413. */
  20414. addInitialStates: function() {
  20415. var finalState = this.finalState, initialState;
  20416. while(true) {
  20417. initialState = get(finalState, 'initialState') || 'start';
  20418. finalState = get(finalState, 'states.' + initialState);
  20419. if (!finalState) { break; }
  20420. this.finalState = finalState;
  20421. this.enterStates.push(finalState);
  20422. this.contexts.push(undefined);
  20423. }
  20424. },
  20425. /**
  20426. Remove any states that were added because the number of contexts
  20427. exceeded the number of explicit enter states, but the context has
  20428. not changed since the last time the state was entered.
  20429. @method removeUnchangedContexts
  20430. @param {Ember.StateManager} manager passed in to look up the last
  20431. context for a states
  20432. */
  20433. removeUnchangedContexts: function(manager) {
  20434. // Start from the beginning of the enter states. If the state was added
  20435. // to the list during the context matching phase, make sure the context
  20436. // has actually changed since the last time the state was entered.
  20437. while (this.enterStates.length > 0) {
  20438. if (this.enterStates[0] !== this.exitStates[0]) { break; }
  20439. if (this.enterStates.length === this.contexts.length) {
  20440. if (manager.getStateMeta(this.enterStates[0], 'context') !== this.contexts[0]) { break; }
  20441. this.contexts.shift();
  20442. }
  20443. this.resolveState = this.enterStates.shift();
  20444. this.exitStates.shift();
  20445. }
  20446. }
  20447. };
  20448. var sendRecursively = function(event, currentState, isUnhandledPass) {
  20449. var log = this.enableLogging,
  20450. eventName = isUnhandledPass ? 'unhandledEvent' : event,
  20451. action = currentState[eventName],
  20452. contexts, sendRecursiveArguments, actionArguments;
  20453. contexts = [].slice.call(arguments, 3);
  20454. // Test to see if the action is a method that
  20455. // can be invoked. Don't blindly check just for
  20456. // existence, because it is possible the state
  20457. // manager has a child state of the given name,
  20458. // and we should still raise an exception in that
  20459. // case.
  20460. if (typeof action === 'function') {
  20461. if (log) {
  20462. if (isUnhandledPass) {
  20463. Ember.Logger.log(fmt("STATEMANAGER: Unhandled event '%@' being sent to state %@.", [event, get(currentState, 'path')]));
  20464. } else {
  20465. Ember.Logger.log(fmt("STATEMANAGER: Sending event '%@' to state %@.", [event, get(currentState, 'path')]));
  20466. }
  20467. }
  20468. actionArguments = contexts;
  20469. if (isUnhandledPass) {
  20470. actionArguments.unshift(event);
  20471. }
  20472. actionArguments.unshift(this);
  20473. return action.apply(currentState, actionArguments);
  20474. } else {
  20475. var parentState = get(currentState, 'parentState');
  20476. if (parentState) {
  20477. sendRecursiveArguments = contexts;
  20478. sendRecursiveArguments.unshift(event, parentState, isUnhandledPass);
  20479. return sendRecursively.apply(this, sendRecursiveArguments);
  20480. } else if (!isUnhandledPass) {
  20481. return sendEvent.call(this, event, contexts, true);
  20482. }
  20483. }
  20484. };
  20485. var sendEvent = function(eventName, sendRecursiveArguments, isUnhandledPass) {
  20486. sendRecursiveArguments.unshift(eventName, get(this, 'currentState'), isUnhandledPass);
  20487. return sendRecursively.apply(this, sendRecursiveArguments);
  20488. };
  20489. /**
  20490. StateManager is part of Ember's implementation of a finite state machine. A
  20491. StateManager instance manages a number of properties that are instances of
  20492. `Ember.State`,
  20493. tracks the current active state, and triggers callbacks when states have changed.
  20494. ## Defining States
  20495. The states of StateManager can be declared in one of two ways. First, you can
  20496. define a `states` property that contains all the states:
  20497. ```javascript
  20498. managerA = Ember.StateManager.create({
  20499. states: {
  20500. stateOne: Ember.State.create(),
  20501. stateTwo: Ember.State.create()
  20502. }
  20503. })
  20504. managerA.get('states')
  20505. // {
  20506. // stateOne: Ember.State.create(),
  20507. // stateTwo: Ember.State.create()
  20508. // }
  20509. ```
  20510. You can also add instances of `Ember.State` (or an `Ember.State` subclass)
  20511. directly as properties of a StateManager. These states will be collected into
  20512. the `states` property for you.
  20513. ```javascript
  20514. managerA = Ember.StateManager.create({
  20515. stateOne: Ember.State.create(),
  20516. stateTwo: Ember.State.create()
  20517. })
  20518. managerA.get('states')
  20519. // {
  20520. // stateOne: Ember.State.create(),
  20521. // stateTwo: Ember.State.create()
  20522. // }
  20523. ```
  20524. ## The Initial State
  20525. When created a StateManager instance will immediately enter into the state
  20526. defined as its `start` property or the state referenced by name in its
  20527. `initialState` property:
  20528. ```javascript
  20529. managerA = Ember.StateManager.create({
  20530. start: Ember.State.create({})
  20531. })
  20532. managerA.get('currentState.name') // 'start'
  20533. managerB = Ember.StateManager.create({
  20534. initialState: 'beginHere',
  20535. beginHere: Ember.State.create({})
  20536. })
  20537. managerB.get('currentState.name') // 'beginHere'
  20538. ```
  20539. Because it is a property you may also provide a computed function if you wish
  20540. to derive an `initialState` programmatically:
  20541. ```javascript
  20542. managerC = Ember.StateManager.create({
  20543. initialState: function(){
  20544. if (someLogic) {
  20545. return 'active';
  20546. } else {
  20547. return 'passive';
  20548. }
  20549. }.property(),
  20550. active: Ember.State.create({}),
  20551. passive: Ember.State.create({})
  20552. })
  20553. ```
  20554. ## Moving Between States
  20555. A StateManager can have any number of `Ember.State` objects as properties
  20556. and can have a single one of these states as its current state.
  20557. Calling `transitionTo` transitions between states:
  20558. ```javascript
  20559. robotManager = Ember.StateManager.create({
  20560. initialState: 'poweredDown',
  20561. poweredDown: Ember.State.create({}),
  20562. poweredUp: Ember.State.create({})
  20563. })
  20564. robotManager.get('currentState.name') // 'poweredDown'
  20565. robotManager.transitionTo('poweredUp')
  20566. robotManager.get('currentState.name') // 'poweredUp'
  20567. ```
  20568. Before transitioning into a new state the existing `currentState` will have
  20569. its `exit` method called with the StateManager instance as its first argument
  20570. and an object representing the transition as its second argument.
  20571. After transitioning into a new state the new `currentState` will have its
  20572. `enter` method called with the StateManager instance as its first argument
  20573. and an object representing the transition as its second argument.
  20574. ```javascript
  20575. robotManager = Ember.StateManager.create({
  20576. initialState: 'poweredDown',
  20577. poweredDown: Ember.State.create({
  20578. exit: function(stateManager){
  20579. console.log("exiting the poweredDown state")
  20580. }
  20581. }),
  20582. poweredUp: Ember.State.create({
  20583. enter: function(stateManager){
  20584. console.log("entering the poweredUp state. Destroy all humans.")
  20585. }
  20586. })
  20587. })
  20588. robotManager.get('currentState.name') // 'poweredDown'
  20589. robotManager.transitionTo('poweredUp')
  20590. // will log
  20591. // 'exiting the poweredDown state'
  20592. // 'entering the poweredUp state. Destroy all humans.'
  20593. ```
  20594. Once a StateManager is already in a state, subsequent attempts to enter that
  20595. state will not trigger enter or exit method calls. Attempts to transition
  20596. into a state that the manager does not have will result in no changes in the
  20597. StateManager's current state:
  20598. ```javascript
  20599. robotManager = Ember.StateManager.create({
  20600. initialState: 'poweredDown',
  20601. poweredDown: Ember.State.create({
  20602. exit: function(stateManager){
  20603. console.log("exiting the poweredDown state")
  20604. }
  20605. }),
  20606. poweredUp: Ember.State.create({
  20607. enter: function(stateManager){
  20608. console.log("entering the poweredUp state. Destroy all humans.")
  20609. }
  20610. })
  20611. })
  20612. robotManager.get('currentState.name') // 'poweredDown'
  20613. robotManager.transitionTo('poweredUp')
  20614. // will log
  20615. // 'exiting the poweredDown state'
  20616. // 'entering the poweredUp state. Destroy all humans.'
  20617. robotManager.transitionTo('poweredUp') // no logging, no state change
  20618. robotManager.transitionTo('someUnknownState') // silently fails
  20619. robotManager.get('currentState.name') // 'poweredUp'
  20620. ```
  20621. Each state property may itself contain properties that are instances of
  20622. `Ember.State`. The StateManager can transition to specific sub-states in a
  20623. series of transitionTo method calls or via a single transitionTo with the
  20624. full path to the specific state. The StateManager will also keep track of the
  20625. full path to its currentState
  20626. ```javascript
  20627. robotManager = Ember.StateManager.create({
  20628. initialState: 'poweredDown',
  20629. poweredDown: Ember.State.create({
  20630. charging: Ember.State.create(),
  20631. charged: Ember.State.create()
  20632. }),
  20633. poweredUp: Ember.State.create({
  20634. mobile: Ember.State.create(),
  20635. stationary: Ember.State.create()
  20636. })
  20637. })
  20638. robotManager.get('currentState.name') // 'poweredDown'
  20639. robotManager.transitionTo('poweredUp')
  20640. robotManager.get('currentState.name') // 'poweredUp'
  20641. robotManager.transitionTo('mobile')
  20642. robotManager.get('currentState.name') // 'mobile'
  20643. // transition via a state path
  20644. robotManager.transitionTo('poweredDown.charging')
  20645. robotManager.get('currentState.name') // 'charging'
  20646. robotManager.get('currentState.path') // 'poweredDown.charging'
  20647. ```
  20648. Enter transition methods will be called for each state and nested child state
  20649. in their hierarchical order. Exit methods will be called for each state and
  20650. its nested states in reverse hierarchical order.
  20651. Exit transitions for a parent state are not called when entering into one of
  20652. its child states, only when transitioning to a new section of possible states
  20653. in the hierarchy.
  20654. ```javascript
  20655. robotManager = Ember.StateManager.create({
  20656. initialState: 'poweredDown',
  20657. poweredDown: Ember.State.create({
  20658. enter: function(){},
  20659. exit: function(){
  20660. console.log("exited poweredDown state")
  20661. },
  20662. charging: Ember.State.create({
  20663. enter: function(){},
  20664. exit: function(){}
  20665. }),
  20666. charged: Ember.State.create({
  20667. enter: function(){
  20668. console.log("entered charged state")
  20669. },
  20670. exit: function(){
  20671. console.log("exited charged state")
  20672. }
  20673. })
  20674. }),
  20675. poweredUp: Ember.State.create({
  20676. enter: function(){
  20677. console.log("entered poweredUp state")
  20678. },
  20679. exit: function(){},
  20680. mobile: Ember.State.create({
  20681. enter: function(){
  20682. console.log("entered mobile state")
  20683. },
  20684. exit: function(){}
  20685. }),
  20686. stationary: Ember.State.create({
  20687. enter: function(){},
  20688. exit: function(){}
  20689. })
  20690. })
  20691. })
  20692. robotManager.get('currentState.path') // 'poweredDown'
  20693. robotManager.transitionTo('charged')
  20694. // logs 'entered charged state'
  20695. // but does *not* log 'exited poweredDown state'
  20696. robotManager.get('currentState.name') // 'charged
  20697. robotManager.transitionTo('poweredUp.mobile')
  20698. // logs
  20699. // 'exited charged state'
  20700. // 'exited poweredDown state'
  20701. // 'entered poweredUp state'
  20702. // 'entered mobile state'
  20703. ```
  20704. During development you can set a StateManager's `enableLogging` property to
  20705. `true` to receive console messages of state transitions.
  20706. ```javascript
  20707. robotManager = Ember.StateManager.create({
  20708. enableLogging: true
  20709. })
  20710. ```
  20711. ## Managing currentState with Actions
  20712. To control which transitions are possible for a given state, and
  20713. appropriately handle external events, the StateManager can receive and
  20714. route action messages to its states via the `send` method. Calling to
  20715. `send` with an action name will begin searching for a method with the same
  20716. name starting at the current state and moving up through the parent states
  20717. in a state hierarchy until an appropriate method is found or the StateManager
  20718. instance itself is reached.
  20719. If an appropriately named method is found it will be called with the state
  20720. manager as the first argument and an optional `context` object as the second
  20721. argument.
  20722. ```javascript
  20723. managerA = Ember.StateManager.create({
  20724. initialState: 'stateOne.substateOne.subsubstateOne',
  20725. stateOne: Ember.State.create({
  20726. substateOne: Ember.State.create({
  20727. anAction: function(manager, context){
  20728. console.log("an action was called")
  20729. },
  20730. subsubstateOne: Ember.State.create({})
  20731. })
  20732. })
  20733. })
  20734. managerA.get('currentState.name') // 'subsubstateOne'
  20735. managerA.send('anAction')
  20736. // 'stateOne.substateOne.subsubstateOne' has no anAction method
  20737. // so the 'anAction' method of 'stateOne.substateOne' is called
  20738. // and logs "an action was called"
  20739. // with managerA as the first argument
  20740. // and no second argument
  20741. someObject = {}
  20742. managerA.send('anAction', someObject)
  20743. // the 'anAction' method of 'stateOne.substateOne' is called again
  20744. // with managerA as the first argument and
  20745. // someObject as the second argument.
  20746. ```
  20747. If the StateManager attempts to send an action but does not find an appropriately named
  20748. method in the current state or while moving upwards through the state hierarchy, it will
  20749. repeat the process looking for a `unhandledEvent` method. If an `unhandledEvent` method is
  20750. found, it will be called with the original event name as the second argument. If an
  20751. `unhandledEvent` method is not found, the StateManager will throw a new Ember.Error.
  20752. ```javascript
  20753. managerB = Ember.StateManager.create({
  20754. initialState: 'stateOne.substateOne.subsubstateOne',
  20755. stateOne: Ember.State.create({
  20756. substateOne: Ember.State.create({
  20757. subsubstateOne: Ember.State.create({}),
  20758. unhandledEvent: function(manager, eventName, context) {
  20759. console.log("got an unhandledEvent with name " + eventName);
  20760. }
  20761. })
  20762. })
  20763. })
  20764. managerB.get('currentState.name') // 'subsubstateOne'
  20765. managerB.send('anAction')
  20766. // neither `stateOne.substateOne.subsubstateOne` nor any of it's
  20767. // parent states have a handler for `anAction`. `subsubstateOne`
  20768. // also does not have a `unhandledEvent` method, but its parent
  20769. // state, `substateOne`, does, and it gets fired. It will log
  20770. // "got an unhandledEvent with name anAction"
  20771. ```
  20772. Action detection only moves upwards through the state hierarchy from the current state.
  20773. It does not search in other portions of the hierarchy.
  20774. ```javascript
  20775. managerC = Ember.StateManager.create({
  20776. initialState: 'stateOne.substateOne.subsubstateOne',
  20777. stateOne: Ember.State.create({
  20778. substateOne: Ember.State.create({
  20779. subsubstateOne: Ember.State.create({})
  20780. })
  20781. }),
  20782. stateTwo: Ember.State.create({
  20783. anAction: function(manager, context){
  20784. // will not be called below because it is
  20785. // not a parent of the current state
  20786. }
  20787. })
  20788. })
  20789. managerC.get('currentState.name') // 'subsubstateOne'
  20790. managerC.send('anAction')
  20791. // Error: <Ember.StateManager:ember132> could not
  20792. // respond to event anAction in state stateOne.substateOne.subsubstateOne.
  20793. ```
  20794. Inside of an action method the given state should delegate `transitionTo` calls on its
  20795. StateManager.
  20796. ```javascript
  20797. robotManager = Ember.StateManager.create({
  20798. initialState: 'poweredDown.charging',
  20799. poweredDown: Ember.State.create({
  20800. charging: Ember.State.create({
  20801. chargeComplete: function(manager, context){
  20802. manager.transitionTo('charged')
  20803. }
  20804. }),
  20805. charged: Ember.State.create({
  20806. boot: function(manager, context){
  20807. manager.transitionTo('poweredUp')
  20808. }
  20809. })
  20810. }),
  20811. poweredUp: Ember.State.create({
  20812. beginExtermination: function(manager, context){
  20813. manager.transitionTo('rampaging')
  20814. },
  20815. rampaging: Ember.State.create()
  20816. })
  20817. })
  20818. robotManager.get('currentState.name') // 'charging'
  20819. robotManager.send('boot') // throws error, no boot action
  20820. // in current hierarchy
  20821. robotManager.get('currentState.name') // remains 'charging'
  20822. robotManager.send('beginExtermination') // throws error, no beginExtermination
  20823. // action in current hierarchy
  20824. robotManager.get('currentState.name') // remains 'charging'
  20825. robotManager.send('chargeComplete')
  20826. robotManager.get('currentState.name') // 'charged'
  20827. robotManager.send('boot')
  20828. robotManager.get('currentState.name') // 'poweredUp'
  20829. robotManager.send('beginExtermination', allHumans)
  20830. robotManager.get('currentState.name') // 'rampaging'
  20831. ```
  20832. Transition actions can also be created using the `transitionTo` method of the `Ember.State` class. The
  20833. following example StateManagers are equivalent:
  20834. ```javascript
  20835. aManager = Ember.StateManager.create({
  20836. stateOne: Ember.State.create({
  20837. changeToStateTwo: Ember.State.transitionTo('stateTwo')
  20838. }),
  20839. stateTwo: Ember.State.create({})
  20840. })
  20841. bManager = Ember.StateManager.create({
  20842. stateOne: Ember.State.create({
  20843. changeToStateTwo: function(manager, context){
  20844. manager.transitionTo('stateTwo', context)
  20845. }
  20846. }),
  20847. stateTwo: Ember.State.create({})
  20848. })
  20849. ```
  20850. @class StateManager
  20851. @namespace Ember
  20852. @extends Ember.State
  20853. **/
  20854. Ember.StateManager = Ember.State.extend({
  20855. /**
  20856. @private
  20857. When creating a new statemanager, look for a default state to transition
  20858. into. This state can either be named `start`, or can be specified using the
  20859. `initialState` property.
  20860. @method init
  20861. */
  20862. init: function() {
  20863. this._super();
  20864. set(this, 'stateMeta', Ember.Map.create());
  20865. var initialState = get(this, 'initialState');
  20866. if (!initialState && get(this, 'states.start')) {
  20867. initialState = 'start';
  20868. }
  20869. if (initialState) {
  20870. this.transitionTo(initialState);
  20871. Ember.assert('Failed to transition to initial state "' + initialState + '"', !!get(this, 'currentState'));
  20872. }
  20873. },
  20874. stateMetaFor: function(state) {
  20875. var meta = get(this, 'stateMeta'),
  20876. stateMeta = meta.get(state);
  20877. if (!stateMeta) {
  20878. stateMeta = {};
  20879. meta.set(state, stateMeta);
  20880. }
  20881. return stateMeta;
  20882. },
  20883. setStateMeta: function(state, key, value) {
  20884. return set(this.stateMetaFor(state), key, value);
  20885. },
  20886. getStateMeta: function(state, key) {
  20887. return get(this.stateMetaFor(state), key);
  20888. },
  20889. /**
  20890. The current state from among the manager's possible states. This property should
  20891. not be set directly. Use `transitionTo` to move between states by name.
  20892. @property currentState
  20893. @type Ember.State
  20894. */
  20895. currentState: null,
  20896. /**
  20897. The path of the current state. Returns a string representation of the current
  20898. state.
  20899. @property currentPath
  20900. @type String
  20901. */
  20902. currentPath: Ember.computed.alias('currentState.path'),
  20903. /**
  20904. The name of transitionEvent that this stateManager will dispatch
  20905. @property transitionEvent
  20906. @type String
  20907. @default 'setup'
  20908. */
  20909. transitionEvent: 'setup',
  20910. /**
  20911. If set to true, `errorOnUnhandledEvents` will cause an exception to be
  20912. raised if you attempt to send an event to a state manager that is not
  20913. handled by the current state or any of its parent states.
  20914. @property errorOnUnhandledEvents
  20915. @type Boolean
  20916. @default true
  20917. */
  20918. errorOnUnhandledEvent: true,
  20919. send: function(event) {
  20920. var contexts = [].slice.call(arguments, 1);
  20921. Ember.assert('Cannot send event "' + event + '" while currentState is ' + get(this, 'currentState'), get(this, 'currentState'));
  20922. return sendEvent.call(this, event, contexts, false);
  20923. },
  20924. unhandledEvent: function(manager, event) {
  20925. if (get(this, 'errorOnUnhandledEvent')) {
  20926. throw new Ember.Error(this.toString() + " could not respond to event " + event + " in state " + get(this, 'currentState.path') + ".");
  20927. }
  20928. },
  20929. /**
  20930. Finds a state by its state path.
  20931. Example:
  20932. ```javascript
  20933. manager = Ember.StateManager.create({
  20934. root: Ember.State.create({
  20935. dashboard: Ember.State.create()
  20936. })
  20937. });
  20938. manager.getStateByPath(manager, "root.dashboard")
  20939. // returns the dashboard state
  20940. ```
  20941. @method getStateByPath
  20942. @param {Ember.State} root the state to start searching from
  20943. @param {String} path the state path to follow
  20944. @return {Ember.State} the state at the end of the path
  20945. */
  20946. getStateByPath: function(root, path) {
  20947. var parts = path.split('.'),
  20948. state = root;
  20949. for (var i=0, len=parts.length; i<len; i++) {
  20950. state = get(get(state, 'states'), parts[i]);
  20951. if (!state) { break; }
  20952. }
  20953. return state;
  20954. },
  20955. findStateByPath: function(state, path) {
  20956. var possible;
  20957. while (!possible && state) {
  20958. possible = this.getStateByPath(state, path);
  20959. state = get(state, 'parentState');
  20960. }
  20961. return possible;
  20962. },
  20963. /**
  20964. A state stores its child states in its `states` hash.
  20965. This code takes a path like `posts.show` and looks
  20966. up `root.states.posts.states.show`.
  20967. It returns a list of all of the states from the
  20968. root, which is the list of states to call `enter`
  20969. on.
  20970. @method getStatesInPath
  20971. @param root
  20972. @param path
  20973. */
  20974. getStatesInPath: function(root, path) {
  20975. if (!path || path === "") { return undefined; }
  20976. var parts = path.split('.'),
  20977. result = [],
  20978. states,
  20979. state;
  20980. for (var i=0, len=parts.length; i<len; i++) {
  20981. states = get(root, 'states');
  20982. if (!states) { return undefined; }
  20983. state = get(states, parts[i]);
  20984. if (state) { root = state; result.push(state); }
  20985. else { return undefined; }
  20986. }
  20987. return result;
  20988. },
  20989. goToState: function() {
  20990. // not deprecating this yet so people don't constantly need to
  20991. // make trivial changes for little reason.
  20992. return this.transitionTo.apply(this, arguments);
  20993. },
  20994. transitionTo: function(path, context) {
  20995. // XXX When is transitionTo called with no path
  20996. if (Ember.isEmpty(path)) { return; }
  20997. // The ES6 signature of this function is `path, ...contexts`
  20998. var contexts = context ? Array.prototype.slice.call(arguments, 1) : [],
  20999. currentState = get(this, 'currentState') || this;
  21000. // First, get the enter, exit and resolve states for the current state
  21001. // and specified path. If possible, use an existing cache.
  21002. var hash = this.contextFreeTransition(currentState, path);
  21003. // Next, process the raw state information for the contexts passed in.
  21004. var transition = new Transition(hash).normalize(this, contexts);
  21005. this.enterState(transition);
  21006. this.triggerSetupContext(transition);
  21007. },
  21008. contextFreeTransition: function(currentState, path) {
  21009. var cache = currentState.pathsCache[path];
  21010. if (cache) { return cache; }
  21011. var enterStates = this.getStatesInPath(currentState, path),
  21012. exitStates = [],
  21013. resolveState = currentState;
  21014. // Walk up the states. For each state, check whether a state matching
  21015. // the `path` is nested underneath. This will find the closest
  21016. // parent state containing `path`.
  21017. //
  21018. // This allows the user to pass in a relative path. For example, for
  21019. // the following state hierarchy:
  21020. //
  21021. // | |root
  21022. // | |- posts
  21023. // | | |- show (* current)
  21024. // | |- comments
  21025. // | | |- show
  21026. //
  21027. // If the current state is `<root.posts.show>`, an attempt to
  21028. // transition to `comments.show` will match `<root.comments.show>`.
  21029. //
  21030. // First, this code will look for root.posts.show.comments.show.
  21031. // Next, it will look for root.posts.comments.show. Finally,
  21032. // it will look for `root.comments.show`, and find the state.
  21033. //
  21034. // After this process, the following variables will exist:
  21035. //
  21036. // * resolveState: a common parent state between the current
  21037. // and target state. In the above example, `<root>` is the
  21038. // `resolveState`.
  21039. // * enterStates: a list of all of the states represented
  21040. // by the path from the `resolveState`. For example, for
  21041. // the path `root.comments.show`, `enterStates` would have
  21042. // `[<root.comments>, <root.comments.show>]`
  21043. // * exitStates: a list of all of the states from the
  21044. // `resolveState` to the `currentState`. In the above
  21045. // example, `exitStates` would have
  21046. // `[<root.posts>`, `<root.posts.show>]`.
  21047. while (resolveState && !enterStates) {
  21048. exitStates.unshift(resolveState);
  21049. resolveState = get(resolveState, 'parentState');
  21050. if (!resolveState) {
  21051. enterStates = this.getStatesInPath(this, path);
  21052. if (!enterStates) {
  21053. Ember.assert('Could not find state for path: "'+path+'"');
  21054. return;
  21055. }
  21056. }
  21057. enterStates = this.getStatesInPath(resolveState, path);
  21058. }
  21059. // If the path contains some states that are parents of both the
  21060. // current state and the target state, remove them.
  21061. //
  21062. // For example, in the following hierarchy:
  21063. //
  21064. // |- root
  21065. // | |- post
  21066. // | | |- index (* current)
  21067. // | | |- show
  21068. //
  21069. // If the `path` is `root.post.show`, the three variables will
  21070. // be:
  21071. //
  21072. // * resolveState: `<state manager>`
  21073. // * enterStates: `[<root>, <root.post>, <root.post.show>]`
  21074. // * exitStates: `[<root>, <root.post>, <root.post.index>]`
  21075. //
  21076. // The goal of this code is to remove the common states, so we
  21077. // have:
  21078. //
  21079. // * resolveState: `<root.post>`
  21080. // * enterStates: `[<root.post.show>]`
  21081. // * exitStates: `[<root.post.index>]`
  21082. //
  21083. // This avoid unnecessary calls to the enter and exit transitions.
  21084. while (enterStates.length > 0 && enterStates[0] === exitStates[0]) {
  21085. resolveState = enterStates.shift();
  21086. exitStates.shift();
  21087. }
  21088. // Cache the enterStates, exitStates, and resolveState for the
  21089. // current state and the `path`.
  21090. var transitions = currentState.pathsCache[path] = {
  21091. exitStates: exitStates,
  21092. enterStates: enterStates,
  21093. resolveState: resolveState
  21094. };
  21095. return transitions;
  21096. },
  21097. triggerSetupContext: function(transitions) {
  21098. var contexts = transitions.contexts,
  21099. offset = transitions.enterStates.length - contexts.length,
  21100. enterStates = transitions.enterStates,
  21101. transitionEvent = get(this, 'transitionEvent');
  21102. Ember.assert("More contexts provided than states", offset >= 0);
  21103. arrayForEach.call(enterStates, function(state, idx) {
  21104. state.trigger(transitionEvent, this, contexts[idx-offset]);
  21105. }, this);
  21106. },
  21107. getState: function(name) {
  21108. var state = get(this, name),
  21109. parentState = get(this, 'parentState');
  21110. if (state) {
  21111. return state;
  21112. } else if (parentState) {
  21113. return parentState.getState(name);
  21114. }
  21115. },
  21116. enterState: function(transition) {
  21117. var log = this.enableLogging;
  21118. var exitStates = transition.exitStates.slice(0).reverse();
  21119. arrayForEach.call(exitStates, function(state) {
  21120. state.trigger('exit', this);
  21121. }, this);
  21122. arrayForEach.call(transition.enterStates, function(state) {
  21123. if (log) { Ember.Logger.log("STATEMANAGER: Entering " + get(state, 'path')); }
  21124. state.trigger('enter', this);
  21125. }, this);
  21126. set(this, 'currentState', transition.finalState);
  21127. }
  21128. });
  21129. })();
  21130. (function() {
  21131. /**
  21132. Ember States
  21133. @module ember
  21134. @submodule ember-states
  21135. @requires ember-runtime
  21136. */
  21137. })();
  21138. })();
  21139. // Version: v1.0.0-rc.1
  21140. // Last commit: 8b061b4 (2013-02-15 12:10:22 -0800)
  21141. (function() {
  21142. /**
  21143. Ember
  21144. @module ember
  21145. */
  21146. })();