ember.js 1.1 MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775307763077730778307793078030781307823078330784307853078630787307883078930790307913079230793307943079530796307973079830799308003080130802308033080430805308063080730808308093081030811308123081330814308153081630817308183081930820308213082230823308243082530826308273082830829308303083130832308333083430835308363083730838308393084030841308423084330844308453084630847308483084930850308513085230853308543085530856308573085830859308603086130862308633086430865308663086730868308693087030871308723087330874308753087630877308783087930880308813088230883308843088530886308873088830889308903089130892308933089430895308963089730898308993090030901309023090330904309053090630907309083090930910309113091230913309143091530916309173091830919309203092130922309233092430925309263092730928309293093030931309323093330934309353093630937309383093930940309413094230943309443094530946309473094830949309503095130952309533095430955309563095730958309593096030961309623096330964309653096630967309683096930970309713097230973309743097530976309773097830979309803098130982309833098430985309863098730988309893099030991309923099330994309953099630997309983099931000310013100231003310043100531006310073100831009310103101131012310133101431015310163101731018310193102031021310223102331024310253102631027310283102931030310313103231033310343103531036310373103831039310403104131042310433104431045310463104731048310493105031051310523105331054310553105631057310583105931060310613106231063310643106531066310673106831069310703107131072310733107431075310763107731078310793108031081310823108331084310853108631087310883108931090310913109231093310943109531096310973109831099311003110131102311033110431105311063110731108311093111031111311123111331114311153111631117311183111931120311213112231123311243112531126311273112831129311303113131132311333113431135311363113731138311393114031141311423114331144311453114631147311483114931150311513115231153311543115531156311573115831159311603116131162311633116431165311663116731168311693117031171311723117331174311753117631177311783117931180311813118231183311843118531186311873118831189311903119131192311933119431195311963119731198311993120031201312023120331204312053120631207312083120931210312113121231213312143121531216312173121831219312203122131222312233122431225312263122731228312293123031231312323123331234312353123631237312383123931240312413124231243312443124531246312473124831249312503125131252312533125431255312563125731258312593126031261312623126331264312653126631267312683126931270312713127231273312743127531276312773127831279312803128131282312833128431285312863128731288312893129031291312923129331294312953129631297312983129931300313013130231303313043130531306313073130831309313103131131312313133131431315313163131731318313193132031321313223132331324313253132631327313283132931330313313133231333313343133531336313373133831339313403134131342313433134431345313463134731348313493135031351313523135331354313553135631357313583135931360313613136231363313643136531366313673136831369313703137131372313733137431375313763137731378313793138031381313823138331384313853138631387313883138931390313913139231393313943139531396313973139831399314003140131402314033140431405314063140731408314093141031411314123141331414314153141631417314183141931420314213142231423314243142531426314273142831429314303143131432314333143431435314363143731438314393144031441314423144331444314453144631447314483144931450314513145231453314543145531456314573145831459314603146131462314633146431465314663146731468314693147031471314723147331474314753147631477314783147931480314813148231483314843148531486314873148831489314903149131492314933149431495314963149731498314993150031501315023150331504315053150631507315083150931510315113151231513315143151531516315173151831519315203152131522315233152431525315263152731528315293153031531315323153331534315353153631537315383153931540315413154231543315443154531546315473154831549315503155131552315533155431555315563155731558315593156031561315623156331564315653156631567315683156931570315713157231573315743157531576315773157831579315803158131582315833158431585315863158731588315893159031591315923159331594315953159631597315983159931600316013160231603316043160531606316073160831609316103161131612316133161431615316163161731618316193162031621316223162331624316253162631627316283162931630316313163231633316343163531636316373163831639316403164131642316433164431645316463164731648316493165031651316523165331654316553165631657316583165931660316613166231663316643166531666316673166831669316703167131672316733167431675316763167731678316793168031681316823168331684316853168631687316883168931690316913169231693316943169531696316973169831699317003170131702317033170431705317063170731708317093171031711317123171331714317153171631717317183171931720317213172231723317243172531726317273172831729317303173131732317333173431735317363173731738317393174031741317423174331744317453174631747317483174931750317513175231753317543175531756317573175831759317603176131762317633176431765317663176731768317693177031771317723177331774317753177631777317783177931780317813178231783317843178531786317873178831789317903179131792317933179431795317963179731798317993180031801318023180331804318053180631807318083180931810318113181231813318143181531816318173181831819318203182131822318233182431825318263182731828318293183031831318323183331834318353183631837318383183931840318413184231843318443184531846318473184831849318503185131852318533185431855318563185731858318593186031861318623186331864318653186631867318683186931870318713187231873318743187531876318773187831879318803188131882318833188431885318863188731888318893189031891318923189331894318953189631897318983189931900319013190231903319043190531906319073190831909319103191131912319133191431915319163191731918319193192031921319223192331924319253192631927319283192931930319313193231933319343193531936319373193831939319403194131942319433194431945319463194731948319493195031951319523195331954319553195631957319583195931960319613196231963319643196531966319673196831969319703197131972319733197431975319763197731978319793198031981319823198331984319853198631987319883198931990319913199231993319943199531996319973199831999320003200132002320033200432005320063200732008320093201032011320123201332014320153201632017320183201932020320213202232023320243202532026320273202832029320303203132032320333203432035320363203732038320393204032041320423204332044320453204632047320483204932050320513205232053320543205532056320573205832059320603206132062320633206432065320663206732068320693207032071320723207332074320753207632077320783207932080320813208232083320843208532086320873208832089320903209132092320933209432095320963209732098320993210032101321023210332104321053210632107321083210932110321113211232113321143211532116321173211832119321203212132122321233212432125321263212732128321293213032131321323213332134321353213632137321383213932140321413214232143321443214532146321473214832149321503215132152321533215432155321563215732158321593216032161321623216332164321653216632167321683216932170321713217232173321743217532176321773217832179321803218132182321833218432185321863218732188321893219032191321923219332194321953219632197321983219932200322013220232203322043220532206322073220832209322103221132212322133221432215322163221732218322193222032221322223222332224322253222632227322283222932230322313223232233322343223532236322373223832239322403224132242322433224432245322463224732248322493225032251322523225332254322553225632257322583225932260322613226232263322643226532266322673226832269322703227132272322733227432275322763227732278322793228032281322823228332284322853228632287322883228932290322913229232293322943229532296322973229832299323003230132302323033230432305323063230732308323093231032311323123231332314323153231632317323183231932320323213232232323323243232532326323273232832329323303233132332323333233432335323363233732338323393234032341323423234332344323453234632347323483234932350323513235232353323543235532356323573235832359323603236132362323633236432365323663236732368323693237032371323723237332374323753237632377323783237932380323813238232383323843238532386323873238832389323903239132392323933239432395323963239732398323993240032401324023240332404324053240632407324083240932410324113241232413324143241532416324173241832419324203242132422324233242432425324263242732428324293243032431324323243332434324353243632437324383243932440324413244232443324443244532446324473244832449324503245132452324533245432455324563245732458324593246032461324623246332464324653246632467324683246932470324713247232473324743247532476324773247832479324803248132482324833248432485324863248732488324893249032491324923249332494324953249632497324983249932500325013250232503325043250532506325073250832509325103251132512325133251432515325163251732518325193252032521325223252332524325253252632527325283252932530325313253232533325343253532536325373253832539325403254132542325433254432545325463254732548325493255032551325523255332554325553255632557325583255932560325613256232563325643256532566325673256832569325703257132572325733257432575325763257732578325793258032581325823258332584325853258632587325883258932590325913259232593325943259532596325973259832599326003260132602326033260432605326063260732608326093261032611326123261332614326153261632617326183261932620326213262232623326243262532626326273262832629326303263132632326333263432635326363263732638326393264032641326423264332644326453264632647326483264932650326513265232653326543265532656326573265832659326603266132662326633266432665326663266732668326693267032671326723267332674326753267632677326783267932680326813268232683326843268532686326873268832689326903269132692326933269432695326963269732698326993270032701327023270332704327053270632707327083270932710327113271232713327143271532716327173271832719327203272132722327233272432725327263272732728327293273032731327323273332734327353273632737327383273932740327413274232743327443274532746327473274832749327503275132752327533275432755327563275732758327593276032761327623276332764327653276632767327683276932770327713277232773327743277532776327773277832779327803278132782327833278432785327863278732788327893279032791327923279332794327953279632797327983279932800328013280232803328043280532806328073280832809328103281132812328133281432815328163281732818328193282032821328223282332824328253282632827328283282932830328313283232833328343283532836328373283832839328403284132842328433284432845328463284732848328493285032851328523285332854328553285632857328583285932860328613286232863328643286532866328673286832869328703287132872328733287432875328763287732878328793288032881328823288332884328853288632887328883288932890328913289232893328943289532896328973289832899329003290132902329033290432905329063290732908329093291032911329123291332914329153291632917329183291932920329213292232923329243292532926329273292832929329303293132932329333293432935329363293732938329393294032941329423294332944329453294632947329483294932950329513295232953329543295532956329573295832959329603296132962329633296432965329663296732968329693297032971329723297332974329753297632977329783297932980329813298232983329843298532986329873298832989329903299132992329933299432995329963299732998329993300033001330023300333004330053300633007330083300933010330113301233013330143301533016330173301833019330203302133022330233302433025330263302733028330293303033031330323303333034330353303633037330383303933040330413304233043330443304533046330473304833049330503305133052330533305433055330563305733058330593306033061330623306333064330653306633067330683306933070330713307233073330743307533076330773307833079330803308133082330833308433085330863308733088330893309033091330923309333094330953309633097330983309933100331013310233103331043310533106331073310833109331103311133112331133311433115331163311733118331193312033121331223312333124331253312633127331283312933130331313313233133331343313533136331373313833139331403314133142331433314433145331463314733148331493315033151331523315333154331553315633157331583315933160331613316233163331643316533166331673316833169331703317133172331733317433175331763317733178331793318033181331823318333184331853318633187331883318933190331913319233193331943319533196331973319833199332003320133202332033320433205332063320733208332093321033211332123321333214332153321633217332183321933220332213322233223332243322533226332273322833229332303323133232332333323433235332363323733238332393324033241332423324333244332453324633247332483324933250332513325233253332543325533256332573325833259332603326133262332633326433265332663326733268332693327033271332723327333274332753327633277332783327933280332813328233283332843328533286332873328833289332903329133292332933329433295332963329733298332993330033301333023330333304333053330633307333083330933310333113331233313333143331533316333173331833319333203332133322333233332433325333263332733328333293333033331333323333333334333353333633337333383333933340333413334233343333443334533346333473334833349333503335133352333533335433355333563335733358333593336033361333623336333364333653336633367333683336933370333713337233373333743337533376333773337833379333803338133382333833338433385333863338733388333893339033391333923339333394333953339633397333983339933400334013340233403334043340533406334073340833409334103341133412334133341433415334163341733418334193342033421334223342333424334253342633427334283342933430334313343233433334343343533436334373343833439334403344133442334433344433445334463344733448334493345033451334523345333454334553345633457334583345933460334613346233463334643346533466334673346833469334703347133472334733347433475334763347733478334793348033481334823348333484334853348633487334883348933490334913349233493334943349533496334973349833499335003350133502335033350433505335063350733508335093351033511335123351333514335153351633517335183351933520335213352233523335243352533526335273352833529335303353133532335333353433535335363353733538335393354033541335423354333544335453354633547335483354933550335513355233553335543355533556335573355833559335603356133562335633356433565335663356733568335693357033571335723357333574335753357633577335783357933580335813358233583335843358533586335873358833589335903359133592335933359433595335963359733598335993360033601336023360333604336053360633607336083360933610336113361233613336143361533616336173361833619336203362133622336233362433625336263362733628336293363033631336323363333634336353363633637336383363933640336413364233643336443364533646336473364833649336503365133652336533365433655336563365733658336593366033661336623366333664336653366633667336683366933670336713367233673336743367533676336773367833679336803368133682336833368433685336863368733688336893369033691336923369333694336953369633697336983369933700337013370233703337043370533706337073370833709337103371133712337133371433715337163371733718337193372033721337223372333724337253372633727337283372933730337313373233733337343373533736337373373833739337403374133742337433374433745337463374733748337493375033751337523375333754337553375633757337583375933760337613376233763337643376533766337673376833769337703377133772337733377433775337763377733778337793378033781337823378333784337853378633787337883378933790337913379233793337943379533796337973379833799338003380133802338033380433805338063380733808338093381033811338123381333814338153381633817338183381933820338213382233823338243382533826338273382833829338303383133832338333383433835338363383733838338393384033841338423384333844338453384633847338483384933850338513385233853338543385533856338573385833859338603386133862338633386433865338663386733868338693387033871338723387333874338753387633877338783387933880338813388233883338843388533886338873388833889338903389133892338933389433895338963389733898338993390033901339023390333904339053390633907339083390933910339113391233913339143391533916339173391833919339203392133922339233392433925339263392733928339293393033931339323393333934339353393633937339383393933940339413394233943339443394533946339473394833949339503395133952339533395433955339563395733958339593396033961339623396333964339653396633967339683396933970339713397233973339743397533976339773397833979339803398133982339833398433985339863398733988339893399033991339923399333994339953399633997339983399934000340013400234003340043400534006340073400834009340103401134012340133401434015340163401734018340193402034021340223402334024340253402634027340283402934030340313403234033340343403534036340373403834039340403404134042340433404434045340463404734048340493405034051340523405334054340553405634057340583405934060340613406234063340643406534066340673406834069340703407134072340733407434075340763407734078340793408034081340823408334084340853408634087340883408934090340913409234093340943409534096340973409834099341003410134102341033410434105341063410734108341093411034111341123411334114341153411634117341183411934120341213412234123341243412534126341273412834129341303413134132341333413434135341363413734138341393414034141341423414334144341453414634147341483414934150341513415234153341543415534156341573415834159341603416134162341633416434165341663416734168341693417034171341723417334174341753417634177341783417934180341813418234183341843418534186341873418834189341903419134192341933419434195341963419734198341993420034201342023420334204342053420634207342083420934210342113421234213342143421534216342173421834219342203422134222342233422434225342263422734228342293423034231342323423334234342353423634237342383423934240342413424234243342443424534246342473424834249342503425134252342533425434255342563425734258342593426034261342623426334264342653426634267342683426934270342713427234273342743427534276342773427834279342803428134282342833428434285342863428734288342893429034291342923429334294342953429634297342983429934300343013430234303343043430534306343073430834309343103431134312343133431434315343163431734318343193432034321343223432334324343253432634327343283432934330343313433234333343343433534336343373433834339343403434134342343433434434345343463434734348343493435034351343523435334354343553435634357343583435934360343613436234363343643436534366343673436834369343703437134372343733437434375343763437734378343793438034381343823438334384343853438634387343883438934390343913439234393343943439534396343973439834399344003440134402344033440434405344063440734408344093441034411344123441334414344153441634417344183441934420344213442234423344243442534426344273442834429344303443134432344333443434435344363443734438344393444034441344423444334444344453444634447344483444934450344513445234453344543445534456344573445834459344603446134462344633446434465344663446734468344693447034471344723447334474344753447634477344783447934480344813448234483344843448534486344873448834489344903449134492344933449434495344963449734498344993450034501345023450334504345053450634507345083450934510345113451234513345143451534516345173451834519345203452134522345233452434525345263452734528345293453034531345323453334534345353453634537345383453934540345413454234543345443454534546345473454834549345503455134552345533455434555345563455734558345593456034561345623456334564345653456634567345683456934570345713457234573345743457534576345773457834579345803458134582345833458434585345863458734588345893459034591345923459334594345953459634597345983459934600346013460234603346043460534606346073460834609346103461134612346133461434615346163461734618346193462034621346223462334624346253462634627346283462934630346313463234633346343463534636346373463834639346403464134642346433464434645346463464734648346493465034651346523465334654346553465634657346583465934660346613466234663346643466534666346673466834669346703467134672346733467434675346763467734678346793468034681346823468334684346853468634687346883468934690346913469234693346943469534696346973469834699347003470134702347033470434705347063470734708347093471034711347123471334714347153471634717347183471934720347213472234723347243472534726347273472834729347303473134732347333473434735347363473734738347393474034741347423474334744347453474634747347483474934750347513475234753347543475534756347573475834759347603476134762347633476434765347663476734768347693477034771347723477334774347753477634777347783477934780347813478234783347843478534786347873478834789347903479134792347933479434795347963479734798347993480034801348023480334804348053480634807348083480934810348113481234813348143481534816348173481834819348203482134822348233482434825348263482734828348293483034831348323483334834348353483634837348383483934840348413484234843348443484534846348473484834849348503485134852348533485434855348563485734858348593486034861348623486334864348653486634867348683486934870348713487234873348743487534876348773487834879348803488134882348833488434885348863488734888348893489034891348923489334894348953489634897348983489934900349013490234903349043490534906349073490834909349103491134912349133491434915349163491734918349193492034921349223492334924349253492634927349283492934930349313493234933349343493534936349373493834939349403494134942349433494434945349463494734948349493495034951349523495334954349553495634957349583495934960349613496234963349643496534966349673496834969349703497134972349733497434975349763497734978349793498034981349823498334984349853498634987349883498934990349913499234993349943499534996349973499834999350003500135002350033500435005350063500735008350093501035011350123501335014350153501635017350183501935020350213502235023350243502535026350273502835029350303503135032350333503435035350363503735038350393504035041350423504335044350453504635047350483504935050350513505235053350543505535056350573505835059350603506135062350633506435065350663506735068350693507035071350723507335074350753507635077350783507935080350813508235083350843508535086350873508835089350903509135092350933509435095350963509735098350993510035101351023510335104351053510635107351083510935110351113511235113351143511535116351173511835119351203512135122351233512435125351263512735128351293513035131351323513335134351353513635137351383513935140351413514235143351443514535146351473514835149351503515135152351533515435155351563515735158351593516035161351623516335164351653516635167351683516935170351713517235173351743517535176351773517835179351803518135182351833518435185351863518735188351893519035191351923519335194351953519635197351983519935200352013520235203352043520535206352073520835209352103521135212352133521435215352163521735218352193522035221352223522335224352253522635227352283522935230352313523235233352343523535236352373523835239352403524135242352433524435245352463524735248352493525035251352523525335254352553525635257352583525935260352613526235263352643526535266352673526835269352703527135272352733527435275352763527735278352793528035281352823528335284352853528635287352883528935290352913529235293352943529535296352973529835299353003530135302353033530435305353063530735308353093531035311353123531335314353153531635317353183531935320353213532235323353243532535326353273532835329353303533135332353333533435335353363533735338353393534035341353423534335344353453534635347353483534935350353513535235353353543535535356353573535835359353603536135362353633536435365353663536735368353693537035371353723537335374353753537635377353783537935380353813538235383353843538535386353873538835389353903539135392353933539435395353963539735398353993540035401354023540335404354053540635407354083540935410354113541235413354143541535416354173541835419354203542135422354233542435425354263542735428354293543035431354323543335434354353543635437354383543935440354413544235443354443544535446354473544835449354503545135452354533545435455354563545735458354593546035461354623546335464354653546635467354683546935470354713547235473354743547535476354773547835479354803548135482354833548435485354863548735488354893549035491354923549335494354953549635497354983549935500355013550235503355043550535506355073550835509355103551135512355133551435515355163551735518355193552035521355223552335524355253552635527355283552935530355313553235533355343553535536355373553835539355403554135542355433554435545355463554735548355493555035551355523555335554355553555635557355583555935560355613556235563355643556535566355673556835569355703557135572355733557435575355763557735578355793558035581355823558335584355853558635587355883558935590355913559235593355943559535596355973559835599356003560135602356033560435605356063560735608356093561035611356123561335614356153561635617356183561935620356213562235623356243562535626356273562835629356303563135632356333563435635356363563735638356393564035641356423564335644356453564635647356483564935650356513565235653356543565535656356573565835659356603566135662356633566435665356663566735668356693567035671356723567335674356753567635677356783567935680356813568235683356843568535686356873568835689356903569135692356933569435695356963569735698356993570035701357023570335704357053570635707357083570935710357113571235713357143571535716357173571835719357203572135722357233572435725357263572735728357293573035731357323573335734357353573635737357383573935740357413574235743357443574535746357473574835749357503575135752357533575435755357563575735758357593576035761357623576335764357653576635767357683576935770357713577235773357743577535776357773577835779357803578135782357833578435785357863578735788357893579035791357923579335794357953579635797357983579935800358013580235803358043580535806358073580835809358103581135812358133581435815358163581735818358193582035821358223582335824358253582635827358283582935830358313583235833358343583535836358373583835839358403584135842358433584435845358463584735848358493585035851358523585335854358553585635857358583585935860358613586235863358643586535866358673586835869358703587135872358733587435875358763587735878358793588035881358823588335884358853588635887358883588935890358913589235893358943589535896358973589835899359003590135902359033590435905359063590735908359093591035911359123591335914359153591635917359183591935920359213592235923359243592535926359273592835929359303593135932359333593435935359363593735938359393594035941359423594335944359453594635947359483594935950359513595235953359543595535956359573595835959359603596135962359633596435965359663596735968359693597035971359723597335974359753597635977359783597935980359813598235983359843598535986359873598835989359903599135992359933599435995359963599735998359993600036001360023600336004360053600636007360083600936010360113601236013360143601536016360173601836019360203602136022360233602436025360263602736028360293603036031360323603336034360353603636037360383603936040360413604236043360443604536046360473604836049360503605136052360533605436055360563605736058360593606036061360623606336064360653606636067360683606936070360713607236073360743607536076360773607836079360803608136082360833608436085360863608736088360893609036091360923609336094360953609636097360983609936100361013610236103361043610536106361073610836109361103611136112361133611436115361163611736118361193612036121361223612336124361253612636127361283612936130361313613236133361343613536136361373613836139361403614136142361433614436145361463614736148361493615036151361523615336154361553615636157361583615936160361613616236163361643616536166361673616836169361703617136172361733617436175361763617736178361793618036181361823618336184361853618636187361883618936190361913619236193361943619536196361973619836199362003620136202362033620436205362063620736208362093621036211362123621336214362153621636217362183621936220362213622236223362243622536226362273622836229362303623136232362333623436235362363623736238362393624036241362423624336244362453624636247362483624936250362513625236253362543625536256362573625836259362603626136262362633626436265362663626736268362693627036271362723627336274362753627636277362783627936280362813628236283362843628536286362873628836289362903629136292362933629436295362963629736298362993630036301363023630336304363053630636307363083630936310363113631236313363143631536316363173631836319363203632136322363233632436325363263632736328363293633036331363323633336334363353633636337363383633936340363413634236343363443634536346363473634836349363503635136352363533635436355363563635736358363593636036361363623636336364363653636636367363683636936370363713637236373363743637536376363773637836379363803638136382363833638436385363863638736388363893639036391363923639336394363953639636397363983639936400364013640236403364043640536406364073640836409364103641136412364133641436415364163641736418364193642036421364223642336424364253642636427364283642936430364313643236433364343643536436364373643836439364403644136442364433644436445364463644736448364493645036451364523645336454364553645636457364583645936460364613646236463364643646536466364673646836469364703647136472364733647436475364763647736478364793648036481364823648336484364853648636487364883648936490364913649236493364943649536496364973649836499365003650136502365033650436505365063650736508365093651036511365123651336514365153651636517365183651936520365213652236523365243652536526365273652836529365303653136532365333653436535365363653736538365393654036541365423654336544365453654636547365483654936550365513655236553365543655536556365573655836559365603656136562365633656436565365663656736568365693657036571365723657336574365753657636577365783657936580365813658236583365843658536586365873658836589365903659136592365933659436595365963659736598365993660036601366023660336604366053660636607366083660936610366113661236613366143661536616366173661836619366203662136622366233662436625366263662736628366293663036631366323663336634366353663636637366383663936640366413664236643366443664536646366473664836649366503665136652366533665436655366563665736658366593666036661366623666336664366653666636667366683666936670366713667236673366743667536676366773667836679366803668136682366833668436685366863668736688366893669036691366923669336694366953669636697366983669936700367013670236703367043670536706367073670836709367103671136712367133671436715367163671736718367193672036721367223672336724367253672636727367283672936730367313673236733367343673536736367373673836739367403674136742367433674436745367463674736748367493675036751367523675336754367553675636757367583675936760367613676236763367643676536766367673676836769367703677136772367733677436775367763677736778367793678036781367823678336784367853678636787367883678936790367913679236793367943679536796367973679836799368003680136802368033680436805368063680736808368093681036811368123681336814368153681636817368183681936820368213682236823368243682536826368273682836829368303683136832368333683436835368363683736838368393684036841368423684336844368453684636847368483684936850368513685236853368543685536856368573685836859368603686136862368633686436865368663686736868368693687036871368723687336874368753687636877368783687936880368813688236883368843688536886368873688836889368903689136892368933689436895368963689736898368993690036901369023690336904369053690636907369083690936910369113691236913369143691536916369173691836919369203692136922369233692436925369263692736928369293693036931369323693336934369353693636937369383693936940369413694236943369443694536946369473694836949369503695136952369533695436955369563695736958369593696036961369623696336964369653696636967369683696936970369713697236973369743697536976369773697836979369803698136982369833698436985369863698736988369893699036991369923699336994369953699636997369983699937000370013700237003370043700537006370073700837009370103701137012370133701437015370163701737018370193702037021370223702337024370253702637027370283702937030370313703237033370343703537036370373703837039370403704137042370433704437045370463704737048370493705037051370523705337054370553705637057370583705937060370613706237063370643706537066370673706837069370703707137072370733707437075370763707737078370793708037081370823708337084370853708637087370883708937090370913709237093370943709537096370973709837099371003710137102371033710437105371063710737108371093711037111371123711337114371153711637117371183711937120371213712237123371243712537126371273712837129371303713137132371333713437135371363713737138371393714037141371423714337144371453714637147371483714937150371513715237153371543715537156371573715837159371603716137162371633716437165371663716737168371693717037171371723717337174371753717637177371783717937180371813718237183371843718537186371873718837189371903719137192371933719437195371963719737198371993720037201372023720337204372053720637207372083720937210372113721237213372143721537216372173721837219372203722137222372233722437225372263722737228372293723037231372323723337234372353723637237372383723937240372413724237243372443724537246372473724837249372503725137252372533725437255372563725737258372593726037261372623726337264372653726637267372683726937270372713727237273372743727537276372773727837279372803728137282372833728437285372863728737288372893729037291372923729337294372953729637297372983729937300373013730237303373043730537306373073730837309373103731137312373133731437315373163731737318373193732037321373223732337324373253732637327373283732937330373313733237333373343733537336373373733837339373403734137342373433734437345373463734737348373493735037351373523735337354373553735637357373583735937360373613736237363373643736537366373673736837369373703737137372373733737437375373763737737378373793738037381373823738337384373853738637387373883738937390373913739237393373943739537396373973739837399374003740137402374033740437405374063740737408374093741037411374123741337414374153741637417374183741937420374213742237423374243742537426374273742837429374303743137432374333743437435374363743737438374393744037441374423744337444374453744637447374483744937450374513745237453374543745537456374573745837459374603746137462374633746437465374663746737468374693747037471374723747337474374753747637477374783747937480374813748237483374843748537486374873748837489374903749137492374933749437495374963749737498374993750037501375023750337504375053750637507375083750937510375113751237513375143751537516375173751837519375203752137522375233752437525375263752737528375293753037531375323753337534375353753637537375383753937540375413754237543375443754537546375473754837549375503755137552375533755437555375563755737558375593756037561375623756337564375653756637567375683756937570375713757237573375743757537576375773757837579375803758137582375833758437585375863758737588375893759037591375923759337594375953759637597375983759937600376013760237603376043760537606376073760837609376103761137612376133761437615376163761737618376193762037621376223762337624376253762637627376283762937630376313763237633376343763537636376373763837639376403764137642376433764437645376463764737648376493765037651376523765337654376553765637657376583765937660376613766237663376643766537666376673766837669376703767137672376733767437675376763767737678376793768037681376823768337684376853768637687376883768937690376913769237693376943769537696376973769837699377003770137702377033770437705377063770737708377093771037711377123771337714377153771637717377183771937720377213772237723377243772537726377273772837729377303773137732377333773437735377363773737738377393774037741377423774337744377453774637747377483774937750377513775237753377543775537756377573775837759377603776137762377633776437765377663776737768377693777037771377723777337774377753777637777377783777937780377813778237783377843778537786377873778837789377903779137792377933779437795377963779737798377993780037801378023780337804378053780637807378083780937810378113781237813378143781537816378173781837819378203782137822378233782437825378263782737828378293783037831378323783337834378353783637837378383783937840378413784237843378443784537846378473784837849378503785137852378533785437855378563785737858378593786037861378623786337864378653786637867378683786937870378713787237873378743787537876378773787837879378803788137882378833788437885378863788737888378893789037891378923789337894378953789637897378983789937900379013790237903379043790537906379073790837909379103791137912379133791437915379163791737918379193792037921379223792337924379253792637927379283792937930379313793237933379343793537936379373793837939379403794137942379433794437945379463794737948379493795037951379523795337954379553795637957379583795937960379613796237963379643796537966379673796837969379703797137972379733797437975379763797737978379793798037981379823798337984379853798637987379883798937990379913799237993379943799537996379973799837999380003800138002380033800438005380063800738008380093801038011380123801338014380153801638017380183801938020380213802238023380243802538026380273802838029380303803138032380333803438035380363803738038380393804038041380423804338044380453804638047380483804938050380513805238053380543805538056380573805838059380603806138062380633806438065380663806738068380693807038071380723807338074380753807638077380783807938080380813808238083380843808538086380873808838089380903809138092380933809438095380963809738098380993810038101381023810338104381053810638107381083810938110381113811238113381143811538116381173811838119381203812138122381233812438125381263812738128381293813038131381323813338134381353813638137381383813938140381413814238143381443814538146381473814838149381503815138152381533815438155381563815738158381593816038161381623816338164381653816638167381683816938170381713817238173381743817538176381773817838179381803818138182381833818438185381863818738188381893819038191381923819338194381953819638197381983819938200382013820238203382043820538206382073820838209382103821138212382133821438215382163821738218382193822038221382223822338224382253822638227382283822938230382313823238233382343823538236382373823838239382403824138242382433824438245382463824738248382493825038251382523825338254382553825638257382583825938260382613826238263382643826538266382673826838269382703827138272382733827438275382763827738278382793828038281382823828338284382853828638287382883828938290382913829238293382943829538296382973829838299383003830138302383033830438305383063830738308383093831038311383123831338314383153831638317383183831938320383213832238323383243832538326383273832838329383303833138332383333833438335383363833738338383393834038341383423834338344383453834638347383483834938350383513835238353383543835538356383573835838359383603836138362383633836438365383663836738368383693837038371383723837338374383753837638377383783837938380383813838238383383843838538386383873838838389383903839138392383933839438395383963839738398383993840038401384023840338404384053840638407384083840938410384113841238413384143841538416384173841838419384203842138422384233842438425384263842738428384293843038431384323843338434384353843638437384383843938440384413844238443384443844538446384473844838449384503845138452384533845438455384563845738458384593846038461384623846338464384653846638467384683846938470384713847238473384743847538476384773847838479384803848138482384833848438485384863848738488384893849038491384923849338494384953849638497384983849938500385013850238503385043850538506385073850838509385103851138512385133851438515385163851738518385193852038521385223852338524385253852638527385283852938530385313853238533385343853538536385373853838539385403854138542385433854438545385463854738548385493855038551385523855338554385553855638557385583855938560385613856238563385643856538566385673856838569385703857138572385733857438575385763857738578385793858038581385823858338584385853858638587385883858938590385913859238593385943859538596385973859838599386003860138602386033860438605386063860738608386093861038611386123861338614386153861638617386183861938620386213862238623386243862538626386273862838629386303863138632386333863438635386363863738638386393864038641386423864338644386453864638647386483864938650386513865238653386543865538656386573865838659386603866138662386633866438665386663866738668386693867038671386723867338674386753867638677386783867938680386813868238683386843868538686386873868838689386903869138692386933869438695386963869738698386993870038701387023870338704387053870638707387083870938710387113871238713387143871538716387173871838719387203872138722387233872438725387263872738728387293873038731387323873338734387353873638737387383873938740387413874238743387443874538746387473874838749387503875138752387533875438755387563875738758387593876038761387623876338764387653876638767387683876938770387713877238773387743877538776387773877838779387803878138782387833878438785387863878738788387893879038791387923879338794387953879638797387983879938800388013880238803388043880538806388073880838809388103881138812388133881438815388163881738818388193882038821388223882338824388253882638827388283882938830388313883238833388343883538836388373883838839388403884138842388433884438845388463884738848388493885038851388523885338854388553885638857388583885938860388613886238863388643886538866388673886838869388703887138872388733887438875388763887738878388793888038881388823888338884388853888638887388883888938890388913889238893388943889538896388973889838899389003890138902389033890438905389063890738908389093891038911389123891338914389153891638917389183891938920389213892238923389243892538926389273892838929389303893138932389333893438935389363893738938389393894038941389423894338944389453894638947389483894938950389513895238953389543895538956389573895838959389603896138962389633896438965389663896738968389693897038971389723897338974389753897638977389783897938980389813898238983389843898538986389873898838989389903899138992389933899438995389963899738998389993900039001390023900339004390053900639007390083900939010390113901239013390143901539016390173901839019390203902139022390233902439025390263902739028390293903039031390323903339034390353903639037390383903939040390413904239043390443904539046390473904839049390503905139052390533905439055390563905739058390593906039061390623906339064390653906639067390683906939070390713907239073390743907539076390773907839079390803908139082390833908439085390863908739088390893909039091390923909339094390953909639097390983909939100391013910239103391043910539106391073910839109391103911139112391133911439115391163911739118391193912039121391223912339124391253912639127391283912939130391313913239133391343913539136391373913839139391403914139142391433914439145391463914739148391493915039151391523915339154391553915639157391583915939160391613916239163391643916539166391673916839169391703917139172391733917439175391763917739178391793918039181391823918339184391853918639187391883918939190391913919239193391943919539196391973919839199392003920139202392033920439205392063920739208392093921039211392123921339214392153921639217392183921939220392213922239223392243922539226392273922839229392303923139232392333923439235392363923739238392393924039241392423924339244392453924639247392483924939250392513925239253392543925539256392573925839259392603926139262392633926439265392663926739268392693927039271392723927339274392753927639277392783927939280392813928239283392843928539286392873928839289392903929139292392933929439295392963929739298392993930039301393023930339304393053930639307393083930939310393113931239313393143931539316393173931839319393203932139322393233932439325393263932739328393293933039331393323933339334393353933639337393383933939340393413934239343393443934539346393473934839349393503935139352393533935439355393563935739358393593936039361393623936339364393653936639367393683936939370393713937239373393743937539376393773937839379393803938139382393833938439385393863938739388393893939039391393923939339394393953939639397393983939939400394013940239403394043940539406394073940839409394103941139412394133941439415394163941739418394193942039421394223942339424394253942639427394283942939430394313943239433394343943539436394373943839439394403944139442394433944439445394463944739448394493945039451394523945339454394553945639457394583945939460394613946239463394643946539466394673946839469394703947139472394733947439475394763947739478394793948039481394823948339484394853948639487394883948939490394913949239493394943949539496394973949839499395003950139502395033950439505395063950739508395093951039511395123951339514395153951639517395183951939520395213952239523395243952539526395273952839529395303953139532395333953439535395363953739538395393954039541395423954339544395453954639547395483954939550395513955239553395543955539556395573955839559395603956139562395633956439565395663956739568395693957039571395723957339574395753957639577395783957939580395813958239583395843958539586395873958839589395903959139592395933959439595395963959739598395993960039601396023960339604396053960639607396083960939610396113961239613396143961539616396173961839619396203962139622396233962439625396263962739628396293963039631396323963339634396353963639637396383963939640396413964239643396443964539646396473964839649396503965139652396533965439655396563965739658396593966039661396623966339664396653966639667396683966939670396713967239673396743967539676396773967839679396803968139682396833968439685396863968739688396893969039691396923969339694396953969639697396983969939700397013970239703397043970539706397073970839709397103971139712397133971439715397163971739718397193972039721397223972339724397253972639727397283972939730397313973239733397343973539736397373973839739397403974139742397433974439745397463974739748397493975039751397523975339754397553975639757397583975939760397613976239763397643976539766397673976839769397703977139772397733977439775397763977739778397793978039781397823978339784397853978639787397883978939790397913979239793397943979539796397973979839799398003980139802398033980439805398063980739808398093981039811398123981339814398153981639817398183981939820398213982239823398243982539826398273982839829398303983139832398333983439835398363983739838398393984039841398423984339844398453984639847398483984939850398513985239853398543985539856398573985839859398603986139862398633986439865398663986739868398693987039871398723987339874398753987639877398783987939880398813988239883398843988539886398873988839889398903989139892398933989439895398963989739898398993990039901399023990339904399053990639907399083990939910399113991239913399143991539916399173991839919399203992139922399233992439925399263992739928399293993039931399323993339934399353993639937399383993939940399413994239943399443994539946399473994839949399503995139952399533995439955399563995739958399593996039961399623996339964399653996639967399683996939970399713997239973399743997539976399773997839979399803998139982399833998439985399863998739988399893999039991399923999339994399953999639997399983999940000400014000240003400044000540006400074000840009400104001140012400134001440015400164001740018400194002040021400224002340024400254002640027400284002940030400314003240033400344003540036400374003840039400404004140042400434004440045400464004740048400494005040051400524005340054400554005640057400584005940060400614006240063400644006540066400674006840069400704007140072400734007440075400764007740078400794008040081400824008340084400854008640087400884008940090400914009240093400944009540096400974009840099401004010140102401034010440105401064010740108401094011040111401124011340114401154011640117401184011940120401214012240123401244012540126401274012840129401304013140132401334013440135401364013740138401394014040141401424014340144401454014640147401484014940150401514015240153401544015540156401574015840159401604016140162401634016440165401664016740168401694017040171401724017340174401754017640177401784017940180401814018240183401844018540186401874018840189401904019140192401934019440195401964019740198401994020040201402024020340204402054020640207402084020940210402114021240213402144021540216402174021840219402204022140222402234022440225402264022740228402294023040231402324023340234402354023640237402384023940240402414024240243402444024540246402474024840249402504025140252402534025440255402564025740258402594026040261402624026340264402654026640267402684026940270402714027240273402744027540276402774027840279402804028140282402834028440285402864028740288402894029040291402924029340294402954029640297402984029940300403014030240303403044030540306403074030840309403104031140312403134031440315403164031740318403194032040321403224032340324403254032640327403284032940330403314033240333403344033540336403374033840339403404034140342403434034440345403464034740348403494035040351403524035340354403554035640357403584035940360403614036240363403644036540366403674036840369403704037140372403734037440375403764037740378403794038040381403824038340384403854038640387403884038940390403914039240393403944039540396403974039840399404004040140402404034040440405404064040740408404094041040411404124041340414404154041640417404184041940420404214042240423404244042540426404274042840429404304043140432404334043440435404364043740438404394044040441404424044340444404454044640447404484044940450404514045240453404544045540456404574045840459404604046140462404634046440465404664046740468404694047040471404724047340474404754047640477404784047940480404814048240483404844048540486404874048840489404904049140492404934049440495404964049740498404994050040501405024050340504405054050640507405084050940510405114051240513405144051540516405174051840519405204052140522405234052440525405264052740528405294053040531405324053340534405354053640537405384053940540405414054240543405444054540546405474054840549405504055140552405534055440555405564055740558405594056040561405624056340564405654056640567405684056940570405714057240573405744057540576405774057840579405804058140582405834058440585405864058740588405894059040591405924059340594405954059640597405984059940600406014060240603406044060540606406074060840609406104061140612406134061440615406164061740618406194062040621406224062340624406254062640627406284062940630406314063240633406344063540636406374063840639406404064140642406434064440645406464064740648406494065040651406524065340654406554065640657406584065940660406614066240663406644066540666406674066840669406704067140672406734067440675406764067740678406794068040681406824068340684406854068640687406884068940690406914069240693406944069540696406974069840699407004070140702407034070440705407064070740708407094071040711407124071340714407154071640717407184071940720407214072240723407244072540726407274072840729407304073140732407334073440735407364073740738407394074040741407424074340744407454074640747407484074940750407514075240753407544075540756407574075840759407604076140762407634076440765407664076740768407694077040771407724077340774407754077640777407784077940780407814078240783407844078540786407874078840789407904079140792407934079440795407964079740798407994080040801408024080340804408054080640807408084080940810408114081240813408144081540816408174081840819408204082140822408234082440825408264082740828408294083040831408324083340834408354083640837408384083940840408414084240843408444084540846408474084840849408504085140852408534085440855408564085740858408594086040861408624086340864408654086640867408684086940870408714087240873408744087540876408774087840879408804088140882408834088440885408864088740888408894089040891408924089340894408954089640897408984089940900409014090240903409044090540906409074090840909409104091140912409134091440915409164091740918409194092040921409224092340924409254092640927409284092940930409314093240933409344093540936409374093840939409404094140942409434094440945409464094740948409494095040951409524095340954409554095640957409584095940960409614096240963409644096540966409674096840969409704097140972409734097440975409764097740978409794098040981409824098340984409854098640987409884098940990409914099240993409944099540996409974099840999410004100141002410034100441005410064100741008410094101041011410124101341014410154101641017410184101941020410214102241023410244102541026410274102841029410304103141032410334103441035410364103741038410394104041041410424104341044410454104641047410484104941050410514105241053410544105541056410574105841059410604106141062410634106441065410664106741068410694107041071410724107341074410754107641077410784107941080410814108241083410844108541086410874108841089410904109141092410934109441095410964109741098410994110041101411024110341104411054110641107411084110941110411114111241113411144111541116411174111841119411204112141122411234112441125411264112741128411294113041131411324113341134411354113641137411384113941140411414114241143411444114541146411474114841149411504115141152411534115441155411564115741158411594116041161411624116341164411654116641167411684116941170411714117241173411744117541176411774117841179411804118141182411834118441185411864118741188411894119041191411924119341194411954119641197411984119941200412014120241203412044120541206412074120841209412104121141212412134121441215412164121741218412194122041221412224122341224412254122641227412284122941230412314123241233412344123541236412374123841239412404124141242412434124441245412464124741248412494125041251412524125341254412554125641257412584125941260412614126241263412644126541266412674126841269412704127141272412734127441275412764127741278412794128041281412824128341284412854128641287412884128941290412914129241293412944129541296412974129841299413004130141302413034130441305413064130741308413094131041311413124131341314413154131641317413184131941320413214132241323413244132541326413274132841329413304133141332413334133441335413364133741338413394134041341413424134341344413454134641347413484134941350413514135241353413544135541356413574135841359413604136141362413634136441365413664136741368413694137041371413724137341374413754137641377413784137941380413814138241383413844138541386413874138841389413904139141392413934139441395413964139741398413994140041401414024140341404414054140641407414084140941410414114141241413414144141541416414174141841419414204142141422414234142441425414264142741428414294143041431414324143341434414354143641437414384143941440414414144241443414444144541446414474144841449414504145141452414534145441455414564145741458414594146041461414624146341464414654146641467414684146941470414714147241473414744147541476414774147841479414804148141482414834148441485414864148741488414894149041491414924149341494414954149641497414984149941500415014150241503415044150541506415074150841509415104151141512415134151441515415164151741518415194152041521415224152341524415254152641527415284152941530415314153241533415344153541536415374153841539415404154141542415434154441545415464154741548415494155041551415524155341554415554155641557415584155941560415614156241563415644156541566415674156841569415704157141572415734157441575415764157741578415794158041581415824158341584415854158641587415884158941590415914159241593415944159541596415974159841599416004160141602416034160441605416064160741608416094161041611416124161341614416154161641617416184161941620416214162241623416244162541626416274162841629416304163141632416334163441635416364163741638416394164041641416424164341644416454164641647416484164941650416514165241653416544165541656416574165841659416604166141662416634166441665416664166741668416694167041671416724167341674416754167641677416784167941680416814168241683416844168541686416874168841689416904169141692416934169441695416964169741698416994170041701417024170341704417054170641707417084170941710417114171241713417144171541716417174171841719417204172141722417234172441725417264172741728417294173041731417324173341734417354173641737417384173941740417414174241743417444174541746417474174841749417504175141752417534175441755417564175741758417594176041761417624176341764417654176641767417684176941770417714177241773417744177541776417774177841779417804178141782417834178441785417864178741788417894179041791417924179341794417954179641797417984179941800418014180241803
  1. /*!
  2. * @overview Ember - JavaScript Application Framework
  3. * @copyright Copyright 2011-2014 Tilde Inc. and contributors
  4. * Portions Copyright 2006-2011 Strobe Inc.
  5. * Portions Copyright 2008-2011 Apple Inc. All rights reserved.
  6. * @license Licensed under MIT license
  7. * See https://raw.github.com/emberjs/ember.js/master/LICENSE
  8. * @version 1.4.0
  9. */
  10. (function() {
  11. /*global __fail__*/
  12. /**
  13. Ember Debug
  14. @module ember
  15. @submodule ember-debug
  16. */
  17. /**
  18. @class Ember
  19. */
  20. if ('undefined' === typeof Ember) {
  21. Ember = {};
  22. if ('undefined' !== typeof window) {
  23. window.Em = window.Ember = Em = Ember;
  24. }
  25. }
  26. // This needs to be kept in sync with the logic in
  27. // `packages/ember-metal/lib/core.js`.
  28. //
  29. // This is duplicated here to ensure that `Ember.ENV`
  30. // is setup even if `Ember` is not loaded yet.
  31. if (Ember.ENV) {
  32. // do nothing if Ember.ENV is already setup
  33. } else if ('undefined' !== typeof EmberENV) {
  34. Ember.ENV = EmberENV;
  35. } else if('undefined' !== typeof ENV) {
  36. Ember.ENV = ENV;
  37. } else {
  38. Ember.ENV = {};
  39. }
  40. if (!('MANDATORY_SETTER' in Ember.ENV)) {
  41. Ember.ENV.MANDATORY_SETTER = true; // default to true for debug dist
  42. }
  43. /**
  44. Define an assertion that will throw an exception if the condition is not
  45. met. Ember build tools will remove any calls to `Ember.assert()` when
  46. doing a production build. Example:
  47. ```javascript
  48. // Test for truthiness
  49. Ember.assert('Must pass a valid object', obj);
  50. // Fail unconditionally
  51. Ember.assert('This code path should never be run')
  52. ```
  53. @method assert
  54. @param {String} desc A description of the assertion. This will become
  55. the text of the Error thrown if the assertion fails.
  56. @param {Boolean} test Must be truthy for the assertion to pass. If
  57. falsy, an exception will be thrown.
  58. */
  59. Ember.assert = function(desc, test) {
  60. if (!test) {
  61. throw new Ember.Error("Assertion Failed: " + desc);
  62. }
  63. };
  64. /**
  65. Display a warning with the provided message. Ember build tools will
  66. remove any calls to `Ember.warn()` when doing a production build.
  67. @method warn
  68. @param {String} message A warning to display.
  69. @param {Boolean} test An optional boolean. If falsy, the warning
  70. will be displayed.
  71. */
  72. Ember.warn = function(message, test) {
  73. if (!test) {
  74. Ember.Logger.warn("WARNING: "+message);
  75. if ('trace' in Ember.Logger) Ember.Logger.trace();
  76. }
  77. };
  78. /**
  79. Display a debug notice. Ember build tools will remove any calls to
  80. `Ember.debug()` when doing a production build.
  81. ```javascript
  82. Ember.debug("I'm a debug notice!");
  83. ```
  84. @method debug
  85. @param {String} message A debug message to display.
  86. */
  87. Ember.debug = function(message) {
  88. Ember.Logger.debug("DEBUG: "+message);
  89. };
  90. /**
  91. Display a deprecation warning with the provided message and a stack trace
  92. (Chrome and Firefox only). Ember build tools will remove any calls to
  93. `Ember.deprecate()` when doing a production build.
  94. @method deprecate
  95. @param {String} message A description of the deprecation.
  96. @param {Boolean} test An optional boolean. If falsy, the deprecation
  97. will be displayed.
  98. */
  99. Ember.deprecate = function(message, test) {
  100. if (Ember.TESTING_DEPRECATION) { return; }
  101. if (arguments.length === 1) { test = false; }
  102. if (test) { return; }
  103. if (Ember.ENV.RAISE_ON_DEPRECATION) { throw new Ember.Error(message); }
  104. var error;
  105. // When using new Error, we can't do the arguments check for Chrome. Alternatives are welcome
  106. try { __fail__.fail(); } catch (e) { error = e; }
  107. if (Ember.LOG_STACKTRACE_ON_DEPRECATION && error.stack) {
  108. var stack, stackStr = '';
  109. if (error['arguments']) {
  110. // Chrome
  111. stack = error.stack.replace(/^\s+at\s+/gm, '').
  112. replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2').
  113. replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm, '{anonymous}($1)').split('\n');
  114. stack.shift();
  115. } else {
  116. // Firefox
  117. stack = error.stack.replace(/(?:\n@:0)?\s+$/m, '').
  118. replace(/^\(/gm, '{anonymous}(').split('\n');
  119. }
  120. stackStr = "\n " + stack.slice(2).join("\n ");
  121. message = message + stackStr;
  122. }
  123. Ember.Logger.warn("DEPRECATION: "+message);
  124. };
  125. /**
  126. Alias an old, deprecated method with its new counterpart.
  127. Display a deprecation warning with the provided message and a stack trace
  128. (Chrome and Firefox only) when the assigned method is called.
  129. Ember build tools will not remove calls to `Ember.deprecateFunc()`, though
  130. no warnings will be shown in production.
  131. ```javascript
  132. Ember.oldMethod = Ember.deprecateFunc("Please use the new, updated method", Ember.newMethod);
  133. ```
  134. @method deprecateFunc
  135. @param {String} message A description of the deprecation.
  136. @param {Function} func The new function called to replace its deprecated counterpart.
  137. @return {Function} a new function that wrapped the original function with a deprecation warning
  138. */
  139. Ember.deprecateFunc = function(message, func) {
  140. return function() {
  141. Ember.deprecate(message);
  142. return func.apply(this, arguments);
  143. };
  144. };
  145. // Inform the developer about the Ember Inspector if not installed.
  146. if (!Ember.testing) {
  147. var isFirefox = typeof InstallTrigger !== 'undefined';
  148. var isChrome = !!window.chrome && !window.opera;
  149. if (typeof window !== 'undefined' && (isFirefox || isChrome) && window.addEventListener) {
  150. window.addEventListener("load", function() {
  151. if (document.body && document.body.dataset && !document.body.dataset.emberExtension) {
  152. var downloadURL;
  153. if(isChrome) {
  154. downloadURL = 'https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi';
  155. } else if(isFirefox) {
  156. downloadURL = 'https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/'
  157. }
  158. Ember.debug('For more advanced debugging, install the Ember Inspector from ' + downloadURL);
  159. }
  160. }, false);
  161. }
  162. }
  163. })();
  164. /*!
  165. * @overview Ember - JavaScript Application Framework
  166. * @copyright Copyright 2011-2014 Tilde Inc. and contributors
  167. * Portions Copyright 2006-2011 Strobe Inc.
  168. * Portions Copyright 2008-2011 Apple Inc. All rights reserved.
  169. * @license Licensed under MIT license
  170. * See https://raw.github.com/emberjs/ember.js/master/LICENSE
  171. * @version 1.4.0
  172. */
  173. (function() {
  174. var define, requireModule, require, requirejs;
  175. (function() {
  176. var registry = {}, seen = {};
  177. define = function(name, deps, callback) {
  178. registry[name] = { deps: deps, callback: callback };
  179. };
  180. requirejs = require = requireModule = function(name) {
  181. requirejs._eak_seen = registry;
  182. if (seen[name]) { return seen[name]; }
  183. seen[name] = {};
  184. if (!registry[name]) {
  185. throw new Error("Could not find module " + name);
  186. }
  187. var mod = registry[name],
  188. deps = mod.deps,
  189. callback = mod.callback,
  190. reified = [],
  191. exports;
  192. for (var i=0, l=deps.length; i<l; i++) {
  193. if (deps[i] === 'exports') {
  194. reified.push(exports = {});
  195. } else {
  196. reified.push(requireModule(resolve(deps[i])));
  197. }
  198. }
  199. var value = callback.apply(this, reified);
  200. return seen[name] = exports || value;
  201. function resolve(child) {
  202. if (child.charAt(0) !== '.') { return child; }
  203. var parts = child.split("/");
  204. var parentBase = name.split("/").slice(0, -1);
  205. for (var i=0, l=parts.length; i<l; i++) {
  206. var part = parts[i];
  207. if (part === '..') { parentBase.pop(); }
  208. else if (part === '.') { continue; }
  209. else { parentBase.push(part); }
  210. }
  211. return parentBase.join("/");
  212. }
  213. };
  214. })();
  215. (function() {
  216. /*globals Em:true ENV EmberENV MetamorphENV:true */
  217. /**
  218. @module ember
  219. @submodule ember-metal
  220. */
  221. /**
  222. All Ember methods and functions are defined inside of this namespace. You
  223. generally should not add new properties to this namespace as it may be
  224. overwritten by future versions of Ember.
  225. You can also use the shorthand `Em` instead of `Ember`.
  226. Ember-Runtime is a framework that provides core functions for Ember including
  227. cross-platform functions, support for property observing and objects. Its
  228. focus is on small size and performance. You can use this in place of or
  229. along-side other cross-platform libraries such as jQuery.
  230. The core Runtime framework is based on the jQuery API with a number of
  231. performance optimizations.
  232. @class Ember
  233. @static
  234. @version 1.4.0
  235. */
  236. if ('undefined' === typeof Ember) {
  237. // Create core object. Make it act like an instance of Ember.Namespace so that
  238. // objects assigned to it are given a sane string representation.
  239. Ember = {};
  240. }
  241. // Default imports, exports and lookup to the global object;
  242. var imports = Ember.imports = Ember.imports || this;
  243. var exports = Ember.exports = Ember.exports || this;
  244. var lookup = Ember.lookup = Ember.lookup || this;
  245. // aliases needed to keep minifiers from removing the global context
  246. exports.Em = exports.Ember = Em = Ember;
  247. // Make sure these are set whether Ember was already defined or not
  248. Ember.isNamespace = true;
  249. Ember.toString = function() { return "Ember"; };
  250. /**
  251. @property VERSION
  252. @type String
  253. @default '1.4.0'
  254. @static
  255. */
  256. Ember.VERSION = '1.4.0';
  257. /**
  258. Standard environmental variables. You can define these in a global `EmberENV`
  259. variable before loading Ember to control various configuration settings.
  260. For backwards compatibility with earlier versions of Ember the global `ENV`
  261. variable will be used if `EmberENV` is not defined.
  262. @property ENV
  263. @type Hash
  264. */
  265. // This needs to be kept in sync with the logic in
  266. // `packages/ember-debug/lib/main.js`.
  267. if (Ember.ENV) {
  268. // do nothing if Ember.ENV is already setup
  269. } else if ('undefined' !== typeof EmberENV) {
  270. Ember.ENV = EmberENV;
  271. } else if('undefined' !== typeof ENV) {
  272. Ember.ENV = ENV;
  273. } else {
  274. Ember.ENV = {};
  275. }
  276. Ember.config = Ember.config || {};
  277. // We disable the RANGE API by default for performance reasons
  278. if ('undefined' === typeof Ember.ENV.DISABLE_RANGE_API) {
  279. Ember.ENV.DISABLE_RANGE_API = true;
  280. }
  281. if ("undefined" === typeof MetamorphENV) {
  282. exports.MetamorphENV = {};
  283. }
  284. MetamorphENV.DISABLE_RANGE_API = Ember.ENV.DISABLE_RANGE_API;
  285. /**
  286. Hash of enabled Canary features. Add to before creating your application.
  287. You can also define `ENV.FEATURES` if you need to enable features flagged at runtime.
  288. @property FEATURES
  289. @type Hash
  290. */
  291. Ember.FEATURES = Ember.ENV.FEATURES || {};
  292. /**
  293. Test that a feature is enabled. Parsed by Ember's build tools to leave
  294. experimental features out of beta/stable builds.
  295. You can define the following configuration options:
  296. * `ENV.ENABLE_ALL_FEATURES` - force all features to be enabled.
  297. * `ENV.ENABLE_OPTIONAL_FEATURES` - enable any features that have not been explicitly
  298. enabled/disabled.
  299. @method isEnabled
  300. @param {string} feature
  301. */
  302. Ember.FEATURES.isEnabled = function(feature) {
  303. var featureValue = Ember.FEATURES[feature];
  304. if (Ember.ENV.ENABLE_ALL_FEATURES) {
  305. return true;
  306. } else if (featureValue === true || featureValue === false || featureValue === undefined) {
  307. return featureValue;
  308. } else if (Ember.ENV.ENABLE_OPTIONAL_FEATURES) {
  309. return true;
  310. } else {
  311. return false;
  312. }
  313. };
  314. // ..........................................................
  315. // BOOTSTRAP
  316. //
  317. /**
  318. Determines whether Ember should enhances some built-in object prototypes to
  319. provide a more friendly API. If enabled, a few methods will be added to
  320. `Function`, `String`, and `Array`. `Object.prototype` will not be enhanced,
  321. which is the one that causes most trouble for people.
  322. In general we recommend leaving this option set to true since it rarely
  323. conflicts with other code. If you need to turn it off however, you can
  324. define an `ENV.EXTEND_PROTOTYPES` config to disable it.
  325. @property EXTEND_PROTOTYPES
  326. @type Boolean
  327. @default true
  328. */
  329. Ember.EXTEND_PROTOTYPES = Ember.ENV.EXTEND_PROTOTYPES;
  330. if (typeof Ember.EXTEND_PROTOTYPES === 'undefined') {
  331. Ember.EXTEND_PROTOTYPES = true;
  332. }
  333. /**
  334. Determines whether Ember logs a full stack trace during deprecation warnings
  335. @property LOG_STACKTRACE_ON_DEPRECATION
  336. @type Boolean
  337. @default true
  338. */
  339. Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false);
  340. /**
  341. Determines whether Ember should add ECMAScript 5 shims to older browsers.
  342. @property SHIM_ES5
  343. @type Boolean
  344. @default Ember.EXTEND_PROTOTYPES
  345. */
  346. Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : Ember.EXTEND_PROTOTYPES;
  347. /**
  348. Determines whether Ember logs info about version of used libraries
  349. @property LOG_VERSION
  350. @type Boolean
  351. @default true
  352. */
  353. Ember.LOG_VERSION = (Ember.ENV.LOG_VERSION === false) ? false : true;
  354. /**
  355. Empty function. Useful for some operations. Always returns `this`.
  356. @method K
  357. @private
  358. @return {Object}
  359. */
  360. Ember.K = function() { return this; };
  361. // Stub out the methods defined by the ember-debug package in case it's not loaded
  362. if ('undefined' === typeof Ember.assert) { Ember.assert = Ember.K; }
  363. if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; }
  364. if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; }
  365. if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.K; }
  366. if ('undefined' === typeof Ember.deprecateFunc) {
  367. Ember.deprecateFunc = function(_, func) { return func; };
  368. }
  369. /**
  370. Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from
  371. jQuery master. We'll just bootstrap our own uuid now.
  372. @property uuid
  373. @type Number
  374. @private
  375. */
  376. Ember.uuid = 0;
  377. /**
  378. Merge the contents of two objects together into the first object.
  379. ```javascript
  380. Ember.merge({first: 'Tom'}, {last: 'Dale'}); // {first: 'Tom', last: 'Dale'}
  381. var a = {first: 'Yehuda'}, b = {last: 'Katz'};
  382. Ember.merge(a, b); // a == {first: 'Yehuda', last: 'Katz'}, b == {last: 'Katz'}
  383. ```
  384. @method merge
  385. @for Ember
  386. @param {Object} original The object to merge into
  387. @param {Object} updates The object to copy properties from
  388. @return {Object}
  389. */
  390. Ember.merge = function(original, updates) {
  391. for (var prop in updates) {
  392. if (!updates.hasOwnProperty(prop)) { continue; }
  393. original[prop] = updates[prop];
  394. }
  395. return original;
  396. };
  397. /**
  398. Returns true if the passed value is null or undefined. This avoids errors
  399. from JSLint complaining about use of ==, which can be technically
  400. confusing.
  401. ```javascript
  402. Ember.isNone(); // true
  403. Ember.isNone(null); // true
  404. Ember.isNone(undefined); // true
  405. Ember.isNone(''); // false
  406. Ember.isNone([]); // false
  407. Ember.isNone(function() {}); // false
  408. ```
  409. @method isNone
  410. @for Ember
  411. @param {Object} obj Value to test
  412. @return {Boolean}
  413. */
  414. Ember.isNone = function(obj) {
  415. return obj === null || obj === undefined;
  416. };
  417. Ember.none = Ember.deprecateFunc("Ember.none is deprecated. Please use Ember.isNone instead.", Ember.isNone);
  418. /**
  419. Verifies that a value is `null` or an empty string, empty array,
  420. or empty function.
  421. Constrains the rules on `Ember.isNone` by returning false for empty
  422. string and empty arrays.
  423. ```javascript
  424. Ember.isEmpty(); // true
  425. Ember.isEmpty(null); // true
  426. Ember.isEmpty(undefined); // true
  427. Ember.isEmpty(''); // true
  428. Ember.isEmpty([]); // true
  429. Ember.isEmpty('Adam Hawkins'); // false
  430. Ember.isEmpty([0,1,2]); // false
  431. ```
  432. @method isEmpty
  433. @for Ember
  434. @param {Object} obj Value to test
  435. @return {Boolean}
  436. */
  437. Ember.isEmpty = function(obj) {
  438. return Ember.isNone(obj) || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && Ember.get(obj, 'length') === 0);
  439. };
  440. Ember.empty = Ember.deprecateFunc("Ember.empty is deprecated. Please use Ember.isEmpty instead.", Ember.isEmpty) ;
  441. })();
  442. (function() {
  443. /*globals Node */
  444. /**
  445. @module ember-metal
  446. */
  447. /**
  448. Platform specific methods and feature detectors needed by the framework.
  449. @class platform
  450. @namespace Ember
  451. @static
  452. */
  453. var platform = Ember.platform = {};
  454. /**
  455. Identical to `Object.create()`. Implements if not available natively.
  456. @method create
  457. @for Ember
  458. */
  459. Ember.create = Object.create;
  460. // IE8 has Object.create but it couldn't treat property descriptors.
  461. if (Ember.create) {
  462. if (Ember.create({a: 1}, {a: {value: 2}}).a !== 2) {
  463. Ember.create = null;
  464. }
  465. }
  466. // STUB_OBJECT_CREATE allows us to override other libraries that stub
  467. // Object.create different than we would prefer
  468. if (!Ember.create || Ember.ENV.STUB_OBJECT_CREATE) {
  469. var K = function() {};
  470. Ember.create = function(obj, props) {
  471. K.prototype = obj;
  472. obj = new K();
  473. if (props) {
  474. K.prototype = obj;
  475. for (var prop in props) {
  476. K.prototype[prop] = props[prop].value;
  477. }
  478. obj = new K();
  479. }
  480. K.prototype = null;
  481. return obj;
  482. };
  483. Ember.create.isSimulated = true;
  484. }
  485. var defineProperty = Object.defineProperty;
  486. var canRedefineProperties, canDefinePropertyOnDOM;
  487. // Catch IE8 where Object.defineProperty exists but only works on DOM elements
  488. if (defineProperty) {
  489. try {
  490. defineProperty({}, 'a',{get:function() {}});
  491. } catch (e) {
  492. defineProperty = null;
  493. }
  494. }
  495. if (defineProperty) {
  496. // Detects a bug in Android <3.2 where you cannot redefine a property using
  497. // Object.defineProperty once accessors have already been set.
  498. canRedefineProperties = (function() {
  499. var obj = {};
  500. defineProperty(obj, 'a', {
  501. configurable: true,
  502. enumerable: true,
  503. get: function() { },
  504. set: function() { }
  505. });
  506. defineProperty(obj, 'a', {
  507. configurable: true,
  508. enumerable: true,
  509. writable: true,
  510. value: true
  511. });
  512. return obj.a === true;
  513. })();
  514. // This is for Safari 5.0, which supports Object.defineProperty, but not
  515. // on DOM nodes.
  516. canDefinePropertyOnDOM = (function() {
  517. try {
  518. defineProperty(document.createElement('div'), 'definePropertyOnDOM', {});
  519. return true;
  520. } catch(e) { }
  521. return false;
  522. })();
  523. if (!canRedefineProperties) {
  524. defineProperty = null;
  525. } else if (!canDefinePropertyOnDOM) {
  526. defineProperty = function(obj, keyName, desc) {
  527. var isNode;
  528. if (typeof Node === "object") {
  529. isNode = obj instanceof Node;
  530. } else {
  531. isNode = typeof obj === "object" && typeof obj.nodeType === "number" && typeof obj.nodeName === "string";
  532. }
  533. if (isNode) {
  534. // TODO: Should we have a warning here?
  535. return (obj[keyName] = desc.value);
  536. } else {
  537. return Object.defineProperty(obj, keyName, desc);
  538. }
  539. };
  540. }
  541. }
  542. /**
  543. @class platform
  544. @namespace Ember
  545. */
  546. /**
  547. Identical to `Object.defineProperty()`. Implements as much functionality
  548. as possible if not available natively.
  549. @method defineProperty
  550. @param {Object} obj The object to modify
  551. @param {String} keyName property name to modify
  552. @param {Object} desc descriptor hash
  553. @return {void}
  554. */
  555. platform.defineProperty = defineProperty;
  556. /**
  557. Set to true if the platform supports native getters and setters.
  558. @property hasPropertyAccessors
  559. @final
  560. */
  561. platform.hasPropertyAccessors = true;
  562. if (!platform.defineProperty) {
  563. platform.hasPropertyAccessors = false;
  564. platform.defineProperty = function(obj, keyName, desc) {
  565. if (!desc.get) { obj[keyName] = desc.value; }
  566. };
  567. platform.defineProperty.isSimulated = true;
  568. }
  569. if (Ember.ENV.MANDATORY_SETTER && !platform.hasPropertyAccessors) {
  570. Ember.ENV.MANDATORY_SETTER = false;
  571. }
  572. })();
  573. (function() {
  574. /*jshint newcap:false*/
  575. /**
  576. @module ember-metal
  577. */
  578. // NOTE: There is a bug in jshint that doesn't recognize `Object()` without `new`
  579. // as being ok unless both `newcap:false` and not `use strict`.
  580. // https://github.com/jshint/jshint/issues/392
  581. // Testing this is not ideal, but we want to use native functions
  582. // if available, but not to use versions created by libraries like Prototype
  583. var isNativeFunc = function(func) {
  584. // This should probably work in all browsers likely to have ES5 array methods
  585. return func && Function.prototype.toString.call(func).indexOf('[native code]') > -1;
  586. };
  587. // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map
  588. var arrayMap = isNativeFunc(Array.prototype.map) ? Array.prototype.map : function(fun /*, thisp */) {
  589. //"use strict";
  590. if (this === void 0 || this === null) {
  591. throw new TypeError();
  592. }
  593. var t = Object(this);
  594. var len = t.length >>> 0;
  595. if (typeof fun !== "function") {
  596. throw new TypeError();
  597. }
  598. var res = new Array(len);
  599. var thisp = arguments[1];
  600. for (var i = 0; i < len; i++) {
  601. if (i in t) {
  602. res[i] = fun.call(thisp, t[i], i, t);
  603. }
  604. }
  605. return res;
  606. };
  607. // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach
  608. var arrayForEach = isNativeFunc(Array.prototype.forEach) ? Array.prototype.forEach : function(fun /*, thisp */) {
  609. //"use strict";
  610. if (this === void 0 || this === null) {
  611. throw new TypeError();
  612. }
  613. var t = Object(this);
  614. var len = t.length >>> 0;
  615. if (typeof fun !== "function") {
  616. throw new TypeError();
  617. }
  618. var thisp = arguments[1];
  619. for (var i = 0; i < len; i++) {
  620. if (i in t) {
  621. fun.call(thisp, t[i], i, t);
  622. }
  623. }
  624. };
  625. var arrayIndexOf = isNativeFunc(Array.prototype.indexOf) ? Array.prototype.indexOf : function (obj, fromIndex) {
  626. if (fromIndex === null || fromIndex === undefined) { fromIndex = 0; }
  627. else if (fromIndex < 0) { fromIndex = Math.max(0, this.length + fromIndex); }
  628. for (var i = fromIndex, j = this.length; i < j; i++) {
  629. if (this[i] === obj) { return i; }
  630. }
  631. return -1;
  632. };
  633. /**
  634. Array polyfills to support ES5 features in older browsers.
  635. @namespace Ember
  636. @property ArrayPolyfills
  637. */
  638. Ember.ArrayPolyfills = {
  639. map: arrayMap,
  640. forEach: arrayForEach,
  641. indexOf: arrayIndexOf
  642. };
  643. if (Ember.SHIM_ES5) {
  644. if (!Array.prototype.map) {
  645. Array.prototype.map = arrayMap;
  646. }
  647. if (!Array.prototype.forEach) {
  648. Array.prototype.forEach = arrayForEach;
  649. }
  650. if (!Array.prototype.indexOf) {
  651. Array.prototype.indexOf = arrayIndexOf;
  652. }
  653. }
  654. })();
  655. (function() {
  656. var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
  657. /**
  658. A subclass of the JavaScript Error object for use in Ember.
  659. @class Error
  660. @namespace Ember
  661. @extends Error
  662. @constructor
  663. */
  664. Ember.Error = function() {
  665. var tmp = Error.apply(this, arguments);
  666. // Adds a `stack` property to the given error object that will yield the
  667. // stack trace at the time captureStackTrace was called.
  668. // When collecting the stack trace all frames above the topmost call
  669. // to this function, including that call, will be left out of the
  670. // stack trace.
  671. // This is useful because we can hide Ember implementation details
  672. // that are not very helpful for the user.
  673. if (Error.captureStackTrace) {
  674. Error.captureStackTrace(this, Ember.Error);
  675. }
  676. // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
  677. for (var idx = 0; idx < errorProps.length; idx++) {
  678. this[errorProps[idx]] = tmp[errorProps[idx]];
  679. }
  680. };
  681. Ember.Error.prototype = Ember.create(Error.prototype);
  682. // ..........................................................
  683. // ERROR HANDLING
  684. //
  685. /**
  686. A function may be assigned to `Ember.onerror` to be called when Ember
  687. internals encounter an error. This is useful for specialized error handling
  688. and reporting code.
  689. ```javascript
  690. Ember.onerror = function(error) {
  691. Em.$.ajax('/report-error', 'POST', {
  692. stack: error.stack,
  693. otherInformation: 'whatever app state you want to provide'
  694. });
  695. };
  696. ```
  697. @event onerror
  698. @for Ember
  699. @param {Exception} error the error object
  700. */
  701. Ember.onerror = null;
  702. /**
  703. Wrap code block in a try/catch if `Ember.onerror` is set.
  704. @private
  705. @method handleErrors
  706. @for Ember
  707. @param {Function} func
  708. @param [context]
  709. */
  710. Ember.handleErrors = function(func, context) {
  711. // Unfortunately in some browsers we lose the backtrace if we rethrow the existing error,
  712. // so in the event that we don't have an `onerror` handler we don't wrap in a try/catch
  713. if ('function' === typeof Ember.onerror) {
  714. try {
  715. return func.call(context || this);
  716. } catch (error) {
  717. Ember.onerror(error);
  718. }
  719. } else {
  720. return func.call(context || this);
  721. }
  722. };
  723. })();
  724. (function() {
  725. /**
  726. @module ember-metal
  727. */
  728. /**
  729. Prefix used for guids through out Ember.
  730. @private
  731. */
  732. Ember.GUID_PREFIX = 'ember';
  733. var o_defineProperty = Ember.platform.defineProperty,
  734. o_create = Ember.create,
  735. // Used for guid generation...
  736. GUID_KEY = '__ember'+ (+ new Date()),
  737. uuid = 0,
  738. numberCache = [],
  739. stringCache = {};
  740. var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER;
  741. /**
  742. A unique key used to assign guids and other private metadata to objects.
  743. If you inspect an object in your browser debugger you will often see these.
  744. They can be safely ignored.
  745. On browsers that support it, these properties are added with enumeration
  746. disabled so they won't show up when you iterate over your properties.
  747. @private
  748. @property GUID_KEY
  749. @for Ember
  750. @type String
  751. @final
  752. */
  753. Ember.GUID_KEY = GUID_KEY;
  754. var GUID_DESC = {
  755. writable: false,
  756. configurable: false,
  757. enumerable: false,
  758. value: null
  759. };
  760. /**
  761. Generates a new guid, optionally saving the guid to the object that you
  762. pass in. You will rarely need to use this method. Instead you should
  763. call `Ember.guidFor(obj)`, which return an existing guid if available.
  764. @private
  765. @method generateGuid
  766. @for Ember
  767. @param {Object} [obj] Object the guid will be used for. If passed in, the guid will
  768. be saved on the object and reused whenever you pass the same object
  769. again.
  770. If no object is passed, just generate a new guid.
  771. @param {String} [prefix] Prefix to place in front of the guid. Useful when you want to
  772. separate the guid into separate namespaces.
  773. @return {String} the guid
  774. */
  775. Ember.generateGuid = function generateGuid(obj, prefix) {
  776. if (!prefix) prefix = Ember.GUID_PREFIX;
  777. var ret = (prefix + (uuid++));
  778. if (obj) {
  779. GUID_DESC.value = ret;
  780. o_defineProperty(obj, GUID_KEY, GUID_DESC);
  781. }
  782. return ret;
  783. };
  784. /**
  785. Returns a unique id for the object. If the object does not yet have a guid,
  786. one will be assigned to it. You can call this on any object,
  787. `Ember.Object`-based or not, but be aware that it will add a `_guid`
  788. property.
  789. You can also use this method on DOM Element objects.
  790. @private
  791. @method guidFor
  792. @for Ember
  793. @param {Object} obj any object, string, number, Element, or primitive
  794. @return {String} the unique guid for this instance.
  795. */
  796. Ember.guidFor = function guidFor(obj) {
  797. // special cases where we don't want to add a key to object
  798. if (obj === undefined) return "(undefined)";
  799. if (obj === null) return "(null)";
  800. var ret;
  801. var type = typeof obj;
  802. // Don't allow prototype changes to String etc. to change the guidFor
  803. switch(type) {
  804. case 'number':
  805. ret = numberCache[obj];
  806. if (!ret) ret = numberCache[obj] = 'nu'+obj;
  807. return ret;
  808. case 'string':
  809. ret = stringCache[obj];
  810. if (!ret) ret = stringCache[obj] = 'st'+(uuid++);
  811. return ret;
  812. case 'boolean':
  813. return obj ? '(true)' : '(false)';
  814. default:
  815. if (obj[GUID_KEY]) return obj[GUID_KEY];
  816. if (obj === Object) return '(Object)';
  817. if (obj === Array) return '(Array)';
  818. ret = 'ember'+(uuid++);
  819. GUID_DESC.value = ret;
  820. o_defineProperty(obj, GUID_KEY, GUID_DESC);
  821. return ret;
  822. }
  823. };
  824. // ..........................................................
  825. // META
  826. //
  827. var META_DESC = Ember.META_DESC = {
  828. writable: true,
  829. configurable: false,
  830. enumerable: false,
  831. value: null
  832. };
  833. var META_KEY = Ember.GUID_KEY+'_meta';
  834. /**
  835. The key used to store meta information on object for property observing.
  836. @property META_KEY
  837. @for Ember
  838. @private
  839. @final
  840. @type String
  841. */
  842. Ember.META_KEY = META_KEY;
  843. var isDefinePropertySimulated = Ember.platform.defineProperty.isSimulated;
  844. function Meta(obj) {
  845. this.descs = {};
  846. this.watching = {};
  847. this.cache = {};
  848. this.source = obj;
  849. }
  850. Meta.prototype = {
  851. descs: null,
  852. deps: null,
  853. watching: null,
  854. listeners: null,
  855. cache: null,
  856. source: null,
  857. mixins: null,
  858. bindings: null,
  859. chains: null,
  860. chainWatchers: null,
  861. values: null,
  862. proto: null
  863. };
  864. if (isDefinePropertySimulated) {
  865. // on platforms that don't support enumerable false
  866. // make meta fail jQuery.isPlainObject() to hide from
  867. // jQuery.extend() by having a property that fails
  868. // hasOwnProperty check.
  869. Meta.prototype.__preventPlainObject__ = true;
  870. // Without non-enumerable properties, meta objects will be output in JSON
  871. // unless explicitly suppressed
  872. Meta.prototype.toJSON = function () { };
  873. }
  874. // Placeholder for non-writable metas.
  875. var EMPTY_META = new Meta(null);
  876. if (MANDATORY_SETTER) { EMPTY_META.values = {}; }
  877. Ember.EMPTY_META = EMPTY_META;
  878. /**
  879. Retrieves the meta hash for an object. If `writable` is true ensures the
  880. hash is writable for this object as well.
  881. The meta object contains information about computed property descriptors as
  882. well as any watched properties and other information. You generally will
  883. not access this information directly but instead work with higher level
  884. methods that manipulate this hash indirectly.
  885. @method meta
  886. @for Ember
  887. @private
  888. @param {Object} obj The object to retrieve meta for
  889. @param {Boolean} [writable=true] Pass `false` if you do not intend to modify
  890. the meta hash, allowing the method to avoid making an unnecessary copy.
  891. @return {Object} the meta hash for an object
  892. */
  893. Ember.meta = function meta(obj, writable) {
  894. var ret = obj[META_KEY];
  895. if (writable===false) return ret || EMPTY_META;
  896. if (!ret) {
  897. if (!isDefinePropertySimulated) o_defineProperty(obj, META_KEY, META_DESC);
  898. ret = new Meta(obj);
  899. if (MANDATORY_SETTER) { ret.values = {}; }
  900. obj[META_KEY] = ret;
  901. // make sure we don't accidentally try to create constructor like desc
  902. ret.descs.constructor = null;
  903. } else if (ret.source !== obj) {
  904. if (!isDefinePropertySimulated) o_defineProperty(obj, META_KEY, META_DESC);
  905. ret = o_create(ret);
  906. ret.descs = o_create(ret.descs);
  907. ret.watching = o_create(ret.watching);
  908. ret.cache = {};
  909. ret.source = obj;
  910. if (MANDATORY_SETTER) { ret.values = o_create(ret.values); }
  911. obj[META_KEY] = ret;
  912. }
  913. return ret;
  914. };
  915. Ember.getMeta = function getMeta(obj, property) {
  916. var meta = Ember.meta(obj, false);
  917. return meta[property];
  918. };
  919. Ember.setMeta = function setMeta(obj, property, value) {
  920. var meta = Ember.meta(obj, true);
  921. meta[property] = value;
  922. return value;
  923. };
  924. /**
  925. @deprecated
  926. @private
  927. In order to store defaults for a class, a prototype may need to create
  928. a default meta object, which will be inherited by any objects instantiated
  929. from the class's constructor.
  930. However, the properties of that meta object are only shallow-cloned,
  931. so if a property is a hash (like the event system's `listeners` hash),
  932. it will by default be shared across all instances of that class.
  933. This method allows extensions to deeply clone a series of nested hashes or
  934. other complex objects. For instance, the event system might pass
  935. `['listeners', 'foo:change', 'ember157']` to `prepareMetaPath`, which will
  936. walk down the keys provided.
  937. For each key, if the key does not exist, it is created. If it already
  938. exists and it was inherited from its constructor, the constructor's
  939. key is cloned.
  940. You can also pass false for `writable`, which will simply return
  941. undefined if `prepareMetaPath` discovers any part of the path that
  942. shared or undefined.
  943. @method metaPath
  944. @for Ember
  945. @param {Object} obj The object whose meta we are examining
  946. @param {Array} path An array of keys to walk down
  947. @param {Boolean} writable whether or not to create a new meta
  948. (or meta property) if one does not already exist or if it's
  949. shared with its constructor
  950. */
  951. Ember.metaPath = function metaPath(obj, path, writable) {
  952. Ember.deprecate("Ember.metaPath is deprecated and will be removed from future releases.");
  953. var meta = Ember.meta(obj, writable), keyName, value;
  954. for (var i=0, l=path.length; i<l; i++) {
  955. keyName = path[i];
  956. value = meta[keyName];
  957. if (!value) {
  958. if (!writable) { return undefined; }
  959. value = meta[keyName] = { __ember_source__: obj };
  960. } else if (value.__ember_source__ !== obj) {
  961. if (!writable) { return undefined; }
  962. value = meta[keyName] = o_create(value);
  963. value.__ember_source__ = obj;
  964. }
  965. meta = value;
  966. }
  967. return value;
  968. };
  969. /**
  970. Wraps the passed function so that `this._super` will point to the superFunc
  971. when the function is invoked. This is the primitive we use to implement
  972. calls to super.
  973. @private
  974. @method wrap
  975. @for Ember
  976. @param {Function} func The function to call
  977. @param {Function} superFunc The super function.
  978. @return {Function} wrapped function.
  979. */
  980. Ember.wrap = function(func, superFunc) {
  981. function K() {}
  982. function superWrapper() {
  983. var ret, sup = this._super;
  984. this._super = superFunc || K;
  985. ret = func.apply(this, arguments);
  986. this._super = sup;
  987. return ret;
  988. }
  989. superWrapper.wrappedFunction = func;
  990. superWrapper.__ember_observes__ = func.__ember_observes__;
  991. superWrapper.__ember_observesBefore__ = func.__ember_observesBefore__;
  992. superWrapper.__ember_listens__ = func.__ember_listens__;
  993. return superWrapper;
  994. };
  995. /**
  996. Returns true if the passed object is an array or Array-like.
  997. Ember Array Protocol:
  998. - the object has an objectAt property
  999. - the object is a native Array
  1000. - the object is an Object, and has a length property
  1001. Unlike `Ember.typeOf` this method returns true even if the passed object is
  1002. not formally array but appears to be array-like (i.e. implements `Ember.Array`)
  1003. ```javascript
  1004. Ember.isArray(); // false
  1005. Ember.isArray([]); // true
  1006. Ember.isArray( Ember.ArrayProxy.create({ content: [] }) ); // true
  1007. ```
  1008. @method isArray
  1009. @for Ember
  1010. @param {Object} obj The object to test
  1011. @return {Boolean} true if the passed object is an array or Array-like
  1012. */
  1013. Ember.isArray = function(obj) {
  1014. if (!obj || obj.setInterval) { return false; }
  1015. if (Array.isArray && Array.isArray(obj)) { return true; }
  1016. if (Ember.Array && Ember.Array.detect(obj)) { return true; }
  1017. if ((obj.length !== undefined) && 'object'===typeof obj) { return true; }
  1018. return false;
  1019. };
  1020. /**
  1021. Forces the passed object to be part of an array. If the object is already
  1022. an array or array-like, returns the object. Otherwise adds the object to
  1023. an array. If obj is `null` or `undefined`, returns an empty array.
  1024. ```javascript
  1025. Ember.makeArray(); // []
  1026. Ember.makeArray(null); // []
  1027. Ember.makeArray(undefined); // []
  1028. Ember.makeArray('lindsay'); // ['lindsay']
  1029. Ember.makeArray([1,2,42]); // [1,2,42]
  1030. var controller = Ember.ArrayProxy.create({ content: [] });
  1031. Ember.makeArray(controller) === controller; // true
  1032. ```
  1033. @method makeArray
  1034. @for Ember
  1035. @param {Object} obj the object
  1036. @return {Array}
  1037. */
  1038. Ember.makeArray = function(obj) {
  1039. if (obj === null || obj === undefined) { return []; }
  1040. return Ember.isArray(obj) ? obj : [obj];
  1041. };
  1042. function canInvoke(obj, methodName) {
  1043. return !!(obj && typeof obj[methodName] === 'function');
  1044. }
  1045. /**
  1046. Checks to see if the `methodName` exists on the `obj`.
  1047. ```javascript
  1048. var foo = {bar: Ember.K, baz: null};
  1049. Ember.canInvoke(foo, 'bar'); // true
  1050. Ember.canInvoke(foo, 'baz'); // false
  1051. Ember.canInvoke(foo, 'bat'); // false
  1052. ```
  1053. @method canInvoke
  1054. @for Ember
  1055. @param {Object} obj The object to check for the method
  1056. @param {String} methodName The method name to check for
  1057. @return {Boolean}
  1058. */
  1059. Ember.canInvoke = canInvoke;
  1060. /**
  1061. Checks to see if the `methodName` exists on the `obj`,
  1062. and if it does, invokes it with the arguments passed.
  1063. ```javascript
  1064. var d = new Date('03/15/2013');
  1065. Ember.tryInvoke(d, 'getTime'); // 1363320000000
  1066. Ember.tryInvoke(d, 'setFullYear', [2014]); // 1394856000000
  1067. Ember.tryInvoke(d, 'noSuchMethod', [2014]); // undefined
  1068. ```
  1069. @method tryInvoke
  1070. @for Ember
  1071. @param {Object} obj The object to check for the method
  1072. @param {String} methodName The method name to check for
  1073. @param {Array} [args] The arguments to pass to the method
  1074. @return {*} the return value of the invoked method or undefined if it cannot be invoked
  1075. */
  1076. Ember.tryInvoke = function(obj, methodName, args) {
  1077. if (canInvoke(obj, methodName)) {
  1078. return obj[methodName].apply(obj, args || []);
  1079. }
  1080. };
  1081. // https://github.com/emberjs/ember.js/pull/1617
  1082. var needsFinallyFix = (function() {
  1083. var count = 0;
  1084. try{
  1085. try { }
  1086. finally {
  1087. count++;
  1088. throw new Error('needsFinallyFixTest');
  1089. }
  1090. } catch (e) {}
  1091. return count !== 1;
  1092. })();
  1093. /**
  1094. Provides try { } finally { } functionality, while working
  1095. around Safari's double finally bug.
  1096. ```javascript
  1097. var tryable = function() {
  1098. someResource.lock();
  1099. runCallback(); // May throw error.
  1100. };
  1101. var finalizer = function() {
  1102. someResource.unlock();
  1103. };
  1104. Ember.tryFinally(tryable, finalizer);
  1105. ```
  1106. @method tryFinally
  1107. @for Ember
  1108. @param {Function} tryable The function to run the try callback
  1109. @param {Function} finalizer The function to run the finally callback
  1110. @param {Object} [binding] The optional calling object. Defaults to 'this'
  1111. @return {*} The return value is the that of the finalizer,
  1112. unless that value is undefined, in which case it is the return value
  1113. of the tryable
  1114. */
  1115. if (needsFinallyFix) {
  1116. Ember.tryFinally = function(tryable, finalizer, binding) {
  1117. var result, finalResult, finalError;
  1118. binding = binding || this;
  1119. try {
  1120. result = tryable.call(binding);
  1121. } finally {
  1122. try {
  1123. finalResult = finalizer.call(binding);
  1124. } catch (e) {
  1125. finalError = e;
  1126. }
  1127. }
  1128. if (finalError) { throw finalError; }
  1129. return (finalResult === undefined) ? result : finalResult;
  1130. };
  1131. } else {
  1132. Ember.tryFinally = function(tryable, finalizer, binding) {
  1133. var result, finalResult;
  1134. binding = binding || this;
  1135. try {
  1136. result = tryable.call(binding);
  1137. } finally {
  1138. finalResult = finalizer.call(binding);
  1139. }
  1140. return (finalResult === undefined) ? result : finalResult;
  1141. };
  1142. }
  1143. /**
  1144. Provides try { } catch finally { } functionality, while working
  1145. around Safari's double finally bug.
  1146. ```javascript
  1147. var tryable = function() {
  1148. for (i=0, l=listeners.length; i<l; i++) {
  1149. listener = listeners[i];
  1150. beforeValues[i] = listener.before(name, time(), payload);
  1151. }
  1152. return callback.call(binding);
  1153. };
  1154. var catchable = function(e) {
  1155. payload = payload || {};
  1156. payload.exception = e;
  1157. };
  1158. var finalizer = function() {
  1159. for (i=0, l=listeners.length; i<l; i++) {
  1160. listener = listeners[i];
  1161. listener.after(name, time(), payload, beforeValues[i]);
  1162. }
  1163. };
  1164. Ember.tryCatchFinally(tryable, catchable, finalizer);
  1165. ```
  1166. @method tryCatchFinally
  1167. @for Ember
  1168. @param {Function} tryable The function to run the try callback
  1169. @param {Function} catchable The function to run the catchable callback
  1170. @param {Function} finalizer The function to run the finally callback
  1171. @param {Object} [binding] The optional calling object. Defaults to 'this'
  1172. @return {*} The return value is the that of the finalizer,
  1173. unless that value is undefined, in which case it is the return value
  1174. of the tryable.
  1175. */
  1176. if (needsFinallyFix) {
  1177. Ember.tryCatchFinally = function(tryable, catchable, finalizer, binding) {
  1178. var result, finalResult, finalError;
  1179. binding = binding || this;
  1180. try {
  1181. result = tryable.call(binding);
  1182. } catch(error) {
  1183. result = catchable.call(binding, error);
  1184. } finally {
  1185. try {
  1186. finalResult = finalizer.call(binding);
  1187. } catch (e) {
  1188. finalError = e;
  1189. }
  1190. }
  1191. if (finalError) { throw finalError; }
  1192. return (finalResult === undefined) ? result : finalResult;
  1193. };
  1194. } else {
  1195. Ember.tryCatchFinally = function(tryable, catchable, finalizer, binding) {
  1196. var result, finalResult;
  1197. binding = binding || this;
  1198. try {
  1199. result = tryable.call(binding);
  1200. } catch(error) {
  1201. result = catchable.call(binding, error);
  1202. } finally {
  1203. finalResult = finalizer.call(binding);
  1204. }
  1205. return (finalResult === undefined) ? result : finalResult;
  1206. };
  1207. }
  1208. // ........................................
  1209. // TYPING & ARRAY MESSAGING
  1210. //
  1211. var TYPE_MAP = {};
  1212. var t = "Boolean Number String Function Array Date RegExp Object".split(" ");
  1213. Ember.ArrayPolyfills.forEach.call(t, function(name) {
  1214. TYPE_MAP[ "[object " + name + "]" ] = name.toLowerCase();
  1215. });
  1216. var toString = Object.prototype.toString;
  1217. /**
  1218. Returns a consistent type for the passed item.
  1219. Use this instead of the built-in `typeof` to get the type of an item.
  1220. It will return the same result across all browsers and includes a bit
  1221. more detail. Here is what will be returned:
  1222. | Return Value | Meaning |
  1223. |---------------|------------------------------------------------------|
  1224. | 'string' | String primitive or String object. |
  1225. | 'number' | Number primitive or Number object. |
  1226. | 'boolean' | Boolean primitive or Boolean object. |
  1227. | 'null' | Null value |
  1228. | 'undefined' | Undefined value |
  1229. | 'function' | A function |
  1230. | 'array' | An instance of Array |
  1231. | 'regexp' | An instance of RegExp |
  1232. | 'date' | An instance of Date |
  1233. | 'class' | An Ember class (created using Ember.Object.extend()) |
  1234. | 'instance' | An Ember object instance |
  1235. | 'error' | An instance of the Error object |
  1236. | 'object' | A JavaScript object not inheriting from Ember.Object |
  1237. Examples:
  1238. ```javascript
  1239. Ember.typeOf(); // 'undefined'
  1240. Ember.typeOf(null); // 'null'
  1241. Ember.typeOf(undefined); // 'undefined'
  1242. Ember.typeOf('michael'); // 'string'
  1243. Ember.typeOf(new String('michael')); // 'string'
  1244. Ember.typeOf(101); // 'number'
  1245. Ember.typeOf(new Number(101)); // 'number'
  1246. Ember.typeOf(true); // 'boolean'
  1247. Ember.typeOf(new Boolean(true)); // 'boolean'
  1248. Ember.typeOf(Ember.makeArray); // 'function'
  1249. Ember.typeOf([1,2,90]); // 'array'
  1250. Ember.typeOf(/abc/); // 'regexp'
  1251. Ember.typeOf(new Date()); // 'date'
  1252. Ember.typeOf(Ember.Object.extend()); // 'class'
  1253. Ember.typeOf(Ember.Object.create()); // 'instance'
  1254. Ember.typeOf(new Error('teamocil')); // 'error'
  1255. // "normal" JavaScript object
  1256. Ember.typeOf({a: 'b'}); // 'object'
  1257. ```
  1258. @method typeOf
  1259. @for Ember
  1260. @param {Object} item the item to check
  1261. @return {String} the type
  1262. */
  1263. Ember.typeOf = function(item) {
  1264. var ret;
  1265. ret = (item === null || item === undefined) ? String(item) : TYPE_MAP[toString.call(item)] || 'object';
  1266. if (ret === 'function') {
  1267. if (Ember.Object && Ember.Object.detect(item)) ret = 'class';
  1268. } else if (ret === 'object') {
  1269. if (item instanceof Error) ret = 'error';
  1270. else if (Ember.Object && item instanceof Ember.Object) ret = 'instance';
  1271. else if (item instanceof Date) ret = 'date';
  1272. }
  1273. return ret;
  1274. };
  1275. /**
  1276. Convenience method to inspect an object. This method will attempt to
  1277. convert the object into a useful string description.
  1278. It is a pretty simple implementation. If you want something more robust,
  1279. use something like JSDump: https://github.com/NV/jsDump
  1280. @method inspect
  1281. @for Ember
  1282. @param {Object} obj The object you want to inspect.
  1283. @return {String} A description of the object
  1284. */
  1285. Ember.inspect = function(obj) {
  1286. var type = Ember.typeOf(obj);
  1287. if (type === 'array') {
  1288. return '[' + obj + ']';
  1289. }
  1290. if (type !== 'object') {
  1291. return obj + '';
  1292. }
  1293. var v, ret = [];
  1294. for(var key in obj) {
  1295. if (obj.hasOwnProperty(key)) {
  1296. v = obj[key];
  1297. if (v === 'toString') { continue; } // ignore useless items
  1298. if (Ember.typeOf(v) === 'function') { v = "function() { ... }"; }
  1299. ret.push(key + ": " + v);
  1300. }
  1301. }
  1302. return "{" + ret.join(", ") + "}";
  1303. };
  1304. })();
  1305. (function() {
  1306. // Ember.tryCatchFinally
  1307. /**
  1308. The purpose of the Ember Instrumentation module is
  1309. to provide efficient, general-purpose instrumentation
  1310. for Ember.
  1311. Subscribe to a listener by using `Ember.subscribe`:
  1312. ```javascript
  1313. Ember.subscribe("render", {
  1314. before: function(name, timestamp, payload) {
  1315. },
  1316. after: function(name, timestamp, payload) {
  1317. }
  1318. });
  1319. ```
  1320. If you return a value from the `before` callback, that same
  1321. value will be passed as a fourth parameter to the `after`
  1322. callback.
  1323. Instrument a block of code by using `Ember.instrument`:
  1324. ```javascript
  1325. Ember.instrument("render.handlebars", payload, function() {
  1326. // rendering logic
  1327. }, binding);
  1328. ```
  1329. Event names passed to `Ember.instrument` are namespaced
  1330. by periods, from more general to more specific. Subscribers
  1331. can listen for events by whatever level of granularity they
  1332. are interested in.
  1333. In the above example, the event is `render.handlebars`,
  1334. and the subscriber listened for all events beginning with
  1335. `render`. It would receive callbacks for events named
  1336. `render`, `render.handlebars`, `render.container`, or
  1337. even `render.handlebars.layout`.
  1338. @class Instrumentation
  1339. @namespace Ember
  1340. @static
  1341. */
  1342. Ember.Instrumentation = {};
  1343. var subscribers = [], cache = {};
  1344. var populateListeners = function(name) {
  1345. var listeners = [], subscriber;
  1346. for (var i=0, l=subscribers.length; i<l; i++) {
  1347. subscriber = subscribers[i];
  1348. if (subscriber.regex.test(name)) {
  1349. listeners.push(subscriber.object);
  1350. }
  1351. }
  1352. cache[name] = listeners;
  1353. return listeners;
  1354. };
  1355. var time = (function() {
  1356. var perf = 'undefined' !== typeof window ? window.performance || {} : {};
  1357. var fn = perf.now || perf.mozNow || perf.webkitNow || perf.msNow || perf.oNow;
  1358. // fn.bind will be available in all the browsers that support the advanced window.performance... ;-)
  1359. return fn ? fn.bind(perf) : function() { return +new Date(); };
  1360. })();
  1361. /**
  1362. Notifies event's subscribers, calls `before` and `after` hooks.
  1363. @method instrument
  1364. @namespace Ember.Instrumentation
  1365. @param {String} [name] Namespaced event name.
  1366. @param {Object} payload
  1367. @param {Function} callback Function that you're instrumenting.
  1368. @param {Object} binding Context that instrument function is called with.
  1369. */
  1370. Ember.Instrumentation.instrument = function(name, payload, callback, binding) {
  1371. var listeners = cache[name], timeName, ret;
  1372. if (Ember.STRUCTURED_PROFILE) {
  1373. timeName = name + ": " + payload.object;
  1374. console.time(timeName);
  1375. }
  1376. if (!listeners) {
  1377. listeners = populateListeners(name);
  1378. }
  1379. if (listeners.length === 0) {
  1380. ret = callback.call(binding);
  1381. if (Ember.STRUCTURED_PROFILE) { console.timeEnd(timeName); }
  1382. return ret;
  1383. }
  1384. var beforeValues = [], listener, i, l;
  1385. function tryable() {
  1386. for (i=0, l=listeners.length; i<l; i++) {
  1387. listener = listeners[i];
  1388. beforeValues[i] = listener.before(name, time(), payload);
  1389. }
  1390. return callback.call(binding);
  1391. }
  1392. function catchable(e) {
  1393. payload = payload || {};
  1394. payload.exception = e;
  1395. }
  1396. function finalizer() {
  1397. for (i=0, l=listeners.length; i<l; i++) {
  1398. listener = listeners[i];
  1399. listener.after(name, time(), payload, beforeValues[i]);
  1400. }
  1401. if (Ember.STRUCTURED_PROFILE) {
  1402. console.timeEnd(timeName);
  1403. }
  1404. }
  1405. return Ember.tryCatchFinally(tryable, catchable, finalizer);
  1406. };
  1407. /**
  1408. Subscribes to a particular event or instrumented block of code.
  1409. @method subscribe
  1410. @namespace Ember.Instrumentation
  1411. @param {String} [pattern] Namespaced event name.
  1412. @param {Object} [object] Before and After hooks.
  1413. @return {Subscriber}
  1414. */
  1415. Ember.Instrumentation.subscribe = function(pattern, object) {
  1416. var paths = pattern.split("."), path, regex = [];
  1417. for (var i=0, l=paths.length; i<l; i++) {
  1418. path = paths[i];
  1419. if (path === "*") {
  1420. regex.push("[^\\.]*");
  1421. } else {
  1422. regex.push(path);
  1423. }
  1424. }
  1425. regex = regex.join("\\.");
  1426. regex = regex + "(\\..*)?";
  1427. var subscriber = {
  1428. pattern: pattern,
  1429. regex: new RegExp("^" + regex + "$"),
  1430. object: object
  1431. };
  1432. subscribers.push(subscriber);
  1433. cache = {};
  1434. return subscriber;
  1435. };
  1436. /**
  1437. Unsubscribes from a particular event or instrumented block of code.
  1438. @method unsubscribe
  1439. @namespace Ember.Instrumentation
  1440. @param {Object} [subscriber]
  1441. */
  1442. Ember.Instrumentation.unsubscribe = function(subscriber) {
  1443. var index;
  1444. for (var i=0, l=subscribers.length; i<l; i++) {
  1445. if (subscribers[i] === subscriber) {
  1446. index = i;
  1447. }
  1448. }
  1449. subscribers.splice(index, 1);
  1450. cache = {};
  1451. };
  1452. /**
  1453. Resets `Ember.Instrumentation` by flushing list of subscribers.
  1454. @method reset
  1455. @namespace Ember.Instrumentation
  1456. */
  1457. Ember.Instrumentation.reset = function() {
  1458. subscribers = [];
  1459. cache = {};
  1460. };
  1461. Ember.instrument = Ember.Instrumentation.instrument;
  1462. Ember.subscribe = Ember.Instrumentation.subscribe;
  1463. })();
  1464. (function() {
  1465. var map, forEach, indexOf, splice, filter;
  1466. map = Array.prototype.map || Ember.ArrayPolyfills.map;
  1467. forEach = Array.prototype.forEach || Ember.ArrayPolyfills.forEach;
  1468. indexOf = Array.prototype.indexOf || Ember.ArrayPolyfills.indexOf;
  1469. filter = Array.prototype.filter || Ember.ArrayPolyfills.filter;
  1470. splice = Array.prototype.splice;
  1471. /**
  1472. * Defines some convenience methods for working with Enumerables.
  1473. * `Ember.EnumerableUtils` uses `Ember.ArrayPolyfills` when necessary.
  1474. *
  1475. * @class EnumerableUtils
  1476. * @namespace Ember
  1477. * @static
  1478. * */
  1479. var utils = Ember.EnumerableUtils = {
  1480. /**
  1481. * Calls the map function on the passed object with a specified callback. This
  1482. * uses `Ember.ArrayPolyfill`'s-map method when necessary.
  1483. *
  1484. * @method map
  1485. * @param {Object} obj The object that should be mapped
  1486. * @param {Function} callback The callback to execute
  1487. * @param {Object} thisArg Value to use as this when executing *callback*
  1488. *
  1489. * @return {Array} An array of mapped values.
  1490. */
  1491. map: function(obj, callback, thisArg) {
  1492. return obj.map ? obj.map.call(obj, callback, thisArg) : map.call(obj, callback, thisArg);
  1493. },
  1494. /**
  1495. * Calls the forEach function on the passed object with a specified callback. This
  1496. * uses `Ember.ArrayPolyfill`'s-forEach method when necessary.
  1497. *
  1498. * @method forEach
  1499. * @param {Object} obj The object to call forEach on
  1500. * @param {Function} callback The callback to execute
  1501. * @param {Object} thisArg Value to use as this when executing *callback*
  1502. *
  1503. */
  1504. forEach: function(obj, callback, thisArg) {
  1505. return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : forEach.call(obj, callback, thisArg);
  1506. },
  1507. /**
  1508. * Calls the filter function on the passed object with a specified callback. This
  1509. * uses `Ember.ArrayPolyfill`'s-filter method when necessary.
  1510. *
  1511. * @method filter
  1512. * @param {Object} obj The object to call filter on
  1513. * @param {Function} callback The callback to execute
  1514. * @param {Object} thisArg Value to use as this when executing *callback*
  1515. *
  1516. * @return {Array} An array containing the filtered values
  1517. */
  1518. filter: function(obj, callback, thisArg) {
  1519. return obj.filter ? obj.filter.call(obj, callback, thisArg) : filter.call(obj, callback, thisArg);
  1520. },
  1521. /**
  1522. * Calls the indexOf function on the passed object with a specified callback. This
  1523. * uses `Ember.ArrayPolyfill`'s-indexOf method when necessary.
  1524. *
  1525. * @method indexOf
  1526. * @param {Object} obj The object to call indexOn on
  1527. * @param {Function} callback The callback to execute
  1528. * @param {Object} index The index to start searching from
  1529. *
  1530. */
  1531. indexOf: function(obj, element, index) {
  1532. return obj.indexOf ? obj.indexOf.call(obj, element, index) : indexOf.call(obj, element, index);
  1533. },
  1534. /**
  1535. * Returns an array of indexes of the first occurrences of the passed elements
  1536. * on the passed object.
  1537. *
  1538. * ```javascript
  1539. * var array = [1, 2, 3, 4, 5];
  1540. * Ember.EnumerableUtils.indexesOf(array, [2, 5]); // [1, 4]
  1541. *
  1542. * var fubar = "Fubarr";
  1543. * Ember.EnumerableUtils.indexesOf(fubar, ['b', 'r']); // [2, 4]
  1544. * ```
  1545. *
  1546. * @method indexesOf
  1547. * @param {Object} obj The object to check for element indexes
  1548. * @param {Array} elements The elements to search for on *obj*
  1549. *
  1550. * @return {Array} An array of indexes.
  1551. *
  1552. */
  1553. indexesOf: function(obj, elements) {
  1554. return elements === undefined ? [] : utils.map(elements, function(item) {
  1555. return utils.indexOf(obj, item);
  1556. });
  1557. },
  1558. /**
  1559. * Adds an object to an array. If the array already includes the object this
  1560. * method has no effect.
  1561. *
  1562. * @method addObject
  1563. * @param {Array} array The array the passed item should be added to
  1564. * @param {Object} item The item to add to the passed array
  1565. *
  1566. * @return 'undefined'
  1567. */
  1568. addObject: function(array, item) {
  1569. var index = utils.indexOf(array, item);
  1570. if (index === -1) { array.push(item); }
  1571. },
  1572. /**
  1573. * Removes an object from an array. If the array does not contain the passed
  1574. * object this method has no effect.
  1575. *
  1576. * @method removeObject
  1577. * @param {Array} array The array to remove the item from.
  1578. * @param {Object} item The item to remove from the passed array.
  1579. *
  1580. * @return 'undefined'
  1581. */
  1582. removeObject: function(array, item) {
  1583. var index = utils.indexOf(array, item);
  1584. if (index !== -1) { array.splice(index, 1); }
  1585. },
  1586. _replace: function(array, idx, amt, objects) {
  1587. var args = [].concat(objects), chunk, ret = [],
  1588. // https://code.google.com/p/chromium/issues/detail?id=56588
  1589. size = 60000, start = idx, ends = amt, count;
  1590. while (args.length) {
  1591. count = ends > size ? size : ends;
  1592. if (count <= 0) { count = 0; }
  1593. chunk = args.splice(0, size);
  1594. chunk = [start, count].concat(chunk);
  1595. start += size;
  1596. ends -= count;
  1597. ret = ret.concat(splice.apply(array, chunk));
  1598. }
  1599. return ret;
  1600. },
  1601. /**
  1602. * Replaces objects in an array with the passed objects.
  1603. *
  1604. * ```javascript
  1605. * var array = [1,2,3];
  1606. * Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5]
  1607. *
  1608. * var array = [1,2,3];
  1609. * Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3]
  1610. *
  1611. * var array = [1,2,3];
  1612. * Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5]
  1613. * ```
  1614. *
  1615. * @method replace
  1616. * @param {Array} array The array the objects should be inserted into.
  1617. * @param {Number} idx Starting index in the array to replace. If *idx* >=
  1618. * length, then append to the end of the array.
  1619. * @param {Number} amt Number of elements that should be remove from the array,
  1620. * starting at *idx*
  1621. * @param {Array} objects An array of zero or more objects that should be
  1622. * inserted into the array at *idx*
  1623. *
  1624. * @return {Array} The changed array.
  1625. */
  1626. replace: function(array, idx, amt, objects) {
  1627. if (array.replace) {
  1628. return array.replace(idx, amt, objects);
  1629. } else {
  1630. return utils._replace(array, idx, amt, objects);
  1631. }
  1632. },
  1633. /**
  1634. * Calculates the intersection of two arrays. This method returns a new array
  1635. * filled with the records that the two passed arrays share with each other.
  1636. * If there is no intersection, an empty array will be returned.
  1637. *
  1638. * ```javascript
  1639. * var array1 = [1, 2, 3, 4, 5];
  1640. * var array2 = [1, 3, 5, 6, 7];
  1641. *
  1642. * Ember.EnumerableUtils.intersection(array1, array2); // [1, 3, 5]
  1643. *
  1644. * var array1 = [1, 2, 3];
  1645. * var array2 = [4, 5, 6];
  1646. *
  1647. * Ember.EnumerableUtils.intersection(array1, array2); // []
  1648. * ```
  1649. *
  1650. * @method intersection
  1651. * @param {Array} array1 The first array
  1652. * @param {Array} array2 The second array
  1653. *
  1654. * @return {Array} The intersection of the two passed arrays.
  1655. */
  1656. intersection: function(array1, array2) {
  1657. var intersection = [];
  1658. utils.forEach(array1, function(element) {
  1659. if (utils.indexOf(array2, element) >= 0) {
  1660. intersection.push(element);
  1661. }
  1662. });
  1663. return intersection;
  1664. }
  1665. };
  1666. })();
  1667. (function() {
  1668. /**
  1669. @module ember-metal
  1670. */
  1671. var META_KEY = Ember.META_KEY, get;
  1672. var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER;
  1673. var IS_GLOBAL_PATH = /^([A-Z$]|([0-9][A-Z$])).*[\.\*]/;
  1674. var HAS_THIS = /^this[\.\*]/;
  1675. var FIRST_KEY = /^([^\.\*]+)/;
  1676. // ..........................................................
  1677. // GET AND SET
  1678. //
  1679. // If we are on a platform that supports accessors we can use those.
  1680. // Otherwise simulate accessors by looking up the property directly on the
  1681. // object.
  1682. /**
  1683. Gets the value of a property on an object. If the property is computed,
  1684. the function will be invoked. If the property is not defined but the
  1685. object implements the `unknownProperty` method then that will be invoked.
  1686. If you plan to run on IE8 and older browsers then you should use this
  1687. method anytime you want to retrieve a property on an object that you don't
  1688. know for sure is private. (Properties beginning with an underscore '_'
  1689. are considered private.)
  1690. On all newer browsers, you only need to use this method to retrieve
  1691. properties if the property might not be defined on the object and you want
  1692. to respect the `unknownProperty` handler. Otherwise you can ignore this
  1693. method.
  1694. Note that if the object itself is `undefined`, this method will throw
  1695. an error.
  1696. @method get
  1697. @for Ember
  1698. @param {Object} obj The object to retrieve from.
  1699. @param {String} keyName The property key to retrieve
  1700. @return {Object} the property value or `null`.
  1701. */
  1702. get = function get(obj, keyName) {
  1703. // Helpers that operate with 'this' within an #each
  1704. if (keyName === '') {
  1705. return obj;
  1706. }
  1707. if (!keyName && 'string'===typeof obj) {
  1708. keyName = obj;
  1709. obj = null;
  1710. }
  1711. Ember.assert("Cannot call get with "+ keyName +" key.", !!keyName);
  1712. Ember.assert("Cannot call get with '"+ keyName +"' on an undefined object.", obj !== undefined);
  1713. if (obj === null || keyName.indexOf('.') !== -1) {
  1714. return getPath(obj, keyName);
  1715. }
  1716. var meta = obj[META_KEY], desc = meta && meta.descs[keyName], ret;
  1717. if (desc) {
  1718. return desc.get(obj, keyName);
  1719. } else {
  1720. if (MANDATORY_SETTER && meta && meta.watching[keyName] > 0) {
  1721. ret = meta.values[keyName];
  1722. } else {
  1723. ret = obj[keyName];
  1724. }
  1725. if (ret === undefined &&
  1726. 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) {
  1727. return obj.unknownProperty(keyName);
  1728. }
  1729. return ret;
  1730. }
  1731. };
  1732. // Currently used only by Ember Data tests
  1733. if (Ember.config.overrideAccessors) {
  1734. Ember.get = get;
  1735. Ember.config.overrideAccessors();
  1736. get = Ember.get;
  1737. }
  1738. /**
  1739. Normalizes a target/path pair to reflect that actual target/path that should
  1740. be observed, etc. This takes into account passing in global property
  1741. paths (i.e. a path beginning with a captial letter not defined on the
  1742. target) and * separators.
  1743. @private
  1744. @method normalizeTuple
  1745. @for Ember
  1746. @param {Object} target The current target. May be `null`.
  1747. @param {String} path A path on the target or a global property path.
  1748. @return {Array} a temporary array with the normalized target/path pair.
  1749. */
  1750. var normalizeTuple = Ember.normalizeTuple = function(target, path) {
  1751. var hasThis = HAS_THIS.test(path),
  1752. isGlobal = !hasThis && IS_GLOBAL_PATH.test(path),
  1753. key;
  1754. if (!target || isGlobal) target = Ember.lookup;
  1755. if (hasThis) path = path.slice(5);
  1756. if (target === Ember.lookup) {
  1757. key = path.match(FIRST_KEY)[0];
  1758. target = get(target, key);
  1759. path = path.slice(key.length+1);
  1760. }
  1761. // must return some kind of path to be valid else other things will break.
  1762. if (!path || path.length===0) throw new Ember.Error('Path cannot be empty');
  1763. return [ target, path ];
  1764. };
  1765. var getPath = Ember._getPath = function(root, path) {
  1766. var hasThis, parts, tuple, idx, len;
  1767. // If there is no root and path is a key name, return that
  1768. // property from the global object.
  1769. // E.g. get('Ember') -> Ember
  1770. if (root === null && path.indexOf('.') === -1) { return get(Ember.lookup, path); }
  1771. // detect complicated paths and normalize them
  1772. hasThis = HAS_THIS.test(path);
  1773. if (!root || hasThis) {
  1774. tuple = normalizeTuple(root, path);
  1775. root = tuple[0];
  1776. path = tuple[1];
  1777. tuple.length = 0;
  1778. }
  1779. parts = path.split(".");
  1780. len = parts.length;
  1781. for (idx = 0; root != null && idx < len; idx++) {
  1782. root = get(root, parts[idx], true);
  1783. if (root && root.isDestroyed) { return undefined; }
  1784. }
  1785. return root;
  1786. };
  1787. Ember.getWithDefault = function(root, key, defaultValue) {
  1788. var value = get(root, key);
  1789. if (value === undefined) { return defaultValue; }
  1790. return value;
  1791. };
  1792. Ember.get = get;
  1793. })();
  1794. (function() {
  1795. /**
  1796. @module ember-metal
  1797. */
  1798. var o_create = Ember.create,
  1799. metaFor = Ember.meta,
  1800. META_KEY = Ember.META_KEY,
  1801. a_slice = [].slice,
  1802. /* listener flags */
  1803. ONCE = 1, SUSPENDED = 2;
  1804. /*
  1805. The event system uses a series of nested hashes to store listeners on an
  1806. object. When a listener is registered, or when an event arrives, these
  1807. hashes are consulted to determine which target and action pair to invoke.
  1808. The hashes are stored in the object's meta hash, and look like this:
  1809. // Object's meta hash
  1810. {
  1811. listeners: { // variable name: `listenerSet`
  1812. "foo:changed": [ // variable name: `actions`
  1813. target, method, flags
  1814. ]
  1815. }
  1816. }
  1817. */
  1818. function indexOf(array, target, method) {
  1819. var index = -1;
  1820. for (var i = 0, l = array.length; i < l; i += 3) {
  1821. if (target === array[i] && method === array[i+1]) { index = i; break; }
  1822. }
  1823. return index;
  1824. }
  1825. function actionsFor(obj, eventName) {
  1826. var meta = metaFor(obj, true),
  1827. actions;
  1828. if (!meta.listeners) { meta.listeners = {}; }
  1829. if (!meta.hasOwnProperty('listeners')) {
  1830. // setup inherited copy of the listeners object
  1831. meta.listeners = o_create(meta.listeners);
  1832. }
  1833. actions = meta.listeners[eventName];
  1834. // if there are actions, but the eventName doesn't exist in our listeners, then copy them from the prototype
  1835. if (actions && !meta.listeners.hasOwnProperty(eventName)) {
  1836. actions = meta.listeners[eventName] = meta.listeners[eventName].slice();
  1837. } else if (!actions) {
  1838. actions = meta.listeners[eventName] = [];
  1839. }
  1840. return actions;
  1841. }
  1842. function actionsUnion(obj, eventName, otherActions) {
  1843. var meta = obj[META_KEY],
  1844. actions = meta && meta.listeners && meta.listeners[eventName];
  1845. if (!actions) { return; }
  1846. for (var i = actions.length - 3; i >= 0; i -= 3) {
  1847. var target = actions[i],
  1848. method = actions[i+1],
  1849. flags = actions[i+2],
  1850. actionIndex = indexOf(otherActions, target, method);
  1851. if (actionIndex === -1) {
  1852. otherActions.push(target, method, flags);
  1853. }
  1854. }
  1855. }
  1856. function actionsDiff(obj, eventName, otherActions) {
  1857. var meta = obj[META_KEY],
  1858. actions = meta && meta.listeners && meta.listeners[eventName],
  1859. diffActions = [];
  1860. if (!actions) { return; }
  1861. for (var i = actions.length - 3; i >= 0; i -= 3) {
  1862. var target = actions[i],
  1863. method = actions[i+1],
  1864. flags = actions[i+2],
  1865. actionIndex = indexOf(otherActions, target, method);
  1866. if (actionIndex !== -1) { continue; }
  1867. otherActions.push(target, method, flags);
  1868. diffActions.push(target, method, flags);
  1869. }
  1870. return diffActions;
  1871. }
  1872. /**
  1873. Add an event listener
  1874. @method addListener
  1875. @for Ember
  1876. @param obj
  1877. @param {String} eventName
  1878. @param {Object|Function} targetOrMethod A target object or a function
  1879. @param {Function|String} method A function or the name of a function to be called on `target`
  1880. @param {Boolean} once A flag whether a function should only be called once
  1881. */
  1882. function addListener(obj, eventName, target, method, once) {
  1883. Ember.assert("You must pass at least an object and event name to Ember.addListener", !!obj && !!eventName);
  1884. if (!method && 'function' === typeof target) {
  1885. method = target;
  1886. target = null;
  1887. }
  1888. var actions = actionsFor(obj, eventName),
  1889. actionIndex = indexOf(actions, target, method),
  1890. flags = 0;
  1891. if (once) flags |= ONCE;
  1892. if (actionIndex !== -1) { return; }
  1893. actions.push(target, method, flags);
  1894. if ('function' === typeof obj.didAddListener) {
  1895. obj.didAddListener(eventName, target, method);
  1896. }
  1897. }
  1898. /**
  1899. Remove an event listener
  1900. Arguments should match those passed to `Ember.addListener`.
  1901. @method removeListener
  1902. @for Ember
  1903. @param obj
  1904. @param {String} eventName
  1905. @param {Object|Function} targetOrMethod A target object or a function
  1906. @param {Function|String} method A function or the name of a function to be called on `target`
  1907. */
  1908. function removeListener(obj, eventName, target, method) {
  1909. Ember.assert("You must pass at least an object and event name to Ember.removeListener", !!obj && !!eventName);
  1910. if (!method && 'function' === typeof target) {
  1911. method = target;
  1912. target = null;
  1913. }
  1914. function _removeListener(target, method) {
  1915. var actions = actionsFor(obj, eventName),
  1916. actionIndex = indexOf(actions, target, method);
  1917. // action doesn't exist, give up silently
  1918. if (actionIndex === -1) { return; }
  1919. actions.splice(actionIndex, 3);
  1920. if ('function' === typeof obj.didRemoveListener) {
  1921. obj.didRemoveListener(eventName, target, method);
  1922. }
  1923. }
  1924. if (method) {
  1925. _removeListener(target, method);
  1926. } else {
  1927. var meta = obj[META_KEY],
  1928. actions = meta && meta.listeners && meta.listeners[eventName];
  1929. if (!actions) { return; }
  1930. for (var i = actions.length - 3; i >= 0; i -= 3) {
  1931. _removeListener(actions[i], actions[i+1]);
  1932. }
  1933. }
  1934. }
  1935. /**
  1936. Suspend listener during callback.
  1937. This should only be used by the target of the event listener
  1938. when it is taking an action that would cause the event, e.g.
  1939. an object might suspend its property change listener while it is
  1940. setting that property.
  1941. @private
  1942. @method suspendListener
  1943. @for Ember
  1944. @param obj
  1945. @param {String} eventName
  1946. @param {Object|Function} targetOrMethod A target object or a function
  1947. @param {Function|String} method A function or the name of a function to be called on `target`
  1948. @param {Function} callback
  1949. */
  1950. function suspendListener(obj, eventName, target, method, callback) {
  1951. if (!method && 'function' === typeof target) {
  1952. method = target;
  1953. target = null;
  1954. }
  1955. var actions = actionsFor(obj, eventName),
  1956. actionIndex = indexOf(actions, target, method);
  1957. if (actionIndex !== -1) {
  1958. actions[actionIndex+2] |= SUSPENDED; // mark the action as suspended
  1959. }
  1960. function tryable() { return callback.call(target); }
  1961. function finalizer() { if (actionIndex !== -1) { actions[actionIndex+2] &= ~SUSPENDED; } }
  1962. return Ember.tryFinally(tryable, finalizer);
  1963. }
  1964. /**
  1965. Suspends multiple listeners during a callback.
  1966. @private
  1967. @method suspendListeners
  1968. @for Ember
  1969. @param obj
  1970. @param {Array} eventName Array of event names
  1971. @param {Object|Function} targetOrMethod A target object or a function
  1972. @param {Function|String} method A function or the name of a function to be called on `target`
  1973. @param {Function} callback
  1974. */
  1975. function suspendListeners(obj, eventNames, target, method, callback) {
  1976. if (!method && 'function' === typeof target) {
  1977. method = target;
  1978. target = null;
  1979. }
  1980. var suspendedActions = [],
  1981. actionsList = [],
  1982. eventName, actions, i, l;
  1983. for (i=0, l=eventNames.length; i<l; i++) {
  1984. eventName = eventNames[i];
  1985. actions = actionsFor(obj, eventName);
  1986. var actionIndex = indexOf(actions, target, method);
  1987. if (actionIndex !== -1) {
  1988. actions[actionIndex+2] |= SUSPENDED;
  1989. suspendedActions.push(actionIndex);
  1990. actionsList.push(actions);
  1991. }
  1992. }
  1993. function tryable() { return callback.call(target); }
  1994. function finalizer() {
  1995. for (var i = 0, l = suspendedActions.length; i < l; i++) {
  1996. var actionIndex = suspendedActions[i];
  1997. actionsList[i][actionIndex+2] &= ~SUSPENDED;
  1998. }
  1999. }
  2000. return Ember.tryFinally(tryable, finalizer);
  2001. }
  2002. /**
  2003. Return a list of currently watched events
  2004. @private
  2005. @method watchedEvents
  2006. @for Ember
  2007. @param obj
  2008. */
  2009. function watchedEvents(obj) {
  2010. var listeners = obj[META_KEY].listeners, ret = [];
  2011. if (listeners) {
  2012. for(var eventName in listeners) {
  2013. if (listeners[eventName]) { ret.push(eventName); }
  2014. }
  2015. }
  2016. return ret;
  2017. }
  2018. /**
  2019. Send an event. The execution of suspended listeners
  2020. is skipped, and once listeners are removed. A listener without
  2021. a target is executed on the passed object. If an array of actions
  2022. is not passed, the actions stored on the passed object are invoked.
  2023. @method sendEvent
  2024. @for Ember
  2025. @param obj
  2026. @param {String} eventName
  2027. @param {Array} params Optional parameters for each listener.
  2028. @param {Array} actions Optional array of actions (listeners).
  2029. @return true
  2030. */
  2031. function sendEvent(obj, eventName, params, actions) {
  2032. // first give object a chance to handle it
  2033. if (obj !== Ember && 'function' === typeof obj.sendEvent) {
  2034. obj.sendEvent(eventName, params);
  2035. }
  2036. if (!actions) {
  2037. var meta = obj[META_KEY];
  2038. actions = meta && meta.listeners && meta.listeners[eventName];
  2039. }
  2040. if (!actions) { return; }
  2041. for (var i = actions.length - 3; i >= 0; i -= 3) { // looping in reverse for once listeners
  2042. var target = actions[i], method = actions[i+1], flags = actions[i+2];
  2043. if (!method) { continue; }
  2044. if (flags & SUSPENDED) { continue; }
  2045. if (flags & ONCE) { removeListener(obj, eventName, target, method); }
  2046. if (!target) { target = obj; }
  2047. if ('string' === typeof method) { method = target[method]; }
  2048. if (params) {
  2049. method.apply(target, params);
  2050. } else {
  2051. method.call(target);
  2052. }
  2053. }
  2054. return true;
  2055. }
  2056. /**
  2057. @private
  2058. @method hasListeners
  2059. @for Ember
  2060. @param obj
  2061. @param {String} eventName
  2062. */
  2063. function hasListeners(obj, eventName) {
  2064. var meta = obj[META_KEY],
  2065. actions = meta && meta.listeners && meta.listeners[eventName];
  2066. return !!(actions && actions.length);
  2067. }
  2068. /**
  2069. @private
  2070. @method listenersFor
  2071. @for Ember
  2072. @param obj
  2073. @param {String} eventName
  2074. */
  2075. function listenersFor(obj, eventName) {
  2076. var ret = [];
  2077. var meta = obj[META_KEY],
  2078. actions = meta && meta.listeners && meta.listeners[eventName];
  2079. if (!actions) { return ret; }
  2080. for (var i = 0, l = actions.length; i < l; i += 3) {
  2081. var target = actions[i],
  2082. method = actions[i+1];
  2083. ret.push([target, method]);
  2084. }
  2085. return ret;
  2086. }
  2087. /**
  2088. Define a property as a function that should be executed when
  2089. a specified event or events are triggered.
  2090. ``` javascript
  2091. var Job = Ember.Object.extend({
  2092. logCompleted: Ember.on('completed', function(){
  2093. console.log('Job completed!');
  2094. })
  2095. });
  2096. var job = Job.create();
  2097. Ember.sendEvent(job, 'completed'); // Logs "Job completed!"
  2098. ```
  2099. @method on
  2100. @for Ember
  2101. @param {String} eventNames*
  2102. @param {Function} func
  2103. @return func
  2104. */
  2105. Ember.on = function(){
  2106. var func = a_slice.call(arguments, -1)[0],
  2107. events = a_slice.call(arguments, 0, -1);
  2108. func.__ember_listens__ = events;
  2109. return func;
  2110. };
  2111. Ember.addListener = addListener;
  2112. Ember.removeListener = removeListener;
  2113. Ember._suspendListener = suspendListener;
  2114. Ember._suspendListeners = suspendListeners;
  2115. Ember.sendEvent = sendEvent;
  2116. Ember.hasListeners = hasListeners;
  2117. Ember.watchedEvents = watchedEvents;
  2118. Ember.listenersFor = listenersFor;
  2119. Ember.listenersDiff = actionsDiff;
  2120. Ember.listenersUnion = actionsUnion;
  2121. })();
  2122. (function() {
  2123. var guidFor = Ember.guidFor,
  2124. sendEvent = Ember.sendEvent;
  2125. /*
  2126. this.observerSet = {
  2127. [senderGuid]: { // variable name: `keySet`
  2128. [keyName]: listIndex
  2129. }
  2130. },
  2131. this.observers = [
  2132. {
  2133. sender: obj,
  2134. keyName: keyName,
  2135. eventName: eventName,
  2136. listeners: [
  2137. [target, method, flags]
  2138. ]
  2139. },
  2140. ...
  2141. ]
  2142. */
  2143. var ObserverSet = Ember._ObserverSet = function() {
  2144. this.clear();
  2145. };
  2146. ObserverSet.prototype.add = function(sender, keyName, eventName) {
  2147. var observerSet = this.observerSet,
  2148. observers = this.observers,
  2149. senderGuid = guidFor(sender),
  2150. keySet = observerSet[senderGuid],
  2151. index;
  2152. if (!keySet) {
  2153. observerSet[senderGuid] = keySet = {};
  2154. }
  2155. index = keySet[keyName];
  2156. if (index === undefined) {
  2157. index = observers.push({
  2158. sender: sender,
  2159. keyName: keyName,
  2160. eventName: eventName,
  2161. listeners: []
  2162. }) - 1;
  2163. keySet[keyName] = index;
  2164. }
  2165. return observers[index].listeners;
  2166. };
  2167. ObserverSet.prototype.flush = function() {
  2168. var observers = this.observers, i, len, observer, sender;
  2169. this.clear();
  2170. for (i=0, len=observers.length; i < len; ++i) {
  2171. observer = observers[i];
  2172. sender = observer.sender;
  2173. if (sender.isDestroying || sender.isDestroyed) { continue; }
  2174. sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners);
  2175. }
  2176. };
  2177. ObserverSet.prototype.clear = function() {
  2178. this.observerSet = {};
  2179. this.observers = [];
  2180. };
  2181. })();
  2182. (function() {
  2183. var META_KEY = Ember.META_KEY,
  2184. guidFor = Ember.guidFor,
  2185. tryFinally = Ember.tryFinally,
  2186. sendEvent = Ember.sendEvent,
  2187. listenersUnion = Ember.listenersUnion,
  2188. listenersDiff = Ember.listenersDiff,
  2189. ObserverSet = Ember._ObserverSet,
  2190. beforeObserverSet = new ObserverSet(),
  2191. observerSet = new ObserverSet(),
  2192. deferred = 0;
  2193. // ..........................................................
  2194. // PROPERTY CHANGES
  2195. //
  2196. /**
  2197. This function is called just before an object property is about to change.
  2198. It will notify any before observers and prepare caches among other things.
  2199. Normally you will not need to call this method directly but if for some
  2200. reason you can't directly watch a property you can invoke this method
  2201. manually along with `Ember.propertyDidChange()` which you should call just
  2202. after the property value changes.
  2203. @method propertyWillChange
  2204. @for Ember
  2205. @param {Object} obj The object with the property that will change
  2206. @param {String} keyName The property key (or path) that will change.
  2207. @return {void}
  2208. */
  2209. function propertyWillChange(obj, keyName) {
  2210. var m = obj[META_KEY],
  2211. watching = (m && m.watching[keyName] > 0) || keyName === 'length',
  2212. proto = m && m.proto,
  2213. desc = m && m.descs[keyName];
  2214. if (!watching) { return; }
  2215. if (proto === obj) { return; }
  2216. if (desc && desc.willChange) { desc.willChange(obj, keyName); }
  2217. dependentKeysWillChange(obj, keyName, m);
  2218. chainsWillChange(obj, keyName, m);
  2219. notifyBeforeObservers(obj, keyName);
  2220. }
  2221. Ember.propertyWillChange = propertyWillChange;
  2222. /**
  2223. This function is called just after an object property has changed.
  2224. It will notify any observers and clear caches among other things.
  2225. Normally you will not need to call this method directly but if for some
  2226. reason you can't directly watch a property you can invoke this method
  2227. manually along with `Ember.propertyWillChange()` which you should call just
  2228. before the property value changes.
  2229. @method propertyDidChange
  2230. @for Ember
  2231. @param {Object} obj The object with the property that will change
  2232. @param {String} keyName The property key (or path) that will change.
  2233. @return {void}
  2234. */
  2235. function propertyDidChange(obj, keyName) {
  2236. var m = obj[META_KEY],
  2237. watching = (m && m.watching[keyName] > 0) || keyName === 'length',
  2238. proto = m && m.proto,
  2239. desc = m && m.descs[keyName];
  2240. if (proto === obj) { return; }
  2241. // shouldn't this mean that we're watching this key?
  2242. if (desc && desc.didChange) { desc.didChange(obj, keyName); }
  2243. if (!watching && keyName !== 'length') { return; }
  2244. dependentKeysDidChange(obj, keyName, m);
  2245. chainsDidChange(obj, keyName, m, false);
  2246. notifyObservers(obj, keyName);
  2247. }
  2248. Ember.propertyDidChange = propertyDidChange;
  2249. var WILL_SEEN, DID_SEEN;
  2250. // called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...)
  2251. function dependentKeysWillChange(obj, depKey, meta) {
  2252. if (obj.isDestroying) { return; }
  2253. var seen = WILL_SEEN, top = !seen;
  2254. if (top) { seen = WILL_SEEN = {}; }
  2255. iterDeps(propertyWillChange, obj, depKey, seen, meta);
  2256. if (top) { WILL_SEEN = null; }
  2257. }
  2258. // called whenever a property has just changed to update dependent keys
  2259. function dependentKeysDidChange(obj, depKey, meta) {
  2260. if (obj.isDestroying) { return; }
  2261. var seen = DID_SEEN, top = !seen;
  2262. if (top) { seen = DID_SEEN = {}; }
  2263. iterDeps(propertyDidChange, obj, depKey, seen, meta);
  2264. if (top) { DID_SEEN = null; }
  2265. }
  2266. function iterDeps(method, obj, depKey, seen, meta) {
  2267. var guid = guidFor(obj);
  2268. if (!seen[guid]) seen[guid] = {};
  2269. if (seen[guid][depKey]) return;
  2270. seen[guid][depKey] = true;
  2271. var deps = meta.deps;
  2272. deps = deps && deps[depKey];
  2273. if (deps) {
  2274. for(var key in deps) {
  2275. var desc = meta.descs[key];
  2276. if (desc && desc._suspended === obj) continue;
  2277. method(obj, key);
  2278. }
  2279. }
  2280. }
  2281. function chainsWillChange(obj, keyName, m) {
  2282. if (!(m.hasOwnProperty('chainWatchers') &&
  2283. m.chainWatchers[keyName])) {
  2284. return;
  2285. }
  2286. var nodes = m.chainWatchers[keyName],
  2287. events = [],
  2288. i, l;
  2289. for(i = 0, l = nodes.length; i < l; i++) {
  2290. nodes[i].willChange(events);
  2291. }
  2292. for (i = 0, l = events.length; i < l; i += 2) {
  2293. propertyWillChange(events[i], events[i+1]);
  2294. }
  2295. }
  2296. function chainsDidChange(obj, keyName, m, suppressEvents) {
  2297. if (!(m && m.hasOwnProperty('chainWatchers') &&
  2298. m.chainWatchers[keyName])) {
  2299. return;
  2300. }
  2301. var nodes = m.chainWatchers[keyName],
  2302. events = suppressEvents ? null : [],
  2303. i, l;
  2304. for(i = 0, l = nodes.length; i < l; i++) {
  2305. nodes[i].didChange(events);
  2306. }
  2307. if (suppressEvents) {
  2308. return;
  2309. }
  2310. for (i = 0, l = events.length; i < l; i += 2) {
  2311. propertyDidChange(events[i], events[i+1]);
  2312. }
  2313. }
  2314. Ember.overrideChains = function(obj, keyName, m) {
  2315. chainsDidChange(obj, keyName, m, true);
  2316. };
  2317. /**
  2318. @method beginPropertyChanges
  2319. @chainable
  2320. @private
  2321. */
  2322. function beginPropertyChanges() {
  2323. deferred++;
  2324. }
  2325. Ember.beginPropertyChanges = beginPropertyChanges;
  2326. /**
  2327. @method endPropertyChanges
  2328. @private
  2329. */
  2330. function endPropertyChanges() {
  2331. deferred--;
  2332. if (deferred<=0) {
  2333. beforeObserverSet.clear();
  2334. observerSet.flush();
  2335. }
  2336. }
  2337. Ember.endPropertyChanges = endPropertyChanges;
  2338. /**
  2339. Make a series of property changes together in an
  2340. exception-safe way.
  2341. ```javascript
  2342. Ember.changeProperties(function() {
  2343. obj1.set('foo', mayBlowUpWhenSet);
  2344. obj2.set('bar', baz);
  2345. });
  2346. ```
  2347. @method changeProperties
  2348. @param {Function} callback
  2349. @param [binding]
  2350. */
  2351. Ember.changeProperties = function(cb, binding) {
  2352. beginPropertyChanges();
  2353. tryFinally(cb, endPropertyChanges, binding);
  2354. };
  2355. function notifyBeforeObservers(obj, keyName) {
  2356. if (obj.isDestroying) { return; }
  2357. var eventName = keyName + ':before', listeners, diff;
  2358. if (deferred) {
  2359. listeners = beforeObserverSet.add(obj, keyName, eventName);
  2360. diff = listenersDiff(obj, eventName, listeners);
  2361. sendEvent(obj, eventName, [obj, keyName], diff);
  2362. } else {
  2363. sendEvent(obj, eventName, [obj, keyName]);
  2364. }
  2365. }
  2366. function notifyObservers(obj, keyName) {
  2367. if (obj.isDestroying) { return; }
  2368. var eventName = keyName + ':change', listeners;
  2369. if (deferred) {
  2370. listeners = observerSet.add(obj, keyName, eventName);
  2371. listenersUnion(obj, eventName, listeners);
  2372. } else {
  2373. sendEvent(obj, eventName, [obj, keyName]);
  2374. }
  2375. }
  2376. })();
  2377. (function() {
  2378. // META_KEY
  2379. // _getPath
  2380. // propertyWillChange, propertyDidChange
  2381. var META_KEY = Ember.META_KEY,
  2382. MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER,
  2383. IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/,
  2384. getPath = Ember._getPath;
  2385. /**
  2386. Sets the value of a property on an object, respecting computed properties
  2387. and notifying observers and other listeners of the change. If the
  2388. property is not defined but the object implements the `setUnknownProperty`
  2389. method then that will be invoked as well.
  2390. @method set
  2391. @for Ember
  2392. @param {Object} obj The object to modify.
  2393. @param {String} keyName The property key to set
  2394. @param {Object} value The value to set
  2395. @return {Object} the passed value.
  2396. */
  2397. var set = function set(obj, keyName, value, tolerant) {
  2398. if (typeof obj === 'string') {
  2399. Ember.assert("Path '" + obj + "' must be global if no obj is given.", IS_GLOBAL.test(obj));
  2400. value = keyName;
  2401. keyName = obj;
  2402. obj = null;
  2403. }
  2404. Ember.assert("Cannot call set with "+ keyName +" key.", !!keyName);
  2405. if (!obj || keyName.indexOf('.') !== -1) {
  2406. return setPath(obj, keyName, value, tolerant);
  2407. }
  2408. Ember.assert("You need to provide an object and key to `set`.", !!obj && keyName !== undefined);
  2409. Ember.assert('calling set on destroyed object', !obj.isDestroyed);
  2410. var meta = obj[META_KEY], desc = meta && meta.descs[keyName],
  2411. isUnknown, currentValue;
  2412. if (desc) {
  2413. desc.set(obj, keyName, value);
  2414. } else {
  2415. isUnknown = 'object' === typeof obj && !(keyName in obj);
  2416. // setUnknownProperty is called if `obj` is an object,
  2417. // the property does not already exist, and the
  2418. // `setUnknownProperty` method exists on the object
  2419. if (isUnknown && 'function' === typeof obj.setUnknownProperty) {
  2420. obj.setUnknownProperty(keyName, value);
  2421. } else if (meta && meta.watching[keyName] > 0) {
  2422. if (MANDATORY_SETTER) {
  2423. currentValue = meta.values[keyName];
  2424. } else {
  2425. currentValue = obj[keyName];
  2426. }
  2427. // only trigger a change if the value has changed
  2428. if (value !== currentValue) {
  2429. Ember.propertyWillChange(obj, keyName);
  2430. if (MANDATORY_SETTER) {
  2431. if ((currentValue === undefined && !(keyName in obj)) || !obj.propertyIsEnumerable(keyName)) {
  2432. Ember.defineProperty(obj, keyName, null, value); // setup mandatory setter
  2433. } else {
  2434. meta.values[keyName] = value;
  2435. }
  2436. } else {
  2437. obj[keyName] = value;
  2438. }
  2439. Ember.propertyDidChange(obj, keyName);
  2440. }
  2441. } else {
  2442. obj[keyName] = value;
  2443. }
  2444. }
  2445. return value;
  2446. };
  2447. // Currently used only by Ember Data tests
  2448. if (Ember.config.overrideAccessors) {
  2449. Ember.set = set;
  2450. Ember.config.overrideAccessors();
  2451. set = Ember.set;
  2452. }
  2453. function setPath(root, path, value, tolerant) {
  2454. var keyName;
  2455. // get the last part of the path
  2456. keyName = path.slice(path.lastIndexOf('.') + 1);
  2457. // get the first part of the part
  2458. path = (path === keyName) ? keyName : path.slice(0, path.length-(keyName.length+1));
  2459. // unless the path is this, look up the first part to
  2460. // get the root
  2461. if (path !== 'this') {
  2462. root = getPath(root, path);
  2463. }
  2464. if (!keyName || keyName.length === 0) {
  2465. throw new Ember.Error('Property set failed: You passed an empty path');
  2466. }
  2467. if (!root) {
  2468. if (tolerant) { return; }
  2469. else { throw new Ember.Error('Property set failed: object in path "'+path+'" could not be found or was destroyed.'); }
  2470. }
  2471. return set(root, keyName, value);
  2472. }
  2473. Ember.set = set;
  2474. /**
  2475. Error-tolerant form of `Ember.set`. Will not blow up if any part of the
  2476. chain is `undefined`, `null`, or destroyed.
  2477. This is primarily used when syncing bindings, which may try to update after
  2478. an object has been destroyed.
  2479. @method trySet
  2480. @for Ember
  2481. @param {Object} obj The object to modify.
  2482. @param {String} path The property path to set
  2483. @param {Object} value The value to set
  2484. */
  2485. Ember.trySet = function(root, path, value) {
  2486. return set(root, path, value, true);
  2487. };
  2488. })();
  2489. (function() {
  2490. /**
  2491. @module ember-metal
  2492. */
  2493. /*
  2494. JavaScript (before ES6) does not have a Map implementation. Objects,
  2495. which are often used as dictionaries, may only have Strings as keys.
  2496. Because Ember has a way to get a unique identifier for every object
  2497. via `Ember.guidFor`, we can implement a performant Map with arbitrary
  2498. keys. Because it is commonly used in low-level bookkeeping, Map is
  2499. implemented as a pure JavaScript object for performance.
  2500. This implementation follows the current iteration of the ES6 proposal for
  2501. maps (http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets),
  2502. with two exceptions. First, because we need our implementation to be pleasant
  2503. on older browsers, we do not use the `delete` name (using `remove` instead).
  2504. Second, as we do not have the luxury of in-VM iteration, we implement a
  2505. forEach method for iteration.
  2506. Map is mocked out to look like an Ember object, so you can do
  2507. `Ember.Map.create()` for symmetry with other Ember classes.
  2508. */
  2509. var set = Ember.set,
  2510. guidFor = Ember.guidFor,
  2511. indexOf = Ember.ArrayPolyfills.indexOf;
  2512. var copy = function(obj) {
  2513. var output = {};
  2514. for (var prop in obj) {
  2515. if (obj.hasOwnProperty(prop)) { output[prop] = obj[prop]; }
  2516. }
  2517. return output;
  2518. };
  2519. var copyMap = function(original, newObject) {
  2520. var keys = original.keys.copy(),
  2521. values = copy(original.values);
  2522. newObject.keys = keys;
  2523. newObject.values = values;
  2524. newObject.length = original.length;
  2525. return newObject;
  2526. };
  2527. /**
  2528. This class is used internally by Ember and Ember Data.
  2529. Please do not use it at this time. We plan to clean it up
  2530. and add many tests soon.
  2531. @class OrderedSet
  2532. @namespace Ember
  2533. @constructor
  2534. @private
  2535. */
  2536. var OrderedSet = Ember.OrderedSet = function() {
  2537. this.clear();
  2538. };
  2539. /**
  2540. @method create
  2541. @static
  2542. @return {Ember.OrderedSet}
  2543. */
  2544. OrderedSet.create = function() {
  2545. return new OrderedSet();
  2546. };
  2547. OrderedSet.prototype = {
  2548. /**
  2549. @method clear
  2550. */
  2551. clear: function() {
  2552. this.presenceSet = {};
  2553. this.list = [];
  2554. },
  2555. /**
  2556. @method add
  2557. @param obj
  2558. */
  2559. add: function(obj) {
  2560. var guid = guidFor(obj),
  2561. presenceSet = this.presenceSet,
  2562. list = this.list;
  2563. if (guid in presenceSet) { return; }
  2564. presenceSet[guid] = true;
  2565. list.push(obj);
  2566. },
  2567. /**
  2568. @method remove
  2569. @param obj
  2570. */
  2571. remove: function(obj) {
  2572. var guid = guidFor(obj),
  2573. presenceSet = this.presenceSet,
  2574. list = this.list;
  2575. delete presenceSet[guid];
  2576. var index = indexOf.call(list, obj);
  2577. if (index > -1) {
  2578. list.splice(index, 1);
  2579. }
  2580. },
  2581. /**
  2582. @method isEmpty
  2583. @return {Boolean}
  2584. */
  2585. isEmpty: function() {
  2586. return this.list.length === 0;
  2587. },
  2588. /**
  2589. @method has
  2590. @param obj
  2591. @return {Boolean}
  2592. */
  2593. has: function(obj) {
  2594. var guid = guidFor(obj),
  2595. presenceSet = this.presenceSet;
  2596. return guid in presenceSet;
  2597. },
  2598. /**
  2599. @method forEach
  2600. @param {Function} fn
  2601. @param self
  2602. */
  2603. forEach: function(fn, self) {
  2604. // allow mutation during iteration
  2605. var list = this.toArray();
  2606. for (var i = 0, j = list.length; i < j; i++) {
  2607. fn.call(self, list[i]);
  2608. }
  2609. },
  2610. /**
  2611. @method toArray
  2612. @return {Array}
  2613. */
  2614. toArray: function() {
  2615. return this.list.slice();
  2616. },
  2617. /**
  2618. @method copy
  2619. @return {Ember.OrderedSet}
  2620. */
  2621. copy: function() {
  2622. var set = new OrderedSet();
  2623. set.presenceSet = copy(this.presenceSet);
  2624. set.list = this.toArray();
  2625. return set;
  2626. }
  2627. };
  2628. /**
  2629. A Map stores values indexed by keys. Unlike JavaScript's
  2630. default Objects, the keys of a Map can be any JavaScript
  2631. object.
  2632. Internally, a Map has two data structures:
  2633. 1. `keys`: an OrderedSet of all of the existing keys
  2634. 2. `values`: a JavaScript Object indexed by the `Ember.guidFor(key)`
  2635. When a key/value pair is added for the first time, we
  2636. add the key to the `keys` OrderedSet, and create or
  2637. replace an entry in `values`. When an entry is deleted,
  2638. we delete its entry in `keys` and `values`.
  2639. @class Map
  2640. @namespace Ember
  2641. @private
  2642. @constructor
  2643. */
  2644. var Map = Ember.Map = function() {
  2645. this.keys = Ember.OrderedSet.create();
  2646. this.values = {};
  2647. };
  2648. /**
  2649. @method create
  2650. @static
  2651. */
  2652. Map.create = function() {
  2653. return new Map();
  2654. };
  2655. Map.prototype = {
  2656. /**
  2657. This property will change as the number of objects in the map changes.
  2658. @property length
  2659. @type number
  2660. @default 0
  2661. */
  2662. length: 0,
  2663. /**
  2664. Retrieve the value associated with a given key.
  2665. @method get
  2666. @param {*} key
  2667. @return {*} the value associated with the key, or `undefined`
  2668. */
  2669. get: function(key) {
  2670. var values = this.values,
  2671. guid = guidFor(key);
  2672. return values[guid];
  2673. },
  2674. /**
  2675. Adds a value to the map. If a value for the given key has already been
  2676. provided, the new value will replace the old value.
  2677. @method set
  2678. @param {*} key
  2679. @param {*} value
  2680. */
  2681. set: function(key, value) {
  2682. var keys = this.keys,
  2683. values = this.values,
  2684. guid = guidFor(key);
  2685. keys.add(key);
  2686. values[guid] = value;
  2687. set(this, 'length', keys.list.length);
  2688. },
  2689. /**
  2690. Removes a value from the map for an associated key.
  2691. @method remove
  2692. @param {*} key
  2693. @return {Boolean} true if an item was removed, false otherwise
  2694. */
  2695. remove: function(key) {
  2696. // don't use ES6 "delete" because it will be annoying
  2697. // to use in browsers that are not ES6 friendly;
  2698. var keys = this.keys,
  2699. values = this.values,
  2700. guid = guidFor(key);
  2701. if (values.hasOwnProperty(guid)) {
  2702. keys.remove(key);
  2703. delete values[guid];
  2704. set(this, 'length', keys.list.length);
  2705. return true;
  2706. } else {
  2707. return false;
  2708. }
  2709. },
  2710. /**
  2711. Check whether a key is present.
  2712. @method has
  2713. @param {*} key
  2714. @return {Boolean} true if the item was present, false otherwise
  2715. */
  2716. has: function(key) {
  2717. var values = this.values,
  2718. guid = guidFor(key);
  2719. return values.hasOwnProperty(guid);
  2720. },
  2721. /**
  2722. Iterate over all the keys and values. Calls the function once
  2723. for each key, passing in the key and value, in that order.
  2724. The keys are guaranteed to be iterated over in insertion order.
  2725. @method forEach
  2726. @param {Function} callback
  2727. @param {*} self if passed, the `this` value inside the
  2728. callback. By default, `this` is the map.
  2729. */
  2730. forEach: function(callback, self) {
  2731. var keys = this.keys,
  2732. values = this.values;
  2733. keys.forEach(function(key) {
  2734. var guid = guidFor(key);
  2735. callback.call(self, key, values[guid]);
  2736. });
  2737. },
  2738. /**
  2739. @method copy
  2740. @return {Ember.Map}
  2741. */
  2742. copy: function() {
  2743. return copyMap(this, new Map());
  2744. }
  2745. };
  2746. /**
  2747. @class MapWithDefault
  2748. @namespace Ember
  2749. @extends Ember.Map
  2750. @private
  2751. @constructor
  2752. @param [options]
  2753. @param {*} [options.defaultValue]
  2754. */
  2755. var MapWithDefault = Ember.MapWithDefault = function(options) {
  2756. Map.call(this);
  2757. this.defaultValue = options.defaultValue;
  2758. };
  2759. /**
  2760. @method create
  2761. @static
  2762. @param [options]
  2763. @param {*} [options.defaultValue]
  2764. @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns
  2765. `Ember.MapWithDefault` otherwise returns `Ember.Map`
  2766. */
  2767. MapWithDefault.create = function(options) {
  2768. if (options) {
  2769. return new MapWithDefault(options);
  2770. } else {
  2771. return new Map();
  2772. }
  2773. };
  2774. MapWithDefault.prototype = Ember.create(Map.prototype);
  2775. /**
  2776. Retrieve the value associated with a given key.
  2777. @method get
  2778. @param {*} key
  2779. @return {*} the value associated with the key, or the default value
  2780. */
  2781. MapWithDefault.prototype.get = function(key) {
  2782. var hasValue = this.has(key);
  2783. if (hasValue) {
  2784. return Map.prototype.get.call(this, key);
  2785. } else {
  2786. var defaultValue = this.defaultValue(key);
  2787. this.set(key, defaultValue);
  2788. return defaultValue;
  2789. }
  2790. };
  2791. /**
  2792. @method copy
  2793. @return {Ember.MapWithDefault}
  2794. */
  2795. MapWithDefault.prototype.copy = function() {
  2796. return copyMap(this, new MapWithDefault({
  2797. defaultValue: this.defaultValue
  2798. }));
  2799. };
  2800. })();
  2801. (function() {
  2802. function consoleMethod(name) {
  2803. var consoleObj, logToConsole;
  2804. if (Ember.imports.console) {
  2805. consoleObj = Ember.imports.console;
  2806. } else if (typeof console !== 'undefined') {
  2807. consoleObj = console;
  2808. }
  2809. var method = typeof consoleObj === 'object' ? consoleObj[name] : null;
  2810. if (method) {
  2811. // Older IE doesn't support apply, but Chrome needs it
  2812. if (method.apply) {
  2813. logToConsole = function() {
  2814. method.apply(consoleObj, arguments);
  2815. };
  2816. logToConsole.displayName = 'console.' + name;
  2817. return logToConsole;
  2818. } else {
  2819. return function() {
  2820. var message = Array.prototype.join.call(arguments, ', ');
  2821. method(message);
  2822. };
  2823. }
  2824. }
  2825. }
  2826. function assertPolyfill(test, message) {
  2827. if (!test) {
  2828. try {
  2829. // attempt to preserve the stack
  2830. throw new Ember.Error("assertion failed: " + message);
  2831. } catch(error) {
  2832. setTimeout(function() {
  2833. throw error;
  2834. }, 0);
  2835. }
  2836. }
  2837. }
  2838. /**
  2839. Inside Ember-Metal, simply uses the methods from `imports.console`.
  2840. Override this to provide more robust logging functionality.
  2841. @class Logger
  2842. @namespace Ember
  2843. */
  2844. Ember.Logger = {
  2845. /**
  2846. Logs the arguments to the console.
  2847. You can pass as many arguments as you want and they will be joined together with a space.
  2848. ```javascript
  2849. var foo = 1;
  2850. Ember.Logger.log('log value of foo:', foo); // "log value of foo: 1" will be printed to the console
  2851. ```
  2852. @method log
  2853. @for Ember.Logger
  2854. @param {*} arguments
  2855. */
  2856. log: consoleMethod('log') || Ember.K,
  2857. /**
  2858. Prints the arguments to the console with a warning icon.
  2859. You can pass as many arguments as you want and they will be joined together with a space.
  2860. ```javascript
  2861. Ember.Logger.warn('Something happened!'); // "Something happened!" will be printed to the console with a warning icon.
  2862. ```
  2863. @method warn
  2864. @for Ember.Logger
  2865. @param {*} arguments
  2866. */
  2867. warn: consoleMethod('warn') || Ember.K,
  2868. /**
  2869. Prints the arguments to the console with an error icon, red text and a stack trace.
  2870. You can pass as many arguments as you want and they will be joined together with a space.
  2871. ```javascript
  2872. Ember.Logger.error('Danger! Danger!'); // "Danger! Danger!" will be printed to the console in red text.
  2873. ```
  2874. @method error
  2875. @for Ember.Logger
  2876. @param {*} arguments
  2877. */
  2878. error: consoleMethod('error') || Ember.K,
  2879. /**
  2880. Logs the arguments to the console.
  2881. You can pass as many arguments as you want and they will be joined together with a space.
  2882. ```javascript
  2883. var foo = 1;
  2884. Ember.Logger.info('log value of foo:', foo); // "log value of foo: 1" will be printed to the console
  2885. ```
  2886. @method info
  2887. @for Ember.Logger
  2888. @param {*} arguments
  2889. */
  2890. info: consoleMethod('info') || Ember.K,
  2891. /**
  2892. Logs the arguments to the console in blue text.
  2893. You can pass as many arguments as you want and they will be joined together with a space.
  2894. ```javascript
  2895. var foo = 1;
  2896. Ember.Logger.debug('log value of foo:', foo); // "log value of foo: 1" will be printed to the console
  2897. ```
  2898. @method debug
  2899. @for Ember.Logger
  2900. @param {*} arguments
  2901. */
  2902. debug: consoleMethod('debug') || consoleMethod('info') || Ember.K,
  2903. /**
  2904. If the value passed into `Ember.Logger.assert` is not truthy it will throw an error with a stack trace.
  2905. ```javascript
  2906. Ember.Logger.assert(true); // undefined
  2907. Ember.Logger.assert(true === false); // Throws an Assertion failed error.
  2908. ```
  2909. @method assert
  2910. @for Ember.Logger
  2911. @param {Boolean} bool Value to test
  2912. */
  2913. assert: consoleMethod('assert') || assertPolyfill
  2914. };
  2915. })();
  2916. (function() {
  2917. /**
  2918. @module ember-metal
  2919. */
  2920. var META_KEY = Ember.META_KEY,
  2921. metaFor = Ember.meta,
  2922. objectDefineProperty = Ember.platform.defineProperty;
  2923. var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER;
  2924. // ..........................................................
  2925. // DESCRIPTOR
  2926. //
  2927. /**
  2928. Objects of this type can implement an interface to respond to requests to
  2929. get and set. The default implementation handles simple properties.
  2930. You generally won't need to create or subclass this directly.
  2931. @class Descriptor
  2932. @namespace Ember
  2933. @private
  2934. @constructor
  2935. */
  2936. Ember.Descriptor = function() {};
  2937. // ..........................................................
  2938. // DEFINING PROPERTIES API
  2939. //
  2940. var MANDATORY_SETTER_FUNCTION = Ember.MANDATORY_SETTER_FUNCTION = function(value) {
  2941. Ember.assert("You must use Ember.set() to access this property (of " + this + ")", false);
  2942. };
  2943. var DEFAULT_GETTER_FUNCTION = Ember.DEFAULT_GETTER_FUNCTION = function(name) {
  2944. return function() {
  2945. var meta = this[META_KEY];
  2946. return meta && meta.values[name];
  2947. };
  2948. };
  2949. /**
  2950. NOTE: This is a low-level method used by other parts of the API. You almost
  2951. never want to call this method directly. Instead you should use
  2952. `Ember.mixin()` to define new properties.
  2953. Defines a property on an object. This method works much like the ES5
  2954. `Object.defineProperty()` method except that it can also accept computed
  2955. properties and other special descriptors.
  2956. Normally this method takes only three parameters. However if you pass an
  2957. instance of `Ember.Descriptor` as the third param then you can pass an
  2958. optional value as the fourth parameter. This is often more efficient than
  2959. creating new descriptor hashes for each property.
  2960. ## Examples
  2961. ```javascript
  2962. // ES5 compatible mode
  2963. Ember.defineProperty(contact, 'firstName', {
  2964. writable: true,
  2965. configurable: false,
  2966. enumerable: true,
  2967. value: 'Charles'
  2968. });
  2969. // define a simple property
  2970. Ember.defineProperty(contact, 'lastName', undefined, 'Jolley');
  2971. // define a computed property
  2972. Ember.defineProperty(contact, 'fullName', Ember.computed(function() {
  2973. return this.firstName+' '+this.lastName;
  2974. }).property('firstName', 'lastName'));
  2975. ```
  2976. @private
  2977. @method defineProperty
  2978. @for Ember
  2979. @param {Object} obj the object to define this property on. This may be a prototype.
  2980. @param {String} keyName the name of the property
  2981. @param {Ember.Descriptor} [desc] an instance of `Ember.Descriptor` (typically a
  2982. computed property) or an ES5 descriptor.
  2983. You must provide this or `data` but not both.
  2984. @param {*} [data] something other than a descriptor, that will
  2985. become the explicit value of this property.
  2986. */
  2987. Ember.defineProperty = function(obj, keyName, desc, data, meta) {
  2988. var descs, existingDesc, watching, value;
  2989. if (!meta) meta = metaFor(obj);
  2990. descs = meta.descs;
  2991. existingDesc = meta.descs[keyName];
  2992. watching = meta.watching[keyName] > 0;
  2993. if (existingDesc instanceof Ember.Descriptor) {
  2994. existingDesc.teardown(obj, keyName);
  2995. }
  2996. if (desc instanceof Ember.Descriptor) {
  2997. value = desc;
  2998. descs[keyName] = desc;
  2999. if (MANDATORY_SETTER && watching) {
  3000. objectDefineProperty(obj, keyName, {
  3001. configurable: true,
  3002. enumerable: true,
  3003. writable: true,
  3004. value: undefined // make enumerable
  3005. });
  3006. } else {
  3007. obj[keyName] = undefined; // make enumerable
  3008. }
  3009. } else {
  3010. descs[keyName] = undefined; // shadow descriptor in proto
  3011. if (desc == null) {
  3012. value = data;
  3013. if (MANDATORY_SETTER && watching) {
  3014. meta.values[keyName] = data;
  3015. objectDefineProperty(obj, keyName, {
  3016. configurable: true,
  3017. enumerable: true,
  3018. set: MANDATORY_SETTER_FUNCTION,
  3019. get: DEFAULT_GETTER_FUNCTION(keyName)
  3020. });
  3021. } else {
  3022. obj[keyName] = data;
  3023. }
  3024. } else {
  3025. value = desc;
  3026. // compatibility with ES5
  3027. objectDefineProperty(obj, keyName, desc);
  3028. }
  3029. }
  3030. // if key is being watched, override chains that
  3031. // were initialized with the prototype
  3032. if (watching) { Ember.overrideChains(obj, keyName, meta); }
  3033. // The `value` passed to the `didDefineProperty` hook is
  3034. // either the descriptor or data, whichever was passed.
  3035. if (obj.didDefineProperty) { obj.didDefineProperty(obj, keyName, value); }
  3036. return this;
  3037. };
  3038. })();
  3039. (function() {
  3040. var get = Ember.get;
  3041. /**
  3042. To get multiple properties at once, call `Ember.getProperties`
  3043. with an object followed by a list of strings or an array:
  3044. ```javascript
  3045. Ember.getProperties(record, 'firstName', 'lastName', 'zipCode'); // { firstName: 'John', lastName: 'Doe', zipCode: '10011' }
  3046. ```
  3047. is equivalent to:
  3048. ```javascript
  3049. Ember.getProperties(record, ['firstName', 'lastName', 'zipCode']); // { firstName: 'John', lastName: 'Doe', zipCode: '10011' }
  3050. ```
  3051. @method getProperties
  3052. @param obj
  3053. @param {String...|Array} list of keys to get
  3054. @return {Hash}
  3055. */
  3056. Ember.getProperties = function(obj) {
  3057. var ret = {},
  3058. propertyNames = arguments,
  3059. i = 1;
  3060. if (arguments.length === 2 && Ember.typeOf(arguments[1]) === 'array') {
  3061. i = 0;
  3062. propertyNames = arguments[1];
  3063. }
  3064. for(var len = propertyNames.length; i < len; i++) {
  3065. ret[propertyNames[i]] = get(obj, propertyNames[i]);
  3066. }
  3067. return ret;
  3068. };
  3069. })();
  3070. (function() {
  3071. var changeProperties = Ember.changeProperties,
  3072. set = Ember.set;
  3073. /**
  3074. Set a list of properties on an object. These properties are set inside
  3075. a single `beginPropertyChanges` and `endPropertyChanges` batch, so
  3076. observers will be buffered.
  3077. ```javascript
  3078. anObject.setProperties({
  3079. firstName: "Stanley",
  3080. lastName: "Stuart",
  3081. age: "21"
  3082. })
  3083. ```
  3084. @method setProperties
  3085. @param self
  3086. @param {Object} hash
  3087. @return self
  3088. */
  3089. Ember.setProperties = function(self, hash) {
  3090. changeProperties(function() {
  3091. for(var prop in hash) {
  3092. if (hash.hasOwnProperty(prop)) { set(self, prop, hash[prop]); }
  3093. }
  3094. });
  3095. return self;
  3096. };
  3097. })();
  3098. (function() {
  3099. var metaFor = Ember.meta, // utils.js
  3100. typeOf = Ember.typeOf, // utils.js
  3101. MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER,
  3102. o_defineProperty = Ember.platform.defineProperty;
  3103. Ember.watchKey = function(obj, keyName, meta) {
  3104. // can't watch length on Array - it is special...
  3105. if (keyName === 'length' && typeOf(obj) === 'array') { return; }
  3106. var m = meta || metaFor(obj), watching = m.watching;
  3107. // activate watching first time
  3108. if (!watching[keyName]) {
  3109. watching[keyName] = 1;
  3110. if ('function' === typeof obj.willWatchProperty) {
  3111. obj.willWatchProperty(keyName);
  3112. }
  3113. if (MANDATORY_SETTER && keyName in obj) {
  3114. m.values[keyName] = obj[keyName];
  3115. o_defineProperty(obj, keyName, {
  3116. configurable: true,
  3117. enumerable: obj.propertyIsEnumerable(keyName),
  3118. set: Ember.MANDATORY_SETTER_FUNCTION,
  3119. get: Ember.DEFAULT_GETTER_FUNCTION(keyName)
  3120. });
  3121. }
  3122. } else {
  3123. watching[keyName] = (watching[keyName] || 0) + 1;
  3124. }
  3125. };
  3126. Ember.unwatchKey = function(obj, keyName, meta) {
  3127. var m = meta || metaFor(obj), watching = m.watching;
  3128. if (watching[keyName] === 1) {
  3129. watching[keyName] = 0;
  3130. if ('function' === typeof obj.didUnwatchProperty) {
  3131. obj.didUnwatchProperty(keyName);
  3132. }
  3133. if (MANDATORY_SETTER && keyName in obj) {
  3134. o_defineProperty(obj, keyName, {
  3135. configurable: true,
  3136. enumerable: obj.propertyIsEnumerable(keyName),
  3137. set: function(val) {
  3138. // redefine to set as enumerable
  3139. o_defineProperty(obj, keyName, {
  3140. configurable: true,
  3141. writable: true,
  3142. enumerable: true,
  3143. value: val
  3144. });
  3145. delete m.values[keyName];
  3146. },
  3147. get: Ember.DEFAULT_GETTER_FUNCTION(keyName)
  3148. });
  3149. }
  3150. } else if (watching[keyName] > 1) {
  3151. watching[keyName]--;
  3152. }
  3153. };
  3154. })();
  3155. (function() {
  3156. var metaFor = Ember.meta, // utils.js
  3157. get = Ember.get, // property_get.js
  3158. normalizeTuple = Ember.normalizeTuple, // property_get.js
  3159. forEach = Ember.ArrayPolyfills.forEach, // array.js
  3160. warn = Ember.warn,
  3161. watchKey = Ember.watchKey,
  3162. unwatchKey = Ember.unwatchKey,
  3163. FIRST_KEY = /^([^\.\*]+)/,
  3164. META_KEY = Ember.META_KEY;
  3165. function firstKey(path) {
  3166. return path.match(FIRST_KEY)[0];
  3167. }
  3168. var pendingQueue = [];
  3169. // attempts to add the pendingQueue chains again. If some of them end up
  3170. // back in the queue and reschedule is true, schedules a timeout to try
  3171. // again.
  3172. Ember.flushPendingChains = function() {
  3173. if (pendingQueue.length === 0) { return; } // nothing to do
  3174. var queue = pendingQueue;
  3175. pendingQueue = [];
  3176. forEach.call(queue, function(q) { q[0].add(q[1]); });
  3177. 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);
  3178. };
  3179. function addChainWatcher(obj, keyName, node) {
  3180. if (!obj || ('object' !== typeof obj)) { return; } // nothing to do
  3181. var m = metaFor(obj), nodes = m.chainWatchers;
  3182. if (!m.hasOwnProperty('chainWatchers')) {
  3183. nodes = m.chainWatchers = {};
  3184. }
  3185. if (!nodes[keyName]) { nodes[keyName] = []; }
  3186. nodes[keyName].push(node);
  3187. watchKey(obj, keyName, m);
  3188. }
  3189. var removeChainWatcher = Ember.removeChainWatcher = function(obj, keyName, node) {
  3190. if (!obj || 'object' !== typeof obj) { return; } // nothing to do
  3191. var m = obj[META_KEY];
  3192. if (m && !m.hasOwnProperty('chainWatchers')) { return; } // nothing to do
  3193. var nodes = m && m.chainWatchers;
  3194. if (nodes && nodes[keyName]) {
  3195. nodes = nodes[keyName];
  3196. for (var i = 0, l = nodes.length; i < l; i++) {
  3197. if (nodes[i] === node) { nodes.splice(i, 1); }
  3198. }
  3199. }
  3200. unwatchKey(obj, keyName, m);
  3201. };
  3202. // A ChainNode watches a single key on an object. If you provide a starting
  3203. // value for the key then the node won't actually watch it. For a root node
  3204. // pass null for parent and key and object for value.
  3205. var ChainNode = Ember._ChainNode = function(parent, key, value) {
  3206. this._parent = parent;
  3207. this._key = key;
  3208. // _watching is true when calling get(this._parent, this._key) will
  3209. // return the value of this node.
  3210. //
  3211. // It is false for the root of a chain (because we have no parent)
  3212. // and for global paths (because the parent node is the object with
  3213. // the observer on it)
  3214. this._watching = value===undefined;
  3215. this._value = value;
  3216. this._paths = {};
  3217. if (this._watching) {
  3218. this._object = parent.value();
  3219. if (this._object) { addChainWatcher(this._object, this._key, this); }
  3220. }
  3221. // Special-case: the EachProxy relies on immediate evaluation to
  3222. // establish its observers.
  3223. //
  3224. // TODO: Replace this with an efficient callback that the EachProxy
  3225. // can implement.
  3226. if (this._parent && this._parent._key === '@each') {
  3227. this.value();
  3228. }
  3229. };
  3230. var ChainNodePrototype = ChainNode.prototype;
  3231. function lazyGet(obj, key) {
  3232. if (!obj) return undefined;
  3233. var meta = obj[META_KEY];
  3234. // check if object meant only to be a prototype
  3235. if (meta && meta.proto === obj) return undefined;
  3236. if (key === "@each") return get(obj, key);
  3237. // if a CP only return cached value
  3238. var desc = meta && meta.descs[key];
  3239. if (desc && desc._cacheable) {
  3240. if (key in meta.cache) {
  3241. return meta.cache[key];
  3242. } else {
  3243. return undefined;
  3244. }
  3245. }
  3246. return get(obj, key);
  3247. }
  3248. ChainNodePrototype.value = function() {
  3249. if (this._value === undefined && this._watching) {
  3250. var obj = this._parent.value();
  3251. this._value = lazyGet(obj, this._key);
  3252. }
  3253. return this._value;
  3254. };
  3255. ChainNodePrototype.destroy = function() {
  3256. if (this._watching) {
  3257. var obj = this._object;
  3258. if (obj) { removeChainWatcher(obj, this._key, this); }
  3259. this._watching = false; // so future calls do nothing
  3260. }
  3261. };
  3262. // copies a top level object only
  3263. ChainNodePrototype.copy = function(obj) {
  3264. var ret = new ChainNode(null, null, obj),
  3265. paths = this._paths, path;
  3266. for (path in paths) {
  3267. if (paths[path] <= 0) { continue; } // this check will also catch non-number vals.
  3268. ret.add(path);
  3269. }
  3270. return ret;
  3271. };
  3272. // called on the root node of a chain to setup watchers on the specified
  3273. // path.
  3274. ChainNodePrototype.add = function(path) {
  3275. var obj, tuple, key, src, paths;
  3276. paths = this._paths;
  3277. paths[path] = (paths[path] || 0) + 1;
  3278. obj = this.value();
  3279. tuple = normalizeTuple(obj, path);
  3280. // the path was a local path
  3281. if (tuple[0] && tuple[0] === obj) {
  3282. path = tuple[1];
  3283. key = firstKey(path);
  3284. path = path.slice(key.length+1);
  3285. // global path, but object does not exist yet.
  3286. // put into a queue and try to connect later.
  3287. } else if (!tuple[0]) {
  3288. pendingQueue.push([this, path]);
  3289. tuple.length = 0;
  3290. return;
  3291. // global path, and object already exists
  3292. } else {
  3293. src = tuple[0];
  3294. key = path.slice(0, 0-(tuple[1].length+1));
  3295. path = tuple[1];
  3296. }
  3297. tuple.length = 0;
  3298. this.chain(key, path, src);
  3299. };
  3300. // called on the root node of a chain to teardown watcher on the specified
  3301. // path
  3302. ChainNodePrototype.remove = function(path) {
  3303. var obj, tuple, key, src, paths;
  3304. paths = this._paths;
  3305. if (paths[path] > 0) { paths[path]--; }
  3306. obj = this.value();
  3307. tuple = normalizeTuple(obj, path);
  3308. if (tuple[0] === obj) {
  3309. path = tuple[1];
  3310. key = firstKey(path);
  3311. path = path.slice(key.length+1);
  3312. } else {
  3313. src = tuple[0];
  3314. key = path.slice(0, 0-(tuple[1].length+1));
  3315. path = tuple[1];
  3316. }
  3317. tuple.length = 0;
  3318. this.unchain(key, path);
  3319. };
  3320. ChainNodePrototype.count = 0;
  3321. ChainNodePrototype.chain = function(key, path, src) {
  3322. var chains = this._chains, node;
  3323. if (!chains) { chains = this._chains = {}; }
  3324. node = chains[key];
  3325. if (!node) { node = chains[key] = new ChainNode(this, key, src); }
  3326. node.count++; // count chains...
  3327. // chain rest of path if there is one
  3328. if (path && path.length>0) {
  3329. key = firstKey(path);
  3330. path = path.slice(key.length+1);
  3331. node.chain(key, path); // NOTE: no src means it will observe changes...
  3332. }
  3333. };
  3334. ChainNodePrototype.unchain = function(key, path) {
  3335. var chains = this._chains, node = chains[key];
  3336. // unchain rest of path first...
  3337. if (path && path.length>1) {
  3338. key = firstKey(path);
  3339. path = path.slice(key.length+1);
  3340. node.unchain(key, path);
  3341. }
  3342. // delete node if needed.
  3343. node.count--;
  3344. if (node.count<=0) {
  3345. delete chains[node._key];
  3346. node.destroy();
  3347. }
  3348. };
  3349. ChainNodePrototype.willChange = function(events) {
  3350. var chains = this._chains;
  3351. if (chains) {
  3352. for(var key in chains) {
  3353. if (!chains.hasOwnProperty(key)) { continue; }
  3354. chains[key].willChange(events);
  3355. }
  3356. }
  3357. if (this._parent) { this._parent.chainWillChange(this, this._key, 1, events); }
  3358. };
  3359. ChainNodePrototype.chainWillChange = function(chain, path, depth, events) {
  3360. if (this._key) { path = this._key + '.' + path; }
  3361. if (this._parent) {
  3362. this._parent.chainWillChange(this, path, depth+1, events);
  3363. } else {
  3364. if (depth > 1) {
  3365. events.push(this.value(), path);
  3366. }
  3367. path = 'this.' + path;
  3368. if (this._paths[path] > 0) {
  3369. events.push(this.value(), path);
  3370. }
  3371. }
  3372. };
  3373. ChainNodePrototype.chainDidChange = function(chain, path, depth, events) {
  3374. if (this._key) { path = this._key + '.' + path; }
  3375. if (this._parent) {
  3376. this._parent.chainDidChange(this, path, depth+1, events);
  3377. } else {
  3378. if (depth > 1) {
  3379. events.push(this.value(), path);
  3380. }
  3381. path = 'this.' + path;
  3382. if (this._paths[path] > 0) {
  3383. events.push(this.value(), path);
  3384. }
  3385. }
  3386. };
  3387. ChainNodePrototype.didChange = function(events) {
  3388. // invalidate my own value first.
  3389. if (this._watching) {
  3390. var obj = this._parent.value();
  3391. if (obj !== this._object) {
  3392. removeChainWatcher(this._object, this._key, this);
  3393. this._object = obj;
  3394. addChainWatcher(obj, this._key, this);
  3395. }
  3396. this._value = undefined;
  3397. // Special-case: the EachProxy relies on immediate evaluation to
  3398. // establish its observers.
  3399. if (this._parent && this._parent._key === '@each')
  3400. this.value();
  3401. }
  3402. // then notify chains...
  3403. var chains = this._chains;
  3404. if (chains) {
  3405. for(var key in chains) {
  3406. if (!chains.hasOwnProperty(key)) { continue; }
  3407. chains[key].didChange(events);
  3408. }
  3409. }
  3410. // if no events are passed in then we only care about the above wiring update
  3411. if (events === null) { return; }
  3412. // and finally tell parent about my path changing...
  3413. if (this._parent) { this._parent.chainDidChange(this, this._key, 1, events); }
  3414. };
  3415. Ember.finishChains = function(obj) {
  3416. // We only create meta if we really have to
  3417. var m = obj[META_KEY], chains = m && m.chains;
  3418. if (chains) {
  3419. if (chains.value() !== obj) {
  3420. metaFor(obj).chains = chains = chains.copy(obj);
  3421. } else {
  3422. chains.didChange(null);
  3423. }
  3424. }
  3425. };
  3426. })();
  3427. (function() {
  3428. /**
  3429. @module ember-metal
  3430. */
  3431. var forEach = Ember.EnumerableUtils.forEach,
  3432. BRACE_EXPANSION = /^((?:[^\.]*\.)*)\{(.*)\}$/;
  3433. /**
  3434. Expands `pattern`, invoking `callback` for each expansion.
  3435. The only pattern supported is brace-expansion, anything else will be passed
  3436. once to `callback` directly. Brace expansion can only appear at the end of a
  3437. pattern, for example as the last item in a chain.
  3438. Example
  3439. ```js
  3440. function echo(arg){ console.log(arg); }
  3441. Ember.expandProperties('foo.bar', echo); //=> 'foo.bar'
  3442. Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar'
  3443. Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz'
  3444. Ember.expandProperties('{foo,bar}.baz', echo); //=> '{foo,bar}.baz'
  3445. ```
  3446. @method
  3447. @private
  3448. @param {string} pattern The property pattern to expand.
  3449. @param {function} callback The callback to invoke. It is invoked once per
  3450. expansion, and is passed the expansion.
  3451. */
  3452. Ember.expandProperties = function (pattern, callback) {
  3453. var match, prefix, list;
  3454. if (match = BRACE_EXPANSION.exec(pattern)) {
  3455. prefix = match[1];
  3456. list = match[2];
  3457. forEach(list.split(','), function (suffix) {
  3458. callback(prefix + suffix);
  3459. });
  3460. } else {
  3461. callback(pattern);
  3462. }
  3463. };
  3464. })();
  3465. (function() {
  3466. var metaFor = Ember.meta, // utils.js
  3467. typeOf = Ember.typeOf, // utils.js
  3468. ChainNode = Ember._ChainNode; // chains.js
  3469. // get the chains for the current object. If the current object has
  3470. // chains inherited from the proto they will be cloned and reconfigured for
  3471. // the current object.
  3472. function chainsFor(obj, meta) {
  3473. var m = meta || metaFor(obj), ret = m.chains;
  3474. if (!ret) {
  3475. ret = m.chains = new ChainNode(null, null, obj);
  3476. } else if (ret.value() !== obj) {
  3477. ret = m.chains = ret.copy(obj);
  3478. }
  3479. return ret;
  3480. }
  3481. Ember.watchPath = function(obj, keyPath, meta) {
  3482. // can't watch length on Array - it is special...
  3483. if (keyPath === 'length' && typeOf(obj) === 'array') { return; }
  3484. var m = meta || metaFor(obj), watching = m.watching;
  3485. if (!watching[keyPath]) { // activate watching first time
  3486. watching[keyPath] = 1;
  3487. chainsFor(obj, m).add(keyPath);
  3488. } else {
  3489. watching[keyPath] = (watching[keyPath] || 0) + 1;
  3490. }
  3491. };
  3492. Ember.unwatchPath = function(obj, keyPath, meta) {
  3493. var m = meta || metaFor(obj), watching = m.watching;
  3494. if (watching[keyPath] === 1) {
  3495. watching[keyPath] = 0;
  3496. chainsFor(obj, m).remove(keyPath);
  3497. } else if (watching[keyPath] > 1) {
  3498. watching[keyPath]--;
  3499. }
  3500. };
  3501. })();
  3502. (function() {
  3503. /**
  3504. @module ember-metal
  3505. */
  3506. var metaFor = Ember.meta, // utils.js
  3507. GUID_KEY = Ember.GUID_KEY, // utils.js
  3508. META_KEY = Ember.META_KEY, // utils.js
  3509. removeChainWatcher = Ember.removeChainWatcher,
  3510. watchKey = Ember.watchKey, // watch_key.js
  3511. unwatchKey = Ember.unwatchKey,
  3512. watchPath = Ember.watchPath, // watch_path.js
  3513. unwatchPath = Ember.unwatchPath,
  3514. typeOf = Ember.typeOf, // utils.js
  3515. generateGuid = Ember.generateGuid,
  3516. IS_PATH = /[\.\*]/;
  3517. // returns true if the passed path is just a keyName
  3518. function isKeyName(path) {
  3519. return path==='*' || !IS_PATH.test(path);
  3520. }
  3521. /**
  3522. Starts watching a property on an object. Whenever the property changes,
  3523. invokes `Ember.propertyWillChange` and `Ember.propertyDidChange`. This is the
  3524. primitive used by observers and dependent keys; usually you will never call
  3525. this method directly but instead use higher level methods like
  3526. `Ember.addObserver()`
  3527. @private
  3528. @method watch
  3529. @for Ember
  3530. @param obj
  3531. @param {String} keyName
  3532. */
  3533. Ember.watch = function(obj, _keyPath, m) {
  3534. // can't watch length on Array - it is special...
  3535. if (_keyPath === 'length' && typeOf(obj) === 'array') { return; }
  3536. if (isKeyName(_keyPath)) {
  3537. watchKey(obj, _keyPath, m);
  3538. } else {
  3539. watchPath(obj, _keyPath, m);
  3540. }
  3541. };
  3542. Ember.isWatching = function isWatching(obj, key) {
  3543. var meta = obj[META_KEY];
  3544. return (meta && meta.watching[key]) > 0;
  3545. };
  3546. Ember.watch.flushPending = Ember.flushPendingChains;
  3547. Ember.unwatch = function(obj, _keyPath, m) {
  3548. // can't watch length on Array - it is special...
  3549. if (_keyPath === 'length' && typeOf(obj) === 'array') { return; }
  3550. if (isKeyName(_keyPath)) {
  3551. unwatchKey(obj, _keyPath, m);
  3552. } else {
  3553. unwatchPath(obj, _keyPath, m);
  3554. }
  3555. };
  3556. /**
  3557. Call on an object when you first beget it from another object. This will
  3558. setup any chained watchers on the object instance as needed. This method is
  3559. safe to call multiple times.
  3560. @private
  3561. @method rewatch
  3562. @for Ember
  3563. @param obj
  3564. */
  3565. Ember.rewatch = function(obj) {
  3566. var m = obj[META_KEY], chains = m && m.chains;
  3567. // make sure the object has its own guid.
  3568. if (GUID_KEY in obj && !obj.hasOwnProperty(GUID_KEY)) {
  3569. generateGuid(obj);
  3570. }
  3571. // make sure any chained watchers update.
  3572. if (chains && chains.value() !== obj) {
  3573. m.chains = chains.copy(obj);
  3574. }
  3575. };
  3576. var NODE_STACK = [];
  3577. /**
  3578. Tears down the meta on an object so that it can be garbage collected.
  3579. Multiple calls will have no effect.
  3580. @method destroy
  3581. @for Ember
  3582. @param {Object} obj the object to destroy
  3583. @return {void}
  3584. */
  3585. Ember.destroy = function (obj) {
  3586. var meta = obj[META_KEY], node, nodes, key, nodeObject;
  3587. if (meta) {
  3588. obj[META_KEY] = null;
  3589. // remove chainWatchers to remove circular references that would prevent GC
  3590. node = meta.chains;
  3591. if (node) {
  3592. NODE_STACK.push(node);
  3593. // process tree
  3594. while (NODE_STACK.length > 0) {
  3595. node = NODE_STACK.pop();
  3596. // push children
  3597. nodes = node._chains;
  3598. if (nodes) {
  3599. for (key in nodes) {
  3600. if (nodes.hasOwnProperty(key)) {
  3601. NODE_STACK.push(nodes[key]);
  3602. }
  3603. }
  3604. }
  3605. // remove chainWatcher in node object
  3606. if (node._watching) {
  3607. nodeObject = node._object;
  3608. if (nodeObject) {
  3609. removeChainWatcher(nodeObject, node._key, node);
  3610. }
  3611. }
  3612. }
  3613. }
  3614. }
  3615. };
  3616. })();
  3617. (function() {
  3618. /**
  3619. @module ember-metal
  3620. */
  3621. 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);
  3622. var get = Ember.get,
  3623. set = Ember.set,
  3624. metaFor = Ember.meta,
  3625. a_slice = [].slice,
  3626. o_create = Ember.create,
  3627. META_KEY = Ember.META_KEY,
  3628. watch = Ember.watch,
  3629. unwatch = Ember.unwatch;
  3630. var expandProperties = Ember.expandProperties;
  3631. // ..........................................................
  3632. // DEPENDENT KEYS
  3633. //
  3634. // data structure:
  3635. // meta.deps = {
  3636. // 'depKey': {
  3637. // 'keyName': count,
  3638. // }
  3639. // }
  3640. /*
  3641. This function returns a map of unique dependencies for a
  3642. given object and key.
  3643. */
  3644. function keysForDep(depsMeta, depKey) {
  3645. var keys = depsMeta[depKey];
  3646. if (!keys) {
  3647. // if there are no dependencies yet for a the given key
  3648. // create a new empty list of dependencies for the key
  3649. keys = depsMeta[depKey] = {};
  3650. } else if (!depsMeta.hasOwnProperty(depKey)) {
  3651. // otherwise if the dependency list is inherited from
  3652. // a superclass, clone the hash
  3653. keys = depsMeta[depKey] = o_create(keys);
  3654. }
  3655. return keys;
  3656. }
  3657. function metaForDeps(meta) {
  3658. return keysForDep(meta, 'deps');
  3659. }
  3660. function addDependentKeys(desc, obj, keyName, meta) {
  3661. // the descriptor has a list of dependent keys, so
  3662. // add all of its dependent keys.
  3663. var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys;
  3664. if (!depKeys) return;
  3665. depsMeta = metaForDeps(meta);
  3666. for(idx = 0, len = depKeys.length; idx < len; idx++) {
  3667. depKey = depKeys[idx];
  3668. // Lookup keys meta for depKey
  3669. keys = keysForDep(depsMeta, depKey);
  3670. // Increment the number of times depKey depends on keyName.
  3671. keys[keyName] = (keys[keyName] || 0) + 1;
  3672. // Watch the depKey
  3673. watch(obj, depKey, meta);
  3674. }
  3675. }
  3676. function removeDependentKeys(desc, obj, keyName, meta) {
  3677. // the descriptor has a list of dependent keys, so
  3678. // add all of its dependent keys.
  3679. var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys;
  3680. if (!depKeys) return;
  3681. depsMeta = metaForDeps(meta);
  3682. for(idx = 0, len = depKeys.length; idx < len; idx++) {
  3683. depKey = depKeys[idx];
  3684. // Lookup keys meta for depKey
  3685. keys = keysForDep(depsMeta, depKey);
  3686. // Increment the number of times depKey depends on keyName.
  3687. keys[keyName] = (keys[keyName] || 0) - 1;
  3688. // Watch the depKey
  3689. unwatch(obj, depKey, meta);
  3690. }
  3691. }
  3692. // ..........................................................
  3693. // COMPUTED PROPERTY
  3694. //
  3695. /**
  3696. A computed property transforms an objects function into a property.
  3697. By default the function backing the computed property will only be called
  3698. once and the result will be cached. You can specify various properties
  3699. that your computed property is dependent on. This will force the cached
  3700. result to be recomputed if the dependencies are modified.
  3701. In the following example we declare a computed property (by calling
  3702. `.property()` on the fullName function) and setup the properties
  3703. dependencies (depending on firstName and lastName). The fullName function
  3704. will be called once (regardless of how many times it is accessed) as long
  3705. as it's dependencies have not been changed. Once firstName or lastName are updated
  3706. any future calls (or anything bound) to fullName will incorporate the new
  3707. values.
  3708. ```javascript
  3709. Person = Ember.Object.extend({
  3710. // these will be supplied by `create`
  3711. firstName: null,
  3712. lastName: null,
  3713. fullName: function() {
  3714. var firstName = this.get('firstName');
  3715. var lastName = this.get('lastName');
  3716. return firstName + ' ' + lastName;
  3717. }.property('firstName', 'lastName')
  3718. });
  3719. var tom = Person.create({
  3720. firstName: "Tom",
  3721. lastName: "Dale"
  3722. });
  3723. tom.get('fullName') // "Tom Dale"
  3724. ```
  3725. You can also define what Ember should do when setting a computed property.
  3726. If you try to set a computed property, it will be invoked with the key and
  3727. value you want to set it to. You can also accept the previous value as the
  3728. third parameter.
  3729. ```javascript
  3730. Person = Ember.Object.extend({
  3731. // these will be supplied by `create`
  3732. firstName: null,
  3733. lastName: null,
  3734. fullName: function(key, value, oldValue) {
  3735. // getter
  3736. if (arguments.length === 1) {
  3737. var firstName = this.get('firstName');
  3738. var lastName = this.get('lastName');
  3739. return firstName + ' ' + lastName;
  3740. // setter
  3741. } else {
  3742. var name = value.split(" ");
  3743. this.set('firstName', name[0]);
  3744. this.set('lastName', name[1]);
  3745. return value;
  3746. }
  3747. }.property('firstName', 'lastName')
  3748. });
  3749. var person = Person.create();
  3750. person.set('fullName', "Peter Wagenet");
  3751. person.get('firstName') // Peter
  3752. person.get('lastName') // Wagenet
  3753. ```
  3754. @class ComputedProperty
  3755. @namespace Ember
  3756. @extends Ember.Descriptor
  3757. @constructor
  3758. */
  3759. function ComputedProperty(func, opts) {
  3760. this.func = func;
  3761. this._dependentKeys = opts && opts.dependentKeys;
  3762. this._cacheable = (opts && opts.cacheable !== undefined) ? opts.cacheable : true;
  3763. this._readOnly = opts && (opts.readOnly !== undefined || !!opts.readOnly);
  3764. }
  3765. Ember.ComputedProperty = ComputedProperty;
  3766. ComputedProperty.prototype = new Ember.Descriptor();
  3767. var ComputedPropertyPrototype = ComputedProperty.prototype;
  3768. /**
  3769. Properties are cacheable by default. Computed property will automatically
  3770. cache the return value of your function until one of the dependent keys changes.
  3771. Call `volatile()` to set it into non-cached mode. When in this mode
  3772. the computed property will not automatically cache the return value.
  3773. However, if a property is properly observable, there is no reason to disable
  3774. caching.
  3775. @method cacheable
  3776. @param {Boolean} aFlag optional set to `false` to disable caching
  3777. @return {Ember.ComputedProperty} this
  3778. @chainable
  3779. */
  3780. ComputedPropertyPrototype.cacheable = function(aFlag) {
  3781. this._cacheable = aFlag !== false;
  3782. return this;
  3783. };
  3784. /**
  3785. Call on a computed property to set it into non-cached mode. When in this
  3786. mode the computed property will not automatically cache the return value.
  3787. ```javascript
  3788. MyApp.outsideService = Ember.Object.extend({
  3789. value: function() {
  3790. return OutsideService.getValue();
  3791. }.property().volatile()
  3792. }).create();
  3793. ```
  3794. @method volatile
  3795. @return {Ember.ComputedProperty} this
  3796. @chainable
  3797. */
  3798. ComputedPropertyPrototype.volatile = function() {
  3799. return this.cacheable(false);
  3800. };
  3801. /**
  3802. Call on a computed property to set it into read-only mode. When in this
  3803. mode the computed property will throw an error when set.
  3804. ```javascript
  3805. MyApp.Person = Ember.Object.extend({
  3806. guid: function() {
  3807. return 'guid-guid-guid';
  3808. }.property().readOnly()
  3809. });
  3810. MyApp.person = MyApp.Person.create();
  3811. MyApp.person.set('guid', 'new-guid'); // will throw an exception
  3812. ```
  3813. @method readOnly
  3814. @return {Ember.ComputedProperty} this
  3815. @chainable
  3816. */
  3817. ComputedPropertyPrototype.readOnly = function(readOnly) {
  3818. this._readOnly = readOnly === undefined || !!readOnly;
  3819. return this;
  3820. };
  3821. /**
  3822. Sets the dependent keys on this computed property. Pass any number of
  3823. arguments containing key paths that this computed property depends on.
  3824. ```javascript
  3825. MyApp.President = Ember.Object.extend({
  3826. fullName: Ember.computed(function() {
  3827. return this.get('firstName') + ' ' + this.get('lastName');
  3828. // Tell Ember that this computed property depends on firstName
  3829. // and lastName
  3830. }).property('firstName', 'lastName')
  3831. });
  3832. MyApp.president = MyApp.President.create({
  3833. firstName: 'Barack',
  3834. lastName: 'Obama',
  3835. });
  3836. MyApp.president.get('fullName'); // Barack Obama
  3837. ```
  3838. @method property
  3839. @param {String} path* zero or more property paths
  3840. @return {Ember.ComputedProperty} this
  3841. @chainable
  3842. */
  3843. ComputedPropertyPrototype.property = function() {
  3844. var args;
  3845. var addArg = function (property) {
  3846. args.push(property);
  3847. };
  3848. args = [];
  3849. for (var i = 0, l = arguments.length; i < l; i++) {
  3850. expandProperties(arguments[i], addArg);
  3851. }
  3852. this._dependentKeys = args;
  3853. return this;
  3854. };
  3855. /**
  3856. In some cases, you may want to annotate computed properties with additional
  3857. metadata about how they function or what values they operate on. For example,
  3858. computed property functions may close over variables that are then no longer
  3859. available for introspection.
  3860. You can pass a hash of these values to a computed property like this:
  3861. ```
  3862. person: function() {
  3863. var personId = this.get('personId');
  3864. return App.Person.create({ id: personId });
  3865. }.property().meta({ type: App.Person })
  3866. ```
  3867. The hash that you pass to the `meta()` function will be saved on the
  3868. computed property descriptor under the `_meta` key. Ember runtime
  3869. exposes a public API for retrieving these values from classes,
  3870. via the `metaForProperty()` function.
  3871. @method meta
  3872. @param {Hash} meta
  3873. @chainable
  3874. */
  3875. ComputedPropertyPrototype.meta = function(meta) {
  3876. if (arguments.length === 0) {
  3877. return this._meta || {};
  3878. } else {
  3879. this._meta = meta;
  3880. return this;
  3881. }
  3882. };
  3883. /* impl descriptor API */
  3884. ComputedPropertyPrototype.didChange = function(obj, keyName) {
  3885. // _suspended is set via a CP.set to ensure we don't clear
  3886. // the cached value set by the setter
  3887. if (this._cacheable && this._suspended !== obj) {
  3888. var meta = metaFor(obj);
  3889. if (keyName in meta.cache) {
  3890. delete meta.cache[keyName];
  3891. removeDependentKeys(this, obj, keyName, meta);
  3892. }
  3893. }
  3894. };
  3895. function finishChains(chainNodes)
  3896. {
  3897. for (var i=0, l=chainNodes.length; i<l; i++) {
  3898. chainNodes[i].didChange(null);
  3899. }
  3900. }
  3901. /**
  3902. Access the value of the function backing the computed property.
  3903. If this property has already been cached, return the cached result.
  3904. Otherwise, call the function passing the property name as an argument.
  3905. ```javascript
  3906. Person = Ember.Object.extend({
  3907. fullName: function(keyName) {
  3908. // the keyName parameter is 'fullName' in this case.
  3909. return this.get('firstName') + ' ' + this.get('lastName');
  3910. }.property('firstName', 'lastName')
  3911. });
  3912. var tom = Person.create({
  3913. firstName: "Tom",
  3914. lastName: "Dale"
  3915. });
  3916. tom.get('fullName') // "Tom Dale"
  3917. ```
  3918. @method get
  3919. @param {String} keyName The key being accessed.
  3920. @return {Object} The return value of the function backing the CP.
  3921. */
  3922. ComputedPropertyPrototype.get = function(obj, keyName) {
  3923. var ret, cache, meta, chainNodes;
  3924. if (this._cacheable) {
  3925. meta = metaFor(obj);
  3926. cache = meta.cache;
  3927. if (keyName in cache) { return cache[keyName]; }
  3928. ret = cache[keyName] = this.func.call(obj, keyName);
  3929. chainNodes = meta.chainWatchers && meta.chainWatchers[keyName];
  3930. if (chainNodes) { finishChains(chainNodes); }
  3931. addDependentKeys(this, obj, keyName, meta);
  3932. } else {
  3933. ret = this.func.call(obj, keyName);
  3934. }
  3935. return ret;
  3936. };
  3937. /**
  3938. Set the value of a computed property. If the function that backs your
  3939. computed property does not accept arguments then the default action for
  3940. setting would be to define the property on the current object, and set
  3941. the value of the property to the value being set.
  3942. Generally speaking if you intend for your computed property to be set
  3943. your backing function should accept either two or three arguments.
  3944. @method set
  3945. @param {String} keyName The key being accessed.
  3946. @param {Object} newValue The new value being assigned.
  3947. @param {String} oldValue The old value being replaced.
  3948. @return {Object} The return value of the function backing the CP.
  3949. */
  3950. ComputedPropertyPrototype.set = function(obj, keyName, value) {
  3951. var cacheable = this._cacheable,
  3952. func = this.func,
  3953. meta = metaFor(obj, cacheable),
  3954. watched = meta.watching[keyName],
  3955. oldSuspended = this._suspended,
  3956. hadCachedValue = false,
  3957. cache = meta.cache,
  3958. funcArgLength, cachedValue, ret;
  3959. if (this._readOnly) {
  3960. throw new Ember.Error('Cannot Set: ' + keyName + ' on: ' + Ember.inspect(obj));
  3961. }
  3962. this._suspended = obj;
  3963. try {
  3964. if (cacheable && cache.hasOwnProperty(keyName)) {
  3965. cachedValue = cache[keyName];
  3966. hadCachedValue = true;
  3967. }
  3968. // Check if the CP has been wrapped. If if has, use the
  3969. // length from the wrapped function.
  3970. funcArgLength = (func.wrappedFunction ? func.wrappedFunction.length : func.length);
  3971. // For backwards-compatibility with computed properties
  3972. // that check for arguments.length === 2 to determine if
  3973. // they are being get or set, only pass the old cached
  3974. // value if the computed property opts into a third
  3975. // argument.
  3976. if (funcArgLength === 3) {
  3977. ret = func.call(obj, keyName, value, cachedValue);
  3978. } else if (funcArgLength === 2) {
  3979. ret = func.call(obj, keyName, value);
  3980. } else {
  3981. Ember.defineProperty(obj, keyName, null, cachedValue);
  3982. Ember.set(obj, keyName, value);
  3983. return;
  3984. }
  3985. if (hadCachedValue && cachedValue === ret) { return; }
  3986. if (watched) { Ember.propertyWillChange(obj, keyName); }
  3987. if (hadCachedValue) {
  3988. delete cache[keyName];
  3989. }
  3990. if (cacheable) {
  3991. if (!hadCachedValue) {
  3992. addDependentKeys(this, obj, keyName, meta);
  3993. }
  3994. cache[keyName] = ret;
  3995. }
  3996. if (watched) { Ember.propertyDidChange(obj, keyName); }
  3997. } finally {
  3998. this._suspended = oldSuspended;
  3999. }
  4000. return ret;
  4001. };
  4002. /* called before property is overridden */
  4003. ComputedPropertyPrototype.teardown = function(obj, keyName) {
  4004. var meta = metaFor(obj);
  4005. if (keyName in meta.cache) {
  4006. removeDependentKeys(this, obj, keyName, meta);
  4007. }
  4008. if (this._cacheable) { delete meta.cache[keyName]; }
  4009. return null; // no value to restore
  4010. };
  4011. /**
  4012. This helper returns a new property descriptor that wraps the passed
  4013. computed property function. You can use this helper to define properties
  4014. with mixins or via `Ember.defineProperty()`.
  4015. The function you pass will be used to both get and set property values.
  4016. The function should accept two parameters, key and value. If value is not
  4017. undefined you should set the value first. In either case return the
  4018. current value of the property.
  4019. @method computed
  4020. @for Ember
  4021. @param {Function} func The computed property function.
  4022. @return {Ember.ComputedProperty} property descriptor instance
  4023. */
  4024. Ember.computed = function(func) {
  4025. var args;
  4026. if (arguments.length > 1) {
  4027. args = a_slice.call(arguments, 0, -1);
  4028. func = a_slice.call(arguments, -1)[0];
  4029. }
  4030. if (typeof func !== "function") {
  4031. throw new Ember.Error("Computed Property declared without a property function");
  4032. }
  4033. var cp = new ComputedProperty(func);
  4034. if (args) {
  4035. cp.property.apply(cp, args);
  4036. }
  4037. return cp;
  4038. };
  4039. /**
  4040. Returns the cached value for a property, if one exists.
  4041. This can be useful for peeking at the value of a computed
  4042. property that is generated lazily, without accidentally causing
  4043. it to be created.
  4044. @method cacheFor
  4045. @for Ember
  4046. @param {Object} obj the object whose property you want to check
  4047. @param {String} key the name of the property whose cached value you want
  4048. to return
  4049. @return {Object} the cached value
  4050. */
  4051. Ember.cacheFor = function cacheFor(obj, key) {
  4052. var meta = obj[META_KEY],
  4053. cache = meta && meta.cache;
  4054. if (cache && key in cache) {
  4055. return cache[key];
  4056. }
  4057. };
  4058. function getProperties(self, propertyNames) {
  4059. var ret = {};
  4060. for(var i = 0; i < propertyNames.length; i++) {
  4061. ret[propertyNames[i]] = get(self, propertyNames[i]);
  4062. }
  4063. return ret;
  4064. }
  4065. var registerComputed, registerComputedWithProperties;
  4066. registerComputed = function (name, macro) {
  4067. Ember.computed[name] = function(dependentKey) {
  4068. var args = a_slice.call(arguments);
  4069. return Ember.computed(dependentKey, function() {
  4070. return macro.apply(this, args);
  4071. });
  4072. };
  4073. };
  4074. registerComputedWithProperties = function(name, macro) {
  4075. Ember.computed[name] = function() {
  4076. var properties = a_slice.call(arguments);
  4077. var computed = Ember.computed(function() {
  4078. return macro.apply(this, [getProperties(this, properties)]);
  4079. });
  4080. return computed.property.apply(computed, properties);
  4081. };
  4082. };
  4083. /**
  4084. A computed property that returns true if the value of the dependent
  4085. property is null, an empty string, empty array, or empty function.
  4086. Note: When using `Ember.computed.empty` to watch an array make sure to
  4087. use the `array.[]` syntax so the computed can subscribe to transitions
  4088. from empty to non-empty states.
  4089. Example
  4090. ```javascript
  4091. var ToDoList = Ember.Object.extend({
  4092. done: Ember.computed.empty('todos.[]') // detect array changes
  4093. });
  4094. var todoList = ToDoList.create({todos: ['Unit Test', 'Documentation', 'Release']});
  4095. todoList.get('done'); // false
  4096. todoList.get('todos').clear(); // []
  4097. todoList.get('done'); // true
  4098. ```
  4099. @method computed.empty
  4100. @for Ember
  4101. @param {String} dependentKey
  4102. @return {Ember.ComputedProperty} computed property which negate
  4103. the original value for property
  4104. */
  4105. registerComputed('empty', function(dependentKey) {
  4106. return Ember.isEmpty(get(this, dependentKey));
  4107. });
  4108. /**
  4109. A computed property that returns true if the value of the dependent
  4110. property is NOT null, an empty string, empty array, or empty function.
  4111. Note: When using `Ember.computed.notEmpty` to watch an array make sure to
  4112. use the `array.[]` syntax so the computed can subscribe to transitions
  4113. from empty to non-empty states.
  4114. Example
  4115. ```javascript
  4116. var Hamster = Ember.Object.extend({
  4117. hasStuff: Ember.computed.notEmpty('backpack.[]')
  4118. });
  4119. var hamster = Hamster.create({backpack: ['Food', 'Sleeping Bag', 'Tent']});
  4120. hamster.get('hasStuff'); // true
  4121. hamster.get('backpack').clear(); // []
  4122. hamster.get('hasStuff'); // false
  4123. ```
  4124. @method computed.notEmpty
  4125. @for Ember
  4126. @param {String} dependentKey
  4127. @return {Ember.ComputedProperty} computed property which returns true if
  4128. original value for property is not empty.
  4129. */
  4130. registerComputed('notEmpty', function(dependentKey) {
  4131. return !Ember.isEmpty(get(this, dependentKey));
  4132. });
  4133. /**
  4134. A computed property that returns true if the value of the dependent
  4135. property is null or undefined. This avoids errors from JSLint complaining
  4136. about use of ==, which can be technically confusing.
  4137. Example
  4138. ```javascript
  4139. var Hamster = Ember.Object.extend({
  4140. isHungry: Ember.computed.none('food')
  4141. });
  4142. var hamster = Hamster.create();
  4143. hamster.get('isHungry'); // true
  4144. hamster.set('food', 'Banana');
  4145. hamster.get('isHungry'); // false
  4146. hamster.set('food', null);
  4147. hamster.get('isHungry'); // true
  4148. ```
  4149. @method computed.none
  4150. @for Ember
  4151. @param {String} dependentKey
  4152. @return {Ember.ComputedProperty} computed property which
  4153. returns true if original value for property is null or undefined.
  4154. */
  4155. registerComputed('none', function(dependentKey) {
  4156. return Ember.isNone(get(this, dependentKey));
  4157. });
  4158. /**
  4159. A computed property that returns the inverse boolean value
  4160. of the original value for the dependent property.
  4161. Example
  4162. ```javascript
  4163. var User = Ember.Object.extend({
  4164. isAnonymous: Ember.computed.not('loggedIn')
  4165. });
  4166. var user = User.create({loggedIn: false});
  4167. user.get('isAnonymous'); // true
  4168. user.set('loggedIn', true);
  4169. user.get('isAnonymous'); // false
  4170. ```
  4171. @method computed.not
  4172. @for Ember
  4173. @param {String} dependentKey
  4174. @return {Ember.ComputedProperty} computed property which returns
  4175. inverse of the original value for property
  4176. */
  4177. registerComputed('not', function(dependentKey) {
  4178. return !get(this, dependentKey);
  4179. });
  4180. /**
  4181. A computed property that converts the provided dependent property
  4182. into a boolean value.
  4183. ```javascript
  4184. var Hamster = Ember.Object.extend({
  4185. hasBananas: Ember.computed.bool('numBananas')
  4186. });
  4187. var hamster = Hamster.create();
  4188. hamster.get('hasBananas'); // false
  4189. hamster.set('numBananas', 0);
  4190. hamster.get('hasBananas'); // false
  4191. hamster.set('numBananas', 1);
  4192. hamster.get('hasBananas'); // true
  4193. hamster.set('numBananas', null);
  4194. hamster.get('hasBananas'); // false
  4195. ```
  4196. @method computed.bool
  4197. @for Ember
  4198. @param {String} dependentKey
  4199. @return {Ember.ComputedProperty} computed property which converts
  4200. to boolean the original value for property
  4201. */
  4202. registerComputed('bool', function(dependentKey) {
  4203. return !!get(this, dependentKey);
  4204. });
  4205. /**
  4206. A computed property which matches the original value for the
  4207. dependent property against a given RegExp, returning `true`
  4208. if they values matches the RegExp and `false` if it does not.
  4209. Example
  4210. ```javascript
  4211. var User = Ember.Object.extend({
  4212. hasValidEmail: Ember.computed.match('email', /^.+@.+\..+$/)
  4213. });
  4214. var user = User.create({loggedIn: false});
  4215. user.get('hasValidEmail'); // false
  4216. user.set('email', '');
  4217. user.get('hasValidEmail'); // false
  4218. user.set('email', 'ember_hamster@example.com');
  4219. user.get('hasValidEmail'); // true
  4220. ```
  4221. @method computed.match
  4222. @for Ember
  4223. @param {String} dependentKey
  4224. @param {RegExp} regexp
  4225. @return {Ember.ComputedProperty} computed property which match
  4226. the original value for property against a given RegExp
  4227. */
  4228. registerComputed('match', function(dependentKey, regexp) {
  4229. var value = get(this, dependentKey);
  4230. return typeof value === 'string' ? regexp.test(value) : false;
  4231. });
  4232. /**
  4233. A computed property that returns true if the provided dependent property
  4234. is equal to the given value.
  4235. Example
  4236. ```javascript
  4237. var Hamster = Ember.Object.extend({
  4238. napTime: Ember.computed.equal('state', 'sleepy')
  4239. });
  4240. var hamster = Hamster.create();
  4241. hamster.get('napTime'); // false
  4242. hamster.set('state', 'sleepy');
  4243. hamster.get('napTime'); // true
  4244. hamster.set('state', 'hungry');
  4245. hamster.get('napTime'); // false
  4246. ```
  4247. @method computed.equal
  4248. @for Ember
  4249. @param {String} dependentKey
  4250. @param {String|Number|Object} value
  4251. @return {Ember.ComputedProperty} computed property which returns true if
  4252. the original value for property is equal to the given value.
  4253. */
  4254. registerComputed('equal', function(dependentKey, value) {
  4255. return get(this, dependentKey) === value;
  4256. });
  4257. /**
  4258. A computed property that returns true if the provied dependent property
  4259. is greater than the provided value.
  4260. Example
  4261. ```javascript
  4262. var Hamster = Ember.Object.extend({
  4263. hasTooManyBananas: Ember.computed.gt('numBananas', 10)
  4264. });
  4265. var hamster = Hamster.create();
  4266. hamster.get('hasTooManyBananas'); // false
  4267. hamster.set('numBananas', 3);
  4268. hamster.get('hasTooManyBananas'); // false
  4269. hamster.set('numBananas', 11);
  4270. hamster.get('hasTooManyBananas'); // true
  4271. ```
  4272. @method computed.gt
  4273. @for Ember
  4274. @param {String} dependentKey
  4275. @param {Number} value
  4276. @return {Ember.ComputedProperty} computed property which returns true if
  4277. the original value for property is greater then given value.
  4278. */
  4279. registerComputed('gt', function(dependentKey, value) {
  4280. return get(this, dependentKey) > value;
  4281. });
  4282. /**
  4283. A computed property that returns true if the provided dependent property
  4284. is greater than or equal to the provided value.
  4285. Example
  4286. ```javascript
  4287. var Hamster = Ember.Object.extend({
  4288. hasTooManyBananas: Ember.computed.gte('numBananas', 10)
  4289. });
  4290. var hamster = Hamster.create();
  4291. hamster.get('hasTooManyBananas'); // false
  4292. hamster.set('numBananas', 3);
  4293. hamster.get('hasTooManyBananas'); // false
  4294. hamster.set('numBananas', 10);
  4295. hamster.get('hasTooManyBananas'); // true
  4296. ```
  4297. @method computed.gte
  4298. @for Ember
  4299. @param {String} dependentKey
  4300. @param {Number} value
  4301. @return {Ember.ComputedProperty} computed property which returns true if
  4302. the original value for property is greater or equal then given value.
  4303. */
  4304. registerComputed('gte', function(dependentKey, value) {
  4305. return get(this, dependentKey) >= value;
  4306. });
  4307. /**
  4308. A computed property that returns true if the provided dependent property
  4309. is less than the provided value.
  4310. Example
  4311. ```javascript
  4312. var Hamster = Ember.Object.extend({
  4313. needsMoreBananas: Ember.computed.lt('numBananas', 3)
  4314. });
  4315. var hamster = Hamster.create();
  4316. hamster.get('needsMoreBananas'); // true
  4317. hamster.set('numBananas', 3);
  4318. hamster.get('needsMoreBananas'); // false
  4319. hamster.set('numBananas', 2);
  4320. hamster.get('needsMoreBananas'); // true
  4321. ```
  4322. @method computed.lt
  4323. @for Ember
  4324. @param {String} dependentKey
  4325. @param {Number} value
  4326. @return {Ember.ComputedProperty} computed property which returns true if
  4327. the original value for property is less then given value.
  4328. */
  4329. registerComputed('lt', function(dependentKey, value) {
  4330. return get(this, dependentKey) < value;
  4331. });
  4332. /**
  4333. A computed property that returns true if the provided dependent property
  4334. is less than or equal to the provided value.
  4335. Example
  4336. ```javascript
  4337. var Hamster = Ember.Object.extend({
  4338. needsMoreBananas: Ember.computed.lte('numBananas', 3)
  4339. });
  4340. var hamster = Hamster.create();
  4341. hamster.get('needsMoreBananas'); // true
  4342. hamster.set('numBananas', 5);
  4343. hamster.get('needsMoreBananas'); // false
  4344. hamster.set('numBananas', 3);
  4345. hamster.get('needsMoreBananas'); // true
  4346. ```
  4347. @method computed.lte
  4348. @for Ember
  4349. @param {String} dependentKey
  4350. @param {Number} value
  4351. @return {Ember.ComputedProperty} computed property which returns true if
  4352. the original value for property is less or equal then given value.
  4353. */
  4354. registerComputed('lte', function(dependentKey, value) {
  4355. return get(this, dependentKey) <= value;
  4356. });
  4357. /**
  4358. A computed property that performs a logical `and` on the
  4359. original values for the provided dependent properties.
  4360. Example
  4361. ```javascript
  4362. var Hamster = Ember.Object.extend({
  4363. readyForCamp: Ember.computed.and('hasTent', 'hasBackpack')
  4364. });
  4365. var hamster = Hamster.create();
  4366. hamster.get('readyForCamp'); // false
  4367. hamster.set('hasTent', true);
  4368. hamster.get('readyForCamp'); // false
  4369. hamster.set('hasBackpack', true);
  4370. hamster.get('readyForCamp'); // true
  4371. ```
  4372. @method computed.and
  4373. @for Ember
  4374. @param {String} dependentKey*
  4375. @return {Ember.ComputedProperty} computed property which performs
  4376. a logical `and` on the values of all the original values for properties.
  4377. */
  4378. registerComputedWithProperties('and', function(properties) {
  4379. for (var key in properties) {
  4380. if (properties.hasOwnProperty(key) && !properties[key]) {
  4381. return false;
  4382. }
  4383. }
  4384. return true;
  4385. });
  4386. /**
  4387. A computed property which performs a logical `or` on the
  4388. original values for the provided dependent properties.
  4389. Example
  4390. ```javascript
  4391. var Hamster = Ember.Object.extend({
  4392. readyForRain: Ember.computed.or('hasJacket', 'hasUmbrella')
  4393. });
  4394. var hamster = Hamster.create();
  4395. hamster.get('readyForRain'); // false
  4396. hamster.set('hasJacket', true);
  4397. hamster.get('readyForRain'); // true
  4398. ```
  4399. @method computed.or
  4400. @for Ember
  4401. @param {String} dependentKey*
  4402. @return {Ember.ComputedProperty} computed property which performs
  4403. a logical `or` on the values of all the original values for properties.
  4404. */
  4405. registerComputedWithProperties('or', function(properties) {
  4406. for (var key in properties) {
  4407. if (properties.hasOwnProperty(key) && properties[key]) {
  4408. return true;
  4409. }
  4410. }
  4411. return false;
  4412. });
  4413. /**
  4414. A computed property that returns the first truthy value
  4415. from a list of dependent properties.
  4416. Example
  4417. ```javascript
  4418. var Hamster = Ember.Object.extend({
  4419. hasClothes: Ember.computed.any('hat', 'shirt')
  4420. });
  4421. var hamster = Hamster.create();
  4422. hamster.get('hasClothes'); // null
  4423. hamster.set('shirt', 'Hawaiian Shirt');
  4424. hamster.get('hasClothes'); // 'Hawaiian Shirt'
  4425. ```
  4426. @method computed.any
  4427. @for Ember
  4428. @param {String} dependentKey*
  4429. @return {Ember.ComputedProperty} computed property which returns
  4430. the first truthy value of given list of properties.
  4431. */
  4432. registerComputedWithProperties('any', function(properties) {
  4433. for (var key in properties) {
  4434. if (properties.hasOwnProperty(key) && properties[key]) {
  4435. return properties[key];
  4436. }
  4437. }
  4438. return null;
  4439. });
  4440. /**
  4441. A computed property that returns the array of values
  4442. for the provided dependent properties.
  4443. Example
  4444. ```javascript
  4445. var Hamster = Ember.Object.extend({
  4446. clothes: Ember.computed.collect('hat', 'shirt')
  4447. });
  4448. var hamster = Hamster.create();
  4449. hamster.get('clothes'); // [null, null]
  4450. hamster.set('hat', 'Camp Hat');
  4451. hamster.set('shirt', 'Camp Shirt');
  4452. hamster.get('clothes'); // ['Camp Hat', 'Camp Shirt']
  4453. ```
  4454. @method computed.collect
  4455. @for Ember
  4456. @param {String} dependentKey*
  4457. @return {Ember.ComputedProperty} computed property which maps
  4458. values of all passed properties in to an array.
  4459. */
  4460. registerComputedWithProperties('collect', function(properties) {
  4461. var res = [];
  4462. for (var key in properties) {
  4463. if (properties.hasOwnProperty(key)) {
  4464. if (Ember.isNone(properties[key])) {
  4465. res.push(null);
  4466. } else {
  4467. res.push(properties[key]);
  4468. }
  4469. }
  4470. }
  4471. return res;
  4472. });
  4473. /**
  4474. Creates a new property that is an alias for another property
  4475. on an object. Calls to `get` or `set` this property behave as
  4476. though they were called on the original property.
  4477. ```javascript
  4478. Person = Ember.Object.extend({
  4479. name: 'Alex Matchneer',
  4480. nomen: Ember.computed.alias('name')
  4481. });
  4482. alex = Person.create();
  4483. alex.get('nomen'); // 'Alex Matchneer'
  4484. alex.get('name'); // 'Alex Matchneer'
  4485. alex.set('nomen', '@machty');
  4486. alex.get('name'); // '@machty'
  4487. ```
  4488. @method computed.alias
  4489. @for Ember
  4490. @param {String} dependentKey
  4491. @return {Ember.ComputedProperty} computed property which creates an
  4492. alias to the original value for property.
  4493. */
  4494. Ember.computed.alias = function(dependentKey) {
  4495. return Ember.computed(dependentKey, function(key, value) {
  4496. if (arguments.length > 1) {
  4497. set(this, dependentKey, value);
  4498. return value;
  4499. } else {
  4500. return get(this, dependentKey);
  4501. }
  4502. });
  4503. };
  4504. /**
  4505. Where `computed.alias` aliases `get` and `set`, and allows for bidirectional
  4506. data flow, `computed.oneWay` only provides an aliased `get`. The `set` will
  4507. not mutate the upstream property, rather causes the current property to
  4508. become the value set. This causes the downstream property to permentantly
  4509. diverge from the upstream property.
  4510. Example
  4511. ```javascript
  4512. User = Ember.Object.extend({
  4513. firstName: null,
  4514. lastName: null,
  4515. nickName: Ember.computed.oneWay('firstName')
  4516. });
  4517. user = User.create({
  4518. firstName: 'Teddy',
  4519. lastName: 'Zeenny'
  4520. });
  4521. user.get('nickName');
  4522. # 'Teddy'
  4523. user.set('nickName', 'TeddyBear');
  4524. # 'TeddyBear'
  4525. user.get('firstName');
  4526. # 'Teddy'
  4527. ```
  4528. @method computed.oneWay
  4529. @for Ember
  4530. @param {String} dependentKey
  4531. @return {Ember.ComputedProperty} computed property which creates a
  4532. one way computed property to the original value for property.
  4533. */
  4534. Ember.computed.oneWay = function(dependentKey) {
  4535. return Ember.computed(dependentKey, function() {
  4536. return get(this, dependentKey);
  4537. });
  4538. };
  4539. /**
  4540. A computed property that acts like a standard getter and setter,
  4541. but returns the value at the provided `defaultPath` if the
  4542. property itself has not been set to a value
  4543. Example
  4544. ```javascript
  4545. var Hamster = Ember.Object.extend({
  4546. wishList: Ember.computed.defaultTo('favoriteFood')
  4547. });
  4548. var hamster = Hamster.create({favoriteFood: 'Banana'});
  4549. hamster.get('wishList'); // 'Banana'
  4550. hamster.set('wishList', 'More Unit Tests');
  4551. hamster.get('wishList'); // 'More Unit Tests'
  4552. hamster.get('favoriteFood'); // 'Banana'
  4553. ```
  4554. @method computed.defaultTo
  4555. @for Ember
  4556. @param {String} defaultPath
  4557. @return {Ember.ComputedProperty} computed property which acts like
  4558. a standard getter and setter, but defaults to the value from `defaultPath`.
  4559. */
  4560. Ember.computed.defaultTo = function(defaultPath) {
  4561. return Ember.computed(function(key, newValue, cachedValue) {
  4562. if (arguments.length === 1) {
  4563. return cachedValue != null ? cachedValue : get(this, defaultPath);
  4564. }
  4565. return newValue != null ? newValue : get(this, defaultPath);
  4566. });
  4567. };
  4568. })();
  4569. (function() {
  4570. // Ember.tryFinally
  4571. /**
  4572. @module ember-metal
  4573. */
  4574. var AFTER_OBSERVERS = ':change',
  4575. BEFORE_OBSERVERS = ':before';
  4576. function changeEvent(keyName) {
  4577. return keyName+AFTER_OBSERVERS;
  4578. }
  4579. function beforeEvent(keyName) {
  4580. return keyName+BEFORE_OBSERVERS;
  4581. }
  4582. /**
  4583. @method addObserver
  4584. @param obj
  4585. @param {String} path
  4586. @param {Object|Function} targetOrMethod
  4587. @param {Function|String} [method]
  4588. */
  4589. Ember.addObserver = function(obj, _path, target, method) {
  4590. Ember.addListener(obj, changeEvent(_path), target, method);
  4591. Ember.watch(obj, _path);
  4592. return this;
  4593. };
  4594. Ember.observersFor = function(obj, path) {
  4595. return Ember.listenersFor(obj, changeEvent(path));
  4596. };
  4597. /**
  4598. @method removeObserver
  4599. @param obj
  4600. @param {String} path
  4601. @param {Object|Function} targetOrMethod
  4602. @param {Function|String} [method]
  4603. */
  4604. Ember.removeObserver = function(obj, _path, target, method) {
  4605. Ember.unwatch(obj, _path);
  4606. Ember.removeListener(obj, changeEvent(_path), target, method);
  4607. return this;
  4608. };
  4609. /**
  4610. @method addBeforeObserver
  4611. @param obj
  4612. @param {String} path
  4613. @param {Object|Function} targetOrMethod
  4614. @param {Function|String} [method]
  4615. */
  4616. Ember.addBeforeObserver = function(obj, _path, target, method) {
  4617. Ember.addListener(obj, beforeEvent(_path), target, method);
  4618. Ember.watch(obj, _path);
  4619. return this;
  4620. };
  4621. // Suspend observer during callback.
  4622. //
  4623. // This should only be used by the target of the observer
  4624. // while it is setting the observed path.
  4625. Ember._suspendBeforeObserver = function(obj, path, target, method, callback) {
  4626. return Ember._suspendListener(obj, beforeEvent(path), target, method, callback);
  4627. };
  4628. Ember._suspendObserver = function(obj, path, target, method, callback) {
  4629. return Ember._suspendListener(obj, changeEvent(path), target, method, callback);
  4630. };
  4631. var map = Ember.ArrayPolyfills.map;
  4632. Ember._suspendBeforeObservers = function(obj, paths, target, method, callback) {
  4633. var events = map.call(paths, beforeEvent);
  4634. return Ember._suspendListeners(obj, events, target, method, callback);
  4635. };
  4636. Ember._suspendObservers = function(obj, paths, target, method, callback) {
  4637. var events = map.call(paths, changeEvent);
  4638. return Ember._suspendListeners(obj, events, target, method, callback);
  4639. };
  4640. Ember.beforeObserversFor = function(obj, path) {
  4641. return Ember.listenersFor(obj, beforeEvent(path));
  4642. };
  4643. /**
  4644. @method removeBeforeObserver
  4645. @param obj
  4646. @param {String} path
  4647. @param {Object|Function} targetOrMethod
  4648. @param {Function|String} [method]
  4649. */
  4650. Ember.removeBeforeObserver = function(obj, _path, target, method) {
  4651. Ember.unwatch(obj, _path);
  4652. Ember.removeListener(obj, beforeEvent(_path), target, method);
  4653. return this;
  4654. };
  4655. })();
  4656. (function() {
  4657. define("backburner/queue",
  4658. ["exports"],
  4659. function(__exports__) {
  4660. "use strict";
  4661. function Queue(daq, name, options) {
  4662. this.daq = daq;
  4663. this.name = name;
  4664. this.options = options;
  4665. this._queue = [];
  4666. }
  4667. Queue.prototype = {
  4668. daq: null,
  4669. name: null,
  4670. options: null,
  4671. _queue: null,
  4672. push: function(target, method, args, stack) {
  4673. var queue = this._queue;
  4674. queue.push(target, method, args, stack);
  4675. return {queue: this, target: target, method: method};
  4676. },
  4677. pushUnique: function(target, method, args, stack) {
  4678. var queue = this._queue, currentTarget, currentMethod, i, l;
  4679. for (i = 0, l = queue.length; i < l; i += 4) {
  4680. currentTarget = queue[i];
  4681. currentMethod = queue[i+1];
  4682. if (currentTarget === target && currentMethod === method) {
  4683. queue[i+2] = args; // replace args
  4684. queue[i+3] = stack; // replace stack
  4685. return {queue: this, target: target, method: method}; // TODO: test this code path
  4686. }
  4687. }
  4688. this._queue.push(target, method, args, stack);
  4689. return {queue: this, target: target, method: method};
  4690. },
  4691. // TODO: remove me, only being used for Ember.run.sync
  4692. flush: function() {
  4693. var queue = this._queue,
  4694. options = this.options,
  4695. before = options && options.before,
  4696. after = options && options.after,
  4697. target, method, args, stack, i, l = queue.length;
  4698. if (l && before) { before(); }
  4699. for (i = 0; i < l; i += 4) {
  4700. target = queue[i];
  4701. method = queue[i+1];
  4702. args = queue[i+2];
  4703. stack = queue[i+3]; // Debugging assistance
  4704. // TODO: error handling
  4705. if (args && args.length > 0) {
  4706. method.apply(target, args);
  4707. } else {
  4708. method.call(target);
  4709. }
  4710. }
  4711. if (l && after) { after(); }
  4712. // check if new items have been added
  4713. if (queue.length > l) {
  4714. this._queue = queue.slice(l);
  4715. this.flush();
  4716. } else {
  4717. this._queue.length = 0;
  4718. }
  4719. },
  4720. cancel: function(actionToCancel) {
  4721. var queue = this._queue, currentTarget, currentMethod, i, l;
  4722. for (i = 0, l = queue.length; i < l; i += 4) {
  4723. currentTarget = queue[i];
  4724. currentMethod = queue[i+1];
  4725. if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) {
  4726. queue.splice(i, 4);
  4727. return true;
  4728. }
  4729. }
  4730. // if not found in current queue
  4731. // could be in the queue that is being flushed
  4732. queue = this._queueBeingFlushed;
  4733. if (!queue) {
  4734. return;
  4735. }
  4736. for (i = 0, l = queue.length; i < l; i += 4) {
  4737. currentTarget = queue[i];
  4738. currentMethod = queue[i+1];
  4739. if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) {
  4740. // don't mess with array during flush
  4741. // just nullify the method
  4742. queue[i+1] = null;
  4743. return true;
  4744. }
  4745. }
  4746. }
  4747. };
  4748. __exports__.Queue = Queue;
  4749. });
  4750. define("backburner/deferred_action_queues",
  4751. ["backburner/queue","exports"],
  4752. function(__dependency1__, __exports__) {
  4753. "use strict";
  4754. var Queue = __dependency1__.Queue;
  4755. function DeferredActionQueues(queueNames, options) {
  4756. var queues = this.queues = {};
  4757. this.queueNames = queueNames = queueNames || [];
  4758. var queueName;
  4759. for (var i = 0, l = queueNames.length; i < l; i++) {
  4760. queueName = queueNames[i];
  4761. queues[queueName] = new Queue(this, queueName, options[queueName]);
  4762. }
  4763. }
  4764. DeferredActionQueues.prototype = {
  4765. queueNames: null,
  4766. queues: null,
  4767. schedule: function(queueName, target, method, args, onceFlag, stack) {
  4768. var queues = this.queues,
  4769. queue = queues[queueName];
  4770. if (!queue) { throw new Error("You attempted to schedule an action in a queue (" + queueName + ") that doesn't exist"); }
  4771. if (onceFlag) {
  4772. return queue.pushUnique(target, method, args, stack);
  4773. } else {
  4774. return queue.push(target, method, args, stack);
  4775. }
  4776. },
  4777. flush: function() {
  4778. var queues = this.queues,
  4779. queueNames = this.queueNames,
  4780. queueName, queue, queueItems, priorQueueNameIndex,
  4781. queueNameIndex = 0, numberOfQueues = queueNames.length;
  4782. outerloop:
  4783. while (queueNameIndex < numberOfQueues) {
  4784. queueName = queueNames[queueNameIndex];
  4785. queue = queues[queueName];
  4786. queueItems = queue._queueBeingFlushed = queue._queue.slice();
  4787. queue._queue = [];
  4788. var options = queue.options,
  4789. before = options && options.before,
  4790. after = options && options.after,
  4791. target, method, args, stack,
  4792. queueIndex = 0, numberOfQueueItems = queueItems.length;
  4793. if (numberOfQueueItems && before) { before(); }
  4794. while (queueIndex < numberOfQueueItems) {
  4795. target = queueItems[queueIndex];
  4796. method = queueItems[queueIndex+1];
  4797. args = queueItems[queueIndex+2];
  4798. stack = queueItems[queueIndex+3]; // Debugging assistance
  4799. if (typeof method === 'string') { method = target[method]; }
  4800. // method could have been nullified / canceled during flush
  4801. if (method) {
  4802. // TODO: error handling
  4803. if (args && args.length > 0) {
  4804. method.apply(target, args);
  4805. } else {
  4806. method.call(target);
  4807. }
  4808. }
  4809. queueIndex += 4;
  4810. }
  4811. queue._queueBeingFlushed = null;
  4812. if (numberOfQueueItems && after) { after(); }
  4813. if ((priorQueueNameIndex = indexOfPriorQueueWithActions(this, queueNameIndex)) !== -1) {
  4814. queueNameIndex = priorQueueNameIndex;
  4815. continue outerloop;
  4816. }
  4817. queueNameIndex++;
  4818. }
  4819. }
  4820. };
  4821. function indexOfPriorQueueWithActions(daq, currentQueueIndex) {
  4822. var queueName, queue;
  4823. for (var i = 0, l = currentQueueIndex; i <= l; i++) {
  4824. queueName = daq.queueNames[i];
  4825. queue = daq.queues[queueName];
  4826. if (queue._queue.length) { return i; }
  4827. }
  4828. return -1;
  4829. }
  4830. __exports__.DeferredActionQueues = DeferredActionQueues;
  4831. });
  4832. define("backburner",
  4833. ["backburner/deferred_action_queues","exports"],
  4834. function(__dependency1__, __exports__) {
  4835. "use strict";
  4836. var DeferredActionQueues = __dependency1__.DeferredActionQueues;
  4837. var slice = [].slice,
  4838. pop = [].pop,
  4839. throttlers = [],
  4840. debouncees = [],
  4841. timers = [],
  4842. autorun, laterTimer, laterTimerExpiresAt,
  4843. global = this,
  4844. NUMBER = /\d+/;
  4845. function isCoercableNumber(number) {
  4846. return typeof number === 'number' || NUMBER.test(number);
  4847. }
  4848. function Backburner(queueNames, options) {
  4849. this.queueNames = queueNames;
  4850. this.options = options || {};
  4851. if (!this.options.defaultQueue) {
  4852. this.options.defaultQueue = queueNames[0];
  4853. }
  4854. this.instanceStack = [];
  4855. }
  4856. Backburner.prototype = {
  4857. queueNames: null,
  4858. options: null,
  4859. currentInstance: null,
  4860. instanceStack: null,
  4861. begin: function() {
  4862. var onBegin = this.options && this.options.onBegin,
  4863. previousInstance = this.currentInstance;
  4864. if (previousInstance) {
  4865. this.instanceStack.push(previousInstance);
  4866. }
  4867. this.currentInstance = new DeferredActionQueues(this.queueNames, this.options);
  4868. if (onBegin) {
  4869. onBegin(this.currentInstance, previousInstance);
  4870. }
  4871. },
  4872. end: function() {
  4873. var onEnd = this.options && this.options.onEnd,
  4874. currentInstance = this.currentInstance,
  4875. nextInstance = null;
  4876. try {
  4877. currentInstance.flush();
  4878. } finally {
  4879. this.currentInstance = null;
  4880. if (this.instanceStack.length) {
  4881. nextInstance = this.instanceStack.pop();
  4882. this.currentInstance = nextInstance;
  4883. }
  4884. if (onEnd) {
  4885. onEnd(currentInstance, nextInstance);
  4886. }
  4887. }
  4888. },
  4889. run: function(target, method /*, args */) {
  4890. var ret;
  4891. this.begin();
  4892. if (!method) {
  4893. method = target;
  4894. target = null;
  4895. }
  4896. if (typeof method === 'string') {
  4897. method = target[method];
  4898. }
  4899. // Prevent Safari double-finally.
  4900. var finallyAlreadyCalled = false;
  4901. try {
  4902. if (arguments.length > 2) {
  4903. ret = method.apply(target, slice.call(arguments, 2));
  4904. } else {
  4905. ret = method.call(target);
  4906. }
  4907. } finally {
  4908. if (!finallyAlreadyCalled) {
  4909. finallyAlreadyCalled = true;
  4910. this.end();
  4911. }
  4912. }
  4913. return ret;
  4914. },
  4915. defer: function(queueName, target, method /* , args */) {
  4916. if (!method) {
  4917. method = target;
  4918. target = null;
  4919. }
  4920. if (typeof method === 'string') {
  4921. method = target[method];
  4922. }
  4923. var stack = this.DEBUG ? new Error() : undefined,
  4924. args = arguments.length > 3 ? slice.call(arguments, 3) : undefined;
  4925. if (!this.currentInstance) { createAutorun(this); }
  4926. return this.currentInstance.schedule(queueName, target, method, args, false, stack);
  4927. },
  4928. deferOnce: function(queueName, target, method /* , args */) {
  4929. if (!method) {
  4930. method = target;
  4931. target = null;
  4932. }
  4933. if (typeof method === 'string') {
  4934. method = target[method];
  4935. }
  4936. var stack = this.DEBUG ? new Error() : undefined,
  4937. args = arguments.length > 3 ? slice.call(arguments, 3) : undefined;
  4938. if (!this.currentInstance) { createAutorun(this); }
  4939. return this.currentInstance.schedule(queueName, target, method, args, true, stack);
  4940. },
  4941. setTimeout: function() {
  4942. var args = slice.call(arguments);
  4943. var length = args.length;
  4944. var method, wait, target;
  4945. var self = this;
  4946. var methodOrTarget, methodOrWait, methodOrArgs;
  4947. if (length === 0) {
  4948. return;
  4949. } else if (length === 1) {
  4950. method = args.shift();
  4951. wait = 0;
  4952. } else if (length === 2) {
  4953. methodOrTarget = args[0];
  4954. methodOrWait = args[1];
  4955. if (typeof methodOrWait === 'function' || typeof methodOrTarget[methodOrWait] === 'function') {
  4956. target = args.shift();
  4957. method = args.shift();
  4958. wait = 0;
  4959. } else if (isCoercableNumber(methodOrWait)) {
  4960. method = args.shift();
  4961. wait = args.shift();
  4962. } else {
  4963. method = args.shift();
  4964. wait = 0;
  4965. }
  4966. } else {
  4967. var last = args[args.length - 1];
  4968. if (isCoercableNumber(last)) {
  4969. wait = args.pop();
  4970. }
  4971. methodOrTarget = args[0];
  4972. methodOrArgs = args[1];
  4973. if (typeof methodOrArgs === 'function' || (typeof methodOrArgs === 'string' &&
  4974. methodOrTarget !== null &&
  4975. methodOrArgs in methodOrTarget)) {
  4976. target = args.shift();
  4977. method = args.shift();
  4978. } else {
  4979. method = args.shift();
  4980. }
  4981. }
  4982. var executeAt = (+new Date()) + parseInt(wait, 10);
  4983. if (typeof method === 'string') {
  4984. method = target[method];
  4985. }
  4986. function fn() {
  4987. method.apply(target, args);
  4988. }
  4989. // find position to insert - TODO: binary search
  4990. var i, l;
  4991. for (i = 0, l = timers.length; i < l; i += 2) {
  4992. if (executeAt < timers[i]) { break; }
  4993. }
  4994. timers.splice(i, 0, executeAt, fn);
  4995. updateLaterTimer(self, executeAt, wait);
  4996. return fn;
  4997. },
  4998. throttle: function(target, method /* , args, wait */) {
  4999. var self = this,
  5000. args = arguments,
  5001. wait = parseInt(pop.call(args), 10),
  5002. throttler,
  5003. index,
  5004. timer;
  5005. index = findThrottler(target, method);
  5006. if (index > -1) { return throttlers[index]; } // throttled
  5007. timer = global.setTimeout(function() {
  5008. self.run.apply(self, args);
  5009. var index = findThrottler(target, method);
  5010. if (index > -1) { throttlers.splice(index, 1); }
  5011. }, wait);
  5012. throttler = [target, method, timer];
  5013. throttlers.push(throttler);
  5014. return throttler;
  5015. },
  5016. debounce: function(target, method /* , args, wait, [immediate] */) {
  5017. var self = this,
  5018. args = arguments,
  5019. immediate = pop.call(args),
  5020. wait,
  5021. index,
  5022. debouncee,
  5023. timer;
  5024. if (typeof immediate === "number" || typeof immediate === "string") {
  5025. wait = immediate;
  5026. immediate = false;
  5027. } else {
  5028. wait = pop.call(args);
  5029. }
  5030. wait = parseInt(wait, 10);
  5031. // Remove debouncee
  5032. index = findDebouncee(target, method);
  5033. if (index > -1) {
  5034. debouncee = debouncees[index];
  5035. debouncees.splice(index, 1);
  5036. clearTimeout(debouncee[2]);
  5037. }
  5038. timer = global.setTimeout(function() {
  5039. if (!immediate) {
  5040. self.run.apply(self, args);
  5041. }
  5042. var index = findDebouncee(target, method);
  5043. if (index > -1) {
  5044. debouncees.splice(index, 1);
  5045. }
  5046. }, wait);
  5047. if (immediate && index === -1) {
  5048. self.run.apply(self, args);
  5049. }
  5050. debouncee = [target, method, timer];
  5051. debouncees.push(debouncee);
  5052. return debouncee;
  5053. },
  5054. cancelTimers: function() {
  5055. var i, len;
  5056. for (i = 0, len = throttlers.length; i < len; i++) {
  5057. clearTimeout(throttlers[i][2]);
  5058. }
  5059. throttlers = [];
  5060. for (i = 0, len = debouncees.length; i < len; i++) {
  5061. clearTimeout(debouncees[i][2]);
  5062. }
  5063. debouncees = [];
  5064. if (laterTimer) {
  5065. clearTimeout(laterTimer);
  5066. laterTimer = null;
  5067. }
  5068. timers = [];
  5069. if (autorun) {
  5070. clearTimeout(autorun);
  5071. autorun = null;
  5072. }
  5073. },
  5074. hasTimers: function() {
  5075. return !!timers.length || autorun;
  5076. },
  5077. cancel: function(timer) {
  5078. var timerType = typeof timer;
  5079. if (timer && timerType === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce
  5080. return timer.queue.cancel(timer);
  5081. } else if (timerType === 'function') { // we're cancelling a setTimeout
  5082. for (var i = 0, l = timers.length; i < l; i += 2) {
  5083. if (timers[i + 1] === timer) {
  5084. timers.splice(i, 2); // remove the two elements
  5085. return true;
  5086. }
  5087. }
  5088. } else if (Object.prototype.toString.call(timer) === "[object Array]"){ // we're cancelling a throttle or debounce
  5089. return this._cancelItem(findThrottler, throttlers, timer) ||
  5090. this._cancelItem(findDebouncee, debouncees, timer);
  5091. } else {
  5092. return; // timer was null or not a timer
  5093. }
  5094. },
  5095. _cancelItem: function(findMethod, array, timer){
  5096. var item,
  5097. index;
  5098. if (timer.length < 3) { return false; }
  5099. index = findMethod(timer[0], timer[1]);
  5100. if(index > -1) {
  5101. item = array[index];
  5102. if(item[2] === timer[2]){
  5103. array.splice(index, 1);
  5104. clearTimeout(timer[2]);
  5105. return true;
  5106. }
  5107. }
  5108. return false;
  5109. }
  5110. };
  5111. Backburner.prototype.schedule = Backburner.prototype.defer;
  5112. Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce;
  5113. Backburner.prototype.later = Backburner.prototype.setTimeout;
  5114. function createAutorun(backburner) {
  5115. backburner.begin();
  5116. autorun = global.setTimeout(function() {
  5117. autorun = null;
  5118. backburner.end();
  5119. });
  5120. }
  5121. function updateLaterTimer(self, executeAt, wait) {
  5122. if (!laterTimer || executeAt < laterTimerExpiresAt) {
  5123. if (laterTimer) {
  5124. clearTimeout(laterTimer);
  5125. }
  5126. laterTimer = global.setTimeout(function() {
  5127. laterTimer = null;
  5128. laterTimerExpiresAt = null;
  5129. executeTimers(self);
  5130. }, wait);
  5131. laterTimerExpiresAt = executeAt;
  5132. }
  5133. }
  5134. function executeTimers(self) {
  5135. var now = +new Date(),
  5136. time, fns, i, l;
  5137. self.run(function() {
  5138. // TODO: binary search
  5139. for (i = 0, l = timers.length; i < l; i += 2) {
  5140. time = timers[i];
  5141. if (time > now) { break; }
  5142. }
  5143. fns = timers.splice(0, i);
  5144. for (i = 1, l = fns.length; i < l; i += 2) {
  5145. self.schedule(self.options.defaultQueue, null, fns[i]);
  5146. }
  5147. });
  5148. if (timers.length) {
  5149. updateLaterTimer(self, timers[0], timers[0] - now);
  5150. }
  5151. }
  5152. function findDebouncee(target, method) {
  5153. var debouncee,
  5154. index = -1;
  5155. for (var i = 0, l = debouncees.length; i < l; i++) {
  5156. debouncee = debouncees[i];
  5157. if (debouncee[0] === target && debouncee[1] === method) {
  5158. index = i;
  5159. break;
  5160. }
  5161. }
  5162. return index;
  5163. }
  5164. function findThrottler(target, method) {
  5165. var throttler,
  5166. index = -1;
  5167. for (var i = 0, l = throttlers.length; i < l; i++) {
  5168. throttler = throttlers[i];
  5169. if (throttler[0] === target && throttler[1] === method) {
  5170. index = i;
  5171. break;
  5172. }
  5173. }
  5174. return index;
  5175. }
  5176. __exports__.Backburner = Backburner;
  5177. });
  5178. })();
  5179. (function() {
  5180. var onBegin = function(current) {
  5181. Ember.run.currentRunLoop = current;
  5182. };
  5183. var onEnd = function(current, next) {
  5184. Ember.run.currentRunLoop = next;
  5185. };
  5186. var Backburner = requireModule('backburner').Backburner,
  5187. backburner = new Backburner(['sync', 'actions', 'destroy'], {
  5188. sync: {
  5189. before: Ember.beginPropertyChanges,
  5190. after: Ember.endPropertyChanges
  5191. },
  5192. defaultQueue: 'actions',
  5193. onBegin: onBegin,
  5194. onEnd: onEnd
  5195. }),
  5196. slice = [].slice,
  5197. concat = [].concat;
  5198. // ..........................................................
  5199. // Ember.run - this is ideally the only public API the dev sees
  5200. //
  5201. /**
  5202. Runs the passed target and method inside of a RunLoop, ensuring any
  5203. deferred actions including bindings and views updates are flushed at the
  5204. end.
  5205. Normally you should not need to invoke this method yourself. However if
  5206. you are implementing raw event handlers when interfacing with other
  5207. libraries or plugins, you should probably wrap all of your code inside this
  5208. call.
  5209. ```javascript
  5210. Ember.run(function() {
  5211. // code to be execute within a RunLoop
  5212. });
  5213. ```
  5214. @class run
  5215. @namespace Ember
  5216. @static
  5217. @constructor
  5218. @param {Object} [target] target of method to call
  5219. @param {Function|String} method Method to invoke.
  5220. May be a function or a string. If you pass a string
  5221. then it will be looked up on the passed target.
  5222. @param {Object} [args*] Any additional arguments you wish to pass to the method.
  5223. @return {Object} return value from invoking the passed function.
  5224. */
  5225. Ember.run = function(target, method) {
  5226. var ret;
  5227. if (Ember.onerror) {
  5228. try {
  5229. ret = backburner.run.apply(backburner, arguments);
  5230. } catch (e) {
  5231. Ember.onerror(e);
  5232. }
  5233. } else {
  5234. ret = backburner.run.apply(backburner, arguments);
  5235. }
  5236. return ret;
  5237. };
  5238. /**
  5239. If no run-loop is present, it creates a new one. If a run loop is
  5240. present it will queue itself to run on the existing run-loops action
  5241. queue.
  5242. Please note: This is not for normal usage, and should be used sparingly.
  5243. If invoked when not within a run loop:
  5244. ```javascript
  5245. Ember.run.join(function() {
  5246. // creates a new run-loop
  5247. });
  5248. ```
  5249. Alternatively, if called within an existing run loop:
  5250. ```javascript
  5251. Ember.run(function() {
  5252. // creates a new run-loop
  5253. Ember.run.join(function() {
  5254. // joins with the existing run-loop, and queues for invocation on
  5255. // the existing run-loops action queue.
  5256. });
  5257. });
  5258. ```
  5259. @method join
  5260. @namespace Ember
  5261. @param {Object} [target] target of method to call
  5262. @param {Function|String} method Method to invoke.
  5263. May be a function or a string. If you pass a string
  5264. then it will be looked up on the passed target.
  5265. @param {Object} [args*] Any additional arguments you wish to pass to the method.
  5266. @return {Object} Return value from invoking the passed function. Please note,
  5267. when called within an existing loop, no return value is possible.
  5268. */
  5269. Ember.run.join = function(target, method /* args */) {
  5270. if (!Ember.run.currentRunLoop) {
  5271. return Ember.run.apply(Ember.run, arguments);
  5272. }
  5273. var args = slice.call(arguments);
  5274. args.unshift('actions');
  5275. Ember.run.schedule.apply(Ember.run, args);
  5276. };
  5277. /**
  5278. Provides a useful utility for when integrating with non-Ember libraries
  5279. that provide asynchronous callbacks.
  5280. Ember utilizes a run-loop to batch and coalesce changes. This works by
  5281. marking the start and end of Ember-related Javascript execution.
  5282. When using events such as a View's click handler, Ember wraps the event
  5283. handler in a run-loop, but when integrating with non-Ember libraries this
  5284. can be tedious.
  5285. For example, the following is rather verbose but is the correct way to combine
  5286. third-party events and Ember code.
  5287. ```javascript
  5288. var that = this;
  5289. jQuery(window).on('resize', function(){
  5290. Ember.run(function(){
  5291. that.handleResize();
  5292. });
  5293. });
  5294. ```
  5295. To reduce the boilerplate, the following can be used to construct a
  5296. run-loop-wrapped callback handler.
  5297. ```javascript
  5298. jQuery(window).on('resize', Ember.run.bind(this, this.triggerResize));
  5299. ```
  5300. @method bind
  5301. @namespace Ember.run
  5302. @param {Object} [target] target of method to call
  5303. @param {Function|String} method Method to invoke.
  5304. May be a function or a string. If you pass a string
  5305. then it will be looked up on the passed target.
  5306. @param {Object} [args*] Any additional arguments you wish to pass to the method.
  5307. @return {Object} return value from invoking the passed function. Please note,
  5308. when called within an existing loop, no return value is possible.
  5309. */
  5310. Ember.run.bind = function(target, method /* args*/) {
  5311. var args = arguments;
  5312. return function() {
  5313. return Ember.run.join.apply(Ember.run, args);
  5314. };
  5315. };
  5316. Ember.run.backburner = backburner;
  5317. var run = Ember.run;
  5318. Ember.run.currentRunLoop = null;
  5319. Ember.run.queues = backburner.queueNames;
  5320. /**
  5321. Begins a new RunLoop. Any deferred actions invoked after the begin will
  5322. be buffered until you invoke a matching call to `Ember.run.end()`. This is
  5323. a lower-level way to use a RunLoop instead of using `Ember.run()`.
  5324. ```javascript
  5325. Ember.run.begin();
  5326. // code to be execute within a RunLoop
  5327. Ember.run.end();
  5328. ```
  5329. @method begin
  5330. @return {void}
  5331. */
  5332. Ember.run.begin = function() {
  5333. backburner.begin();
  5334. };
  5335. /**
  5336. Ends a RunLoop. This must be called sometime after you call
  5337. `Ember.run.begin()` to flush any deferred actions. This is a lower-level way
  5338. to use a RunLoop instead of using `Ember.run()`.
  5339. ```javascript
  5340. Ember.run.begin();
  5341. // code to be execute within a RunLoop
  5342. Ember.run.end();
  5343. ```
  5344. @method end
  5345. @return {void}
  5346. */
  5347. Ember.run.end = function() {
  5348. backburner.end();
  5349. };
  5350. /**
  5351. Array of named queues. This array determines the order in which queues
  5352. are flushed at the end of the RunLoop. You can define your own queues by
  5353. simply adding the queue name to this array. Normally you should not need
  5354. to inspect or modify this property.
  5355. @property queues
  5356. @type Array
  5357. @default ['sync', 'actions', 'destroy']
  5358. */
  5359. /**
  5360. Adds the passed target/method and any optional arguments to the named
  5361. queue to be executed at the end of the RunLoop. If you have not already
  5362. started a RunLoop when calling this method one will be started for you
  5363. automatically.
  5364. At the end of a RunLoop, any methods scheduled in this way will be invoked.
  5365. Methods will be invoked in an order matching the named queues defined in
  5366. the `Ember.run.queues` property.
  5367. ```javascript
  5368. Ember.run.schedule('sync', this, function() {
  5369. // this will be executed in the first RunLoop queue, when bindings are synced
  5370. console.log("scheduled on sync queue");
  5371. });
  5372. Ember.run.schedule('actions', this, function() {
  5373. // this will be executed in the 'actions' queue, after bindings have synced.
  5374. console.log("scheduled on actions queue");
  5375. });
  5376. // Note the functions will be run in order based on the run queues order.
  5377. // Output would be:
  5378. // scheduled on sync queue
  5379. // scheduled on actions queue
  5380. ```
  5381. @method schedule
  5382. @param {String} queue The name of the queue to schedule against.
  5383. Default queues are 'sync' and 'actions'
  5384. @param {Object} [target] target object to use as the context when invoking a method.
  5385. @param {String|Function} method The method to invoke. If you pass a string it
  5386. will be resolved on the target object at the time the scheduled item is
  5387. invoked allowing you to change the target function.
  5388. @param {Object} [arguments*] Optional arguments to be passed to the queued method.
  5389. @return {void}
  5390. */
  5391. Ember.run.schedule = function(queue, target, method) {
  5392. checkAutoRun();
  5393. backburner.schedule.apply(backburner, arguments);
  5394. };
  5395. // Used by global test teardown
  5396. Ember.run.hasScheduledTimers = function() {
  5397. return backburner.hasTimers();
  5398. };
  5399. // Used by global test teardown
  5400. Ember.run.cancelTimers = function () {
  5401. backburner.cancelTimers();
  5402. };
  5403. /**
  5404. Immediately flushes any events scheduled in the 'sync' queue. Bindings
  5405. use this queue so this method is a useful way to immediately force all
  5406. bindings in the application to sync.
  5407. You should call this method anytime you need any changed state to propagate
  5408. throughout the app immediately without repainting the UI (which happens
  5409. in the later 'render' queue added by the `ember-views` package).
  5410. ```javascript
  5411. Ember.run.sync();
  5412. ```
  5413. @method sync
  5414. @return {void}
  5415. */
  5416. Ember.run.sync = function() {
  5417. if (backburner.currentInstance) {
  5418. backburner.currentInstance.queues.sync.flush();
  5419. }
  5420. };
  5421. /**
  5422. Invokes the passed target/method and optional arguments after a specified
  5423. period if time. The last parameter of this method must always be a number
  5424. of milliseconds.
  5425. You should use this method whenever you need to run some action after a
  5426. period of time instead of using `setTimeout()`. This method will ensure that
  5427. items that expire during the same script execution cycle all execute
  5428. together, which is often more efficient than using a real setTimeout.
  5429. ```javascript
  5430. Ember.run.later(myContext, function() {
  5431. // code here will execute within a RunLoop in about 500ms with this == myContext
  5432. }, 500);
  5433. ```
  5434. @method later
  5435. @param {Object} [target] target of method to invoke
  5436. @param {Function|String} method The method to invoke.
  5437. If you pass a string it will be resolved on the
  5438. target at the time the method is invoked.
  5439. @param {Object} [args*] Optional arguments to pass to the timeout.
  5440. @param {Number} wait Number of milliseconds to wait.
  5441. @return {String} a string you can use to cancel the timer in
  5442. `Ember.run.cancel` later.
  5443. */
  5444. Ember.run.later = function(target, method) {
  5445. return backburner.later.apply(backburner, arguments);
  5446. };
  5447. /**
  5448. Schedule a function to run one time during the current RunLoop. This is equivalent
  5449. to calling `scheduleOnce` with the "actions" queue.
  5450. @method once
  5451. @param {Object} [target] The target of the method to invoke.
  5452. @param {Function|String} method The method to invoke.
  5453. If you pass a string it will be resolved on the
  5454. target at the time the method is invoked.
  5455. @param {Object} [args*] Optional arguments to pass to the timeout.
  5456. @return {Object} Timer information for use in cancelling, see `Ember.run.cancel`.
  5457. */
  5458. Ember.run.once = function(target, method) {
  5459. checkAutoRun();
  5460. var args = slice.call(arguments);
  5461. args.unshift('actions');
  5462. return backburner.scheduleOnce.apply(backburner, args);
  5463. };
  5464. /**
  5465. Schedules a function to run one time in a given queue of the current RunLoop.
  5466. Calling this method with the same queue/target/method combination will have
  5467. no effect (past the initial call).
  5468. Note that although you can pass optional arguments these will not be
  5469. considered when looking for duplicates. New arguments will replace previous
  5470. calls.
  5471. ```javascript
  5472. Ember.run(function() {
  5473. var sayHi = function() { console.log('hi'); }
  5474. Ember.run.scheduleOnce('afterRender', myContext, sayHi);
  5475. Ember.run.scheduleOnce('afterRender', myContext, sayHi);
  5476. // sayHi will only be executed once, in the afterRender queue of the RunLoop
  5477. });
  5478. ```
  5479. Also note that passing an anonymous function to `Ember.run.scheduleOnce` will
  5480. not prevent additional calls with an identical anonymous function from
  5481. scheduling the items multiple times, e.g.:
  5482. ```javascript
  5483. function scheduleIt() {
  5484. Ember.run.scheduleOnce('actions', myContext, function() { console.log("Closure"); });
  5485. }
  5486. scheduleIt();
  5487. scheduleIt();
  5488. // "Closure" will print twice, even though we're using `Ember.run.scheduleOnce`,
  5489. // because the function we pass to it is anonymous and won't match the
  5490. // previously scheduled operation.
  5491. ```
  5492. Available queues, and their order, can be found at `Ember.run.queues`
  5493. @method scheduleOnce
  5494. @param {String} [queue] The name of the queue to schedule against. Default queues are 'sync' and 'actions'.
  5495. @param {Object} [target] The target of the method to invoke.
  5496. @param {Function|String} method The method to invoke.
  5497. If you pass a string it will be resolved on the
  5498. target at the time the method is invoked.
  5499. @param {Object} [args*] Optional arguments to pass to the timeout.
  5500. @return {Object} Timer information for use in cancelling, see `Ember.run.cancel`.
  5501. */
  5502. Ember.run.scheduleOnce = function(queue, target, method) {
  5503. checkAutoRun();
  5504. return backburner.scheduleOnce.apply(backburner, arguments);
  5505. };
  5506. /**
  5507. Schedules an item to run from within a separate run loop, after
  5508. control has been returned to the system. This is equivalent to calling
  5509. `Ember.run.later` with a wait time of 1ms.
  5510. ```javascript
  5511. Ember.run.next(myContext, function() {
  5512. // code to be executed in the next run loop,
  5513. // which will be scheduled after the current one
  5514. });
  5515. ```
  5516. Multiple operations scheduled with `Ember.run.next` will coalesce
  5517. into the same later run loop, along with any other operations
  5518. scheduled by `Ember.run.later` that expire right around the same
  5519. time that `Ember.run.next` operations will fire.
  5520. Note that there are often alternatives to using `Ember.run.next`.
  5521. For instance, if you'd like to schedule an operation to happen
  5522. after all DOM element operations have completed within the current
  5523. run loop, you can make use of the `afterRender` run loop queue (added
  5524. by the `ember-views` package, along with the preceding `render` queue
  5525. where all the DOM element operations happen). Example:
  5526. ```javascript
  5527. App.MyCollectionView = Ember.CollectionView.extend({
  5528. didInsertElement: function() {
  5529. Ember.run.scheduleOnce('afterRender', this, 'processChildElements');
  5530. },
  5531. processChildElements: function() {
  5532. // ... do something with collectionView's child view
  5533. // elements after they've finished rendering, which
  5534. // can't be done within the CollectionView's
  5535. // `didInsertElement` hook because that gets run
  5536. // before the child elements have been added to the DOM.
  5537. }
  5538. });
  5539. ```
  5540. One benefit of the above approach compared to using `Ember.run.next` is
  5541. that you will be able to perform DOM/CSS operations before unprocessed
  5542. elements are rendered to the screen, which may prevent flickering or
  5543. other artifacts caused by delaying processing until after rendering.
  5544. The other major benefit to the above approach is that `Ember.run.next`
  5545. introduces an element of non-determinism, which can make things much
  5546. harder to test, due to its reliance on `setTimeout`; it's much harder
  5547. to guarantee the order of scheduled operations when they are scheduled
  5548. outside of the current run loop, i.e. with `Ember.run.next`.
  5549. @method next
  5550. @param {Object} [target] target of method to invoke
  5551. @param {Function|String} method The method to invoke.
  5552. If you pass a string it will be resolved on the
  5553. target at the time the method is invoked.
  5554. @param {Object} [args*] Optional arguments to pass to the timeout.
  5555. @return {Object} Timer information for use in cancelling, see `Ember.run.cancel`.
  5556. */
  5557. Ember.run.next = function() {
  5558. var args = slice.call(arguments);
  5559. args.push(1);
  5560. return backburner.later.apply(backburner, args);
  5561. };
  5562. /**
  5563. Cancels a scheduled item. Must be a value returned by `Ember.run.later()`,
  5564. `Ember.run.once()`, `Ember.run.next()`, `Ember.run.debounce()`, or
  5565. `Ember.run.throttle()`.
  5566. ```javascript
  5567. var runNext = Ember.run.next(myContext, function() {
  5568. // will not be executed
  5569. });
  5570. Ember.run.cancel(runNext);
  5571. var runLater = Ember.run.later(myContext, function() {
  5572. // will not be executed
  5573. }, 500);
  5574. Ember.run.cancel(runLater);
  5575. var runOnce = Ember.run.once(myContext, function() {
  5576. // will not be executed
  5577. });
  5578. Ember.run.cancel(runOnce);
  5579. var throttle = Ember.run.throttle(myContext, function() {
  5580. // will not be executed
  5581. }, 1);
  5582. Ember.run.cancel(throttle);
  5583. var debounce = Ember.run.debounce(myContext, function() {
  5584. // will not be executed
  5585. }, 1);
  5586. Ember.run.cancel(debounce);
  5587. var debounceImmediate = Ember.run.debounce(myContext, function() {
  5588. // will be executed since we passed in true (immediate)
  5589. }, 100, true);
  5590. // the 100ms delay until this method can be called again will be cancelled
  5591. Ember.run.cancel(debounceImmediate);
  5592. ```
  5593. ```
  5594. ```
  5595. @method cancel
  5596. @param {Object} timer Timer object to cancel
  5597. @return {Boolean} true if cancelled or false/undefined if it wasn't found
  5598. */
  5599. Ember.run.cancel = function(timer) {
  5600. return backburner.cancel(timer);
  5601. };
  5602. /**
  5603. Delay calling the target method until the debounce period has elapsed
  5604. with no additional debounce calls. If `debounce` is called again before
  5605. the specified time has elapsed, the timer is reset and the entire period
  5606. must pass again before the target method is called.
  5607. This method should be used when an event may be called multiple times
  5608. but the action should only be called once when the event is done firing.
  5609. A common example is for scroll events where you only want updates to
  5610. happen once scrolling has ceased.
  5611. ```javascript
  5612. var myFunc = function() { console.log(this.name + ' ran.'); };
  5613. var myContext = {name: 'debounce'};
  5614. Ember.run.debounce(myContext, myFunc, 150);
  5615. // less than 150ms passes
  5616. Ember.run.debounce(myContext, myFunc, 150);
  5617. // 150ms passes
  5618. // myFunc is invoked with context myContext
  5619. // console logs 'debounce ran.' one time.
  5620. ```
  5621. Immediate allows you to run the function immediately, but debounce
  5622. other calls for this function until the wait time has elapsed. If
  5623. `debounce` is called again before the specified time has elapsed,
  5624. the timer is reset and the entire period msut pass again before
  5625. the method can be called again.
  5626. ```javascript
  5627. var myFunc = function() { console.log(this.name + ' ran.'); };
  5628. var myContext = {name: 'debounce'};
  5629. Ember.run.debounce(myContext, myFunc, 150, true);
  5630. // console logs 'debounce ran.' one time immediately.
  5631. // 100ms passes
  5632. Ember.run.debounce(myContext, myFunc, 150, true);
  5633. // 150ms passes and nothing else is logged to the console and
  5634. // the debouncee is no longer being watched
  5635. Ember.run.debounce(myContext, myFunc, 150, true);
  5636. // console logs 'debounce ran.' one time immediately.
  5637. // 150ms passes and nothing else is logged tot he console and
  5638. // the debouncee is no longer being watched
  5639. ```
  5640. @method debounce
  5641. @param {Object} [target] target of method to invoke
  5642. @param {Function|String} method The method to invoke.
  5643. May be a function or a string. If you pass a string
  5644. then it will be looked up on the passed target.
  5645. @param {Object} [args*] Optional arguments to pass to the timeout.
  5646. @param {Number} wait Number of milliseconds to wait.
  5647. @param {Boolean} immediate Trigger the function on the leading instead of the trailing edge of the wait interval.
  5648. @return {Array} Timer information for use in cancelling, see `Ember.run.cancel`.
  5649. */
  5650. Ember.run.debounce = function() {
  5651. return backburner.debounce.apply(backburner, arguments);
  5652. };
  5653. /**
  5654. Ensure that the target method is never called more frequently than
  5655. the specified spacing period.
  5656. ```javascript
  5657. var myFunc = function() { console.log(this.name + ' ran.'); };
  5658. var myContext = {name: 'throttle'};
  5659. Ember.run.throttle(myContext, myFunc, 150);
  5660. // 50ms passes
  5661. Ember.run.throttle(myContext, myFunc, 150);
  5662. // 50ms passes
  5663. Ember.run.throttle(myContext, myFunc, 150);
  5664. // 50ms passes
  5665. Ember.run.throttle(myContext, myFunc, 150);
  5666. // 150ms passes
  5667. // myFunc is invoked with context myContext
  5668. // console logs 'throttle ran.' twice, 150ms apart.
  5669. ```
  5670. @method throttle
  5671. @param {Object} [target] target of method to invoke
  5672. @param {Function|String} method The method to invoke.
  5673. May be a function or a string. If you pass a string
  5674. then it will be looked up on the passed target.
  5675. @param {Object} [args*] Optional arguments to pass to the timeout.
  5676. @param {Number} spacing Number of milliseconds to space out requests.
  5677. @return {Array} Timer information for use in cancelling, see `Ember.run.cancel`.
  5678. */
  5679. Ember.run.throttle = function() {
  5680. return backburner.throttle.apply(backburner, arguments);
  5681. };
  5682. // Make sure it's not an autorun during testing
  5683. function checkAutoRun() {
  5684. if (!Ember.run.currentRunLoop) {
  5685. 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);
  5686. }
  5687. }
  5688. })();
  5689. (function() {
  5690. // Ember.Logger
  5691. // get
  5692. // set
  5693. // guidFor, meta
  5694. // addObserver, removeObserver
  5695. // Ember.run.schedule
  5696. /**
  5697. @module ember-metal
  5698. */
  5699. // ..........................................................
  5700. // CONSTANTS
  5701. //
  5702. /**
  5703. Debug parameter you can turn on. This will log all bindings that fire to
  5704. the console. This should be disabled in production code. Note that you
  5705. can also enable this from the console or temporarily.
  5706. @property LOG_BINDINGS
  5707. @for Ember
  5708. @type Boolean
  5709. @default false
  5710. */
  5711. Ember.LOG_BINDINGS = false || !!Ember.ENV.LOG_BINDINGS;
  5712. var get = Ember.get,
  5713. set = Ember.set,
  5714. guidFor = Ember.guidFor,
  5715. IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/;
  5716. /**
  5717. Returns true if the provided path is global (e.g., `MyApp.fooController.bar`)
  5718. instead of local (`foo.bar.baz`).
  5719. @method isGlobalPath
  5720. @for Ember
  5721. @private
  5722. @param {String} path
  5723. @return Boolean
  5724. */
  5725. var isGlobalPath = Ember.isGlobalPath = function(path) {
  5726. return IS_GLOBAL.test(path);
  5727. };
  5728. function getWithGlobals(obj, path) {
  5729. return get(isGlobalPath(path) ? Ember.lookup : obj, path);
  5730. }
  5731. // ..........................................................
  5732. // BINDING
  5733. //
  5734. var Binding = function(toPath, fromPath) {
  5735. this._direction = 'fwd';
  5736. this._from = fromPath;
  5737. this._to = toPath;
  5738. this._directionMap = Ember.Map.create();
  5739. };
  5740. /**
  5741. @class Binding
  5742. @namespace Ember
  5743. */
  5744. Binding.prototype = {
  5745. /**
  5746. This copies the Binding so it can be connected to another object.
  5747. @method copy
  5748. @return {Ember.Binding} `this`
  5749. */
  5750. copy: function () {
  5751. var copy = new Binding(this._to, this._from);
  5752. if (this._oneWay) { copy._oneWay = true; }
  5753. return copy;
  5754. },
  5755. // ..........................................................
  5756. // CONFIG
  5757. //
  5758. /**
  5759. This will set `from` property path to the specified value. It will not
  5760. attempt to resolve this property path to an actual object until you
  5761. connect the binding.
  5762. The binding will search for the property path starting at the root object
  5763. you pass when you `connect()` the binding. It follows the same rules as
  5764. `get()` - see that method for more information.
  5765. @method from
  5766. @param {String} path the property path to connect to
  5767. @return {Ember.Binding} `this`
  5768. */
  5769. from: function(path) {
  5770. this._from = path;
  5771. return this;
  5772. },
  5773. /**
  5774. This will set the `to` property path to the specified value. It will not
  5775. attempt to resolve this property path to an actual object until you
  5776. connect the binding.
  5777. The binding will search for the property path starting at the root object
  5778. you pass when you `connect()` the binding. It follows the same rules as
  5779. `get()` - see that method for more information.
  5780. @method to
  5781. @param {String|Tuple} path A property path or tuple
  5782. @return {Ember.Binding} `this`
  5783. */
  5784. to: function(path) {
  5785. this._to = path;
  5786. return this;
  5787. },
  5788. /**
  5789. Configures the binding as one way. A one-way binding will relay changes
  5790. on the `from` side to the `to` side, but not the other way around. This
  5791. means that if you change the `to` side directly, the `from` side may have
  5792. a different value.
  5793. @method oneWay
  5794. @return {Ember.Binding} `this`
  5795. */
  5796. oneWay: function() {
  5797. this._oneWay = true;
  5798. return this;
  5799. },
  5800. /**
  5801. @method toString
  5802. @return {String} string representation of binding
  5803. */
  5804. toString: function() {
  5805. var oneWay = this._oneWay ? '[oneWay]' : '';
  5806. return "Ember.Binding<" + guidFor(this) + ">(" + this._from + " -> " + this._to + ")" + oneWay;
  5807. },
  5808. // ..........................................................
  5809. // CONNECT AND SYNC
  5810. //
  5811. /**
  5812. Attempts to connect this binding instance so that it can receive and relay
  5813. changes. This method will raise an exception if you have not set the
  5814. from/to properties yet.
  5815. @method connect
  5816. @param {Object} obj The root object for this binding.
  5817. @return {Ember.Binding} `this`
  5818. */
  5819. connect: function(obj) {
  5820. Ember.assert('Must pass a valid object to Ember.Binding.connect()', !!obj);
  5821. var fromPath = this._from, toPath = this._to;
  5822. Ember.trySet(obj, toPath, getWithGlobals(obj, fromPath));
  5823. // add an observer on the object to be notified when the binding should be updated
  5824. Ember.addObserver(obj, fromPath, this, this.fromDidChange);
  5825. // if the binding is a two-way binding, also set up an observer on the target
  5826. if (!this._oneWay) { Ember.addObserver(obj, toPath, this, this.toDidChange); }
  5827. this._readyToSync = true;
  5828. return this;
  5829. },
  5830. /**
  5831. Disconnects the binding instance. Changes will no longer be relayed. You
  5832. will not usually need to call this method.
  5833. @method disconnect
  5834. @param {Object} obj The root object you passed when connecting the binding.
  5835. @return {Ember.Binding} `this`
  5836. */
  5837. disconnect: function(obj) {
  5838. Ember.assert('Must pass a valid object to Ember.Binding.disconnect()', !!obj);
  5839. var twoWay = !this._oneWay;
  5840. // remove an observer on the object so we're no longer notified of
  5841. // changes that should update bindings.
  5842. Ember.removeObserver(obj, this._from, this, this.fromDidChange);
  5843. // if the binding is two-way, remove the observer from the target as well
  5844. if (twoWay) { Ember.removeObserver(obj, this._to, this, this.toDidChange); }
  5845. this._readyToSync = false; // disable scheduled syncs...
  5846. return this;
  5847. },
  5848. // ..........................................................
  5849. // PRIVATE
  5850. //
  5851. /* called when the from side changes */
  5852. fromDidChange: function(target) {
  5853. this._scheduleSync(target, 'fwd');
  5854. },
  5855. /* called when the to side changes */
  5856. toDidChange: function(target) {
  5857. this._scheduleSync(target, 'back');
  5858. },
  5859. _scheduleSync: function(obj, dir) {
  5860. var directionMap = this._directionMap;
  5861. var existingDir = directionMap.get(obj);
  5862. // if we haven't scheduled the binding yet, schedule it
  5863. if (!existingDir) {
  5864. Ember.run.schedule('sync', this, this._sync, obj);
  5865. directionMap.set(obj, dir);
  5866. }
  5867. // If both a 'back' and 'fwd' sync have been scheduled on the same object,
  5868. // default to a 'fwd' sync so that it remains deterministic.
  5869. if (existingDir === 'back' && dir === 'fwd') {
  5870. directionMap.set(obj, 'fwd');
  5871. }
  5872. },
  5873. _sync: function(obj) {
  5874. var log = Ember.LOG_BINDINGS;
  5875. // don't synchronize destroyed objects or disconnected bindings
  5876. if (obj.isDestroyed || !this._readyToSync) { return; }
  5877. // get the direction of the binding for the object we are
  5878. // synchronizing from
  5879. var directionMap = this._directionMap;
  5880. var direction = directionMap.get(obj);
  5881. var fromPath = this._from, toPath = this._to;
  5882. directionMap.remove(obj);
  5883. // if we're synchronizing from the remote object...
  5884. if (direction === 'fwd') {
  5885. var fromValue = getWithGlobals(obj, this._from);
  5886. if (log) {
  5887. Ember.Logger.log(' ', this.toString(), '->', fromValue, obj);
  5888. }
  5889. if (this._oneWay) {
  5890. Ember.trySet(obj, toPath, fromValue);
  5891. } else {
  5892. Ember._suspendObserver(obj, toPath, this, this.toDidChange, function () {
  5893. Ember.trySet(obj, toPath, fromValue);
  5894. });
  5895. }
  5896. // if we're synchronizing *to* the remote object
  5897. } else if (direction === 'back') {
  5898. var toValue = get(obj, this._to);
  5899. if (log) {
  5900. Ember.Logger.log(' ', this.toString(), '<-', toValue, obj);
  5901. }
  5902. Ember._suspendObserver(obj, fromPath, this, this.fromDidChange, function () {
  5903. Ember.trySet(Ember.isGlobalPath(fromPath) ? Ember.lookup : obj, fromPath, toValue);
  5904. });
  5905. }
  5906. }
  5907. };
  5908. function mixinProperties(to, from) {
  5909. for (var key in from) {
  5910. if (from.hasOwnProperty(key)) {
  5911. to[key] = from[key];
  5912. }
  5913. }
  5914. }
  5915. mixinProperties(Binding, {
  5916. /*
  5917. See `Ember.Binding.from`.
  5918. @method from
  5919. @static
  5920. */
  5921. from: function() {
  5922. var C = this, binding = new C();
  5923. return binding.from.apply(binding, arguments);
  5924. },
  5925. /*
  5926. See `Ember.Binding.to`.
  5927. @method to
  5928. @static
  5929. */
  5930. to: function() {
  5931. var C = this, binding = new C();
  5932. return binding.to.apply(binding, arguments);
  5933. },
  5934. /**
  5935. Creates a new Binding instance and makes it apply in a single direction.
  5936. A one-way binding will relay changes on the `from` side object (supplied
  5937. as the `from` argument) the `to` side, but not the other way around.
  5938. This means that if you change the "to" side directly, the "from" side may have
  5939. a different value.
  5940. See `Binding.oneWay`.
  5941. @method oneWay
  5942. @param {String} from from path.
  5943. @param {Boolean} [flag] (Optional) passing nothing here will make the
  5944. binding `oneWay`. You can instead pass `false` to disable `oneWay`, making the
  5945. binding two way again.
  5946. @return {Ember.Binding} `this`
  5947. */
  5948. oneWay: function(from, flag) {
  5949. var C = this, binding = new C(null, from);
  5950. return binding.oneWay(flag);
  5951. }
  5952. });
  5953. /**
  5954. An `Ember.Binding` connects the properties of two objects so that whenever
  5955. the value of one property changes, the other property will be changed also.
  5956. ## Automatic Creation of Bindings with `/^*Binding/`-named Properties
  5957. You do not usually create Binding objects directly but instead describe
  5958. bindings in your class or object definition using automatic binding
  5959. detection.
  5960. Properties ending in a `Binding` suffix will be converted to `Ember.Binding`
  5961. instances. The value of this property should be a string representing a path
  5962. to another object or a custom binding instanced created using Binding helpers
  5963. (see "One Way Bindings"):
  5964. ```
  5965. valueBinding: "MyApp.someController.title"
  5966. ```
  5967. This will create a binding from `MyApp.someController.title` to the `value`
  5968. property of your object instance automatically. Now the two values will be
  5969. kept in sync.
  5970. ## One Way Bindings
  5971. One especially useful binding customization you can use is the `oneWay()`
  5972. helper. This helper tells Ember that you are only interested in
  5973. receiving changes on the object you are binding from. For example, if you
  5974. are binding to a preference and you want to be notified if the preference
  5975. has changed, but your object will not be changing the preference itself, you
  5976. could do:
  5977. ```
  5978. bigTitlesBinding: Ember.Binding.oneWay("MyApp.preferencesController.bigTitles")
  5979. ```
  5980. This way if the value of `MyApp.preferencesController.bigTitles` changes the
  5981. `bigTitles` property of your object will change also. However, if you
  5982. change the value of your `bigTitles` property, it will not update the
  5983. `preferencesController`.
  5984. One way bindings are almost twice as fast to setup and twice as fast to
  5985. execute because the binding only has to worry about changes to one side.
  5986. You should consider using one way bindings anytime you have an object that
  5987. may be created frequently and you do not intend to change a property; only
  5988. to monitor it for changes (such as in the example above).
  5989. ## Adding Bindings Manually
  5990. All of the examples above show you how to configure a custom binding, but the
  5991. result of these customizations will be a binding template, not a fully active
  5992. Binding instance. The binding will actually become active only when you
  5993. instantiate the object the binding belongs to. It is useful however, to
  5994. understand what actually happens when the binding is activated.
  5995. For a binding to function it must have at least a `from` property and a `to`
  5996. property. The `from` property path points to the object/key that you want to
  5997. bind from while the `to` path points to the object/key you want to bind to.
  5998. When you define a custom binding, you are usually describing the property
  5999. you want to bind from (such as `MyApp.someController.value` in the examples
  6000. above). When your object is created, it will automatically assign the value
  6001. you want to bind `to` based on the name of your binding key. In the
  6002. examples above, during init, Ember objects will effectively call
  6003. something like this on your binding:
  6004. ```javascript
  6005. binding = Ember.Binding.from(this.valueBinding).to("value");
  6006. ```
  6007. This creates a new binding instance based on the template you provide, and
  6008. sets the to path to the `value` property of the new object. Now that the
  6009. binding is fully configured with a `from` and a `to`, it simply needs to be
  6010. connected to become active. This is done through the `connect()` method:
  6011. ```javascript
  6012. binding.connect(this);
  6013. ```
  6014. Note that when you connect a binding you pass the object you want it to be
  6015. connected to. This object will be used as the root for both the from and
  6016. to side of the binding when inspecting relative paths. This allows the
  6017. binding to be automatically inherited by subclassed objects as well.
  6018. Now that the binding is connected, it will observe both the from and to side
  6019. and relay changes.
  6020. If you ever needed to do so (you almost never will, but it is useful to
  6021. understand this anyway), you could manually create an active binding by
  6022. using the `Ember.bind()` helper method. (This is the same method used by
  6023. to setup your bindings on objects):
  6024. ```javascript
  6025. Ember.bind(MyApp.anotherObject, "value", "MyApp.someController.value");
  6026. ```
  6027. Both of these code fragments have the same effect as doing the most friendly
  6028. form of binding creation like so:
  6029. ```javascript
  6030. MyApp.anotherObject = Ember.Object.create({
  6031. valueBinding: "MyApp.someController.value",
  6032. // OTHER CODE FOR THIS OBJECT...
  6033. });
  6034. ```
  6035. Ember's built in binding creation method makes it easy to automatically
  6036. create bindings for you. You should always use the highest-level APIs
  6037. available, even if you understand how it works underneath.
  6038. @class Binding
  6039. @namespace Ember
  6040. @since Ember 0.9
  6041. */
  6042. Ember.Binding = Binding;
  6043. /**
  6044. Global helper method to create a new binding. Just pass the root object
  6045. along with a `to` and `from` path to create and connect the binding.
  6046. @method bind
  6047. @for Ember
  6048. @param {Object} obj The root object of the transform.
  6049. @param {String} to The path to the 'to' side of the binding.
  6050. Must be relative to obj.
  6051. @param {String} from The path to the 'from' side of the binding.
  6052. Must be relative to obj or a global path.
  6053. @return {Ember.Binding} binding instance
  6054. */
  6055. Ember.bind = function(obj, to, from) {
  6056. return new Ember.Binding(to, from).connect(obj);
  6057. };
  6058. /**
  6059. @method oneWay
  6060. @for Ember
  6061. @param {Object} obj The root object of the transform.
  6062. @param {String} to The path to the 'to' side of the binding.
  6063. Must be relative to obj.
  6064. @param {String} from The path to the 'from' side of the binding.
  6065. Must be relative to obj or a global path.
  6066. @return {Ember.Binding} binding instance
  6067. */
  6068. Ember.oneWay = function(obj, to, from) {
  6069. return new Ember.Binding(to, from).oneWay().connect(obj);
  6070. };
  6071. })();
  6072. (function() {
  6073. /**
  6074. @module ember
  6075. @submodule ember-metal
  6076. */
  6077. var Mixin, REQUIRED, Alias,
  6078. a_map = Ember.ArrayPolyfills.map,
  6079. a_indexOf = Ember.ArrayPolyfills.indexOf,
  6080. a_forEach = Ember.ArrayPolyfills.forEach,
  6081. a_slice = [].slice,
  6082. o_create = Ember.create,
  6083. defineProperty = Ember.defineProperty,
  6084. guidFor = Ember.guidFor,
  6085. metaFor = Ember.meta,
  6086. META_KEY = Ember.META_KEY;
  6087. var expandProperties = Ember.expandProperties;
  6088. function mixinsMeta(obj) {
  6089. var m = metaFor(obj, true), ret = m.mixins;
  6090. if (!ret) {
  6091. ret = m.mixins = {};
  6092. } else if (!m.hasOwnProperty('mixins')) {
  6093. ret = m.mixins = o_create(ret);
  6094. }
  6095. return ret;
  6096. }
  6097. function initMixin(mixin, args) {
  6098. if (args && args.length > 0) {
  6099. mixin.mixins = a_map.call(args, function(x) {
  6100. if (x instanceof Mixin) { return x; }
  6101. // Note: Manually setup a primitive mixin here. This is the only
  6102. // way to actually get a primitive mixin. This way normal creation
  6103. // of mixins will give you combined mixins...
  6104. var mixin = new Mixin();
  6105. mixin.properties = x;
  6106. return mixin;
  6107. });
  6108. }
  6109. return mixin;
  6110. }
  6111. function isMethod(obj) {
  6112. return 'function' === typeof obj &&
  6113. obj.isMethod !== false &&
  6114. obj !== Boolean && obj !== Object && obj !== Number && obj !== Array && obj !== Date && obj !== String;
  6115. }
  6116. var CONTINUE = {};
  6117. function mixinProperties(mixinsMeta, mixin) {
  6118. var guid;
  6119. if (mixin instanceof Mixin) {
  6120. guid = guidFor(mixin);
  6121. if (mixinsMeta[guid]) { return CONTINUE; }
  6122. mixinsMeta[guid] = mixin;
  6123. return mixin.properties;
  6124. } else {
  6125. return mixin; // apply anonymous mixin properties
  6126. }
  6127. }
  6128. function concatenatedMixinProperties(concatProp, props, values, base) {
  6129. var concats;
  6130. // reset before adding each new mixin to pickup concats from previous
  6131. concats = values[concatProp] || base[concatProp];
  6132. if (props[concatProp]) {
  6133. concats = concats ? concats.concat(props[concatProp]) : props[concatProp];
  6134. }
  6135. return concats;
  6136. }
  6137. function giveDescriptorSuper(meta, key, property, values, descs) {
  6138. var superProperty;
  6139. // Computed properties override methods, and do not call super to them
  6140. if (values[key] === undefined) {
  6141. // Find the original descriptor in a parent mixin
  6142. superProperty = descs[key];
  6143. }
  6144. // If we didn't find the original descriptor in a parent mixin, find
  6145. // it on the original object.
  6146. superProperty = superProperty || meta.descs[key];
  6147. if (!superProperty || !(superProperty instanceof Ember.ComputedProperty)) {
  6148. return property;
  6149. }
  6150. // Since multiple mixins may inherit from the same parent, we need
  6151. // to clone the computed property so that other mixins do not receive
  6152. // the wrapped version.
  6153. property = o_create(property);
  6154. property.func = Ember.wrap(property.func, superProperty.func);
  6155. return property;
  6156. }
  6157. function giveMethodSuper(obj, key, method, values, descs) {
  6158. var superMethod;
  6159. // Methods overwrite computed properties, and do not call super to them.
  6160. if (descs[key] === undefined) {
  6161. // Find the original method in a parent mixin
  6162. superMethod = values[key];
  6163. }
  6164. // If we didn't find the original value in a parent mixin, find it in
  6165. // the original object
  6166. superMethod = superMethod || obj[key];
  6167. // Only wrap the new method if the original method was a function
  6168. if ('function' !== typeof superMethod) {
  6169. return method;
  6170. }
  6171. return Ember.wrap(method, superMethod);
  6172. }
  6173. function applyConcatenatedProperties(obj, key, value, values) {
  6174. var baseValue = values[key] || obj[key];
  6175. if (baseValue) {
  6176. if ('function' === typeof baseValue.concat) {
  6177. return baseValue.concat(value);
  6178. } else {
  6179. return Ember.makeArray(baseValue).concat(value);
  6180. }
  6181. } else {
  6182. return Ember.makeArray(value);
  6183. }
  6184. }
  6185. function applyMergedProperties(obj, key, value, values) {
  6186. var baseValue = values[key] || obj[key];
  6187. if (!baseValue) { return value; }
  6188. var newBase = Ember.merge({}, baseValue);
  6189. for (var prop in value) {
  6190. if (!value.hasOwnProperty(prop)) { continue; }
  6191. var propValue = value[prop];
  6192. if (isMethod(propValue)) {
  6193. // TODO: support for Computed Properties, etc?
  6194. newBase[prop] = giveMethodSuper(obj, prop, propValue, baseValue, {});
  6195. } else {
  6196. newBase[prop] = propValue;
  6197. }
  6198. }
  6199. return newBase;
  6200. }
  6201. function addNormalizedProperty(base, key, value, meta, descs, values, concats, mergings) {
  6202. if (value instanceof Ember.Descriptor) {
  6203. if (value === REQUIRED && descs[key]) { return CONTINUE; }
  6204. // Wrap descriptor function to implement
  6205. // _super() if needed
  6206. if (value.func) {
  6207. value = giveDescriptorSuper(meta, key, value, values, descs);
  6208. }
  6209. descs[key] = value;
  6210. values[key] = undefined;
  6211. } else {
  6212. if ((concats && a_indexOf.call(concats, key) >= 0) ||
  6213. key === 'concatenatedProperties' ||
  6214. key === 'mergedProperties') {
  6215. value = applyConcatenatedProperties(base, key, value, values);
  6216. } else if ((mergings && a_indexOf.call(mergings, key) >= 0)) {
  6217. value = applyMergedProperties(base, key, value, values);
  6218. } else if (isMethod(value)) {
  6219. value = giveMethodSuper(base, key, value, values, descs);
  6220. }
  6221. descs[key] = undefined;
  6222. values[key] = value;
  6223. }
  6224. }
  6225. function mergeMixins(mixins, m, descs, values, base, keys) {
  6226. var mixin, props, key, concats, mergings, meta;
  6227. function removeKeys(keyName) {
  6228. delete descs[keyName];
  6229. delete values[keyName];
  6230. }
  6231. for(var i=0, l=mixins.length; i<l; i++) {
  6232. mixin = mixins[i];
  6233. Ember.assert('Expected hash or Mixin instance, got ' + Object.prototype.toString.call(mixin),
  6234. typeof mixin === 'object' && mixin !== null && Object.prototype.toString.call(mixin) !== '[object Array]');
  6235. props = mixinProperties(m, mixin);
  6236. if (props === CONTINUE) { continue; }
  6237. if (props) {
  6238. meta = metaFor(base);
  6239. if (base.willMergeMixin) { base.willMergeMixin(props); }
  6240. concats = concatenatedMixinProperties('concatenatedProperties', props, values, base);
  6241. mergings = concatenatedMixinProperties('mergedProperties', props, values, base);
  6242. for (key in props) {
  6243. if (!props.hasOwnProperty(key)) { continue; }
  6244. keys.push(key);
  6245. addNormalizedProperty(base, key, props[key], meta, descs, values, concats, mergings);
  6246. }
  6247. // manually copy toString() because some JS engines do not enumerate it
  6248. if (props.hasOwnProperty('toString')) { base.toString = props.toString; }
  6249. } else if (mixin.mixins) {
  6250. mergeMixins(mixin.mixins, m, descs, values, base, keys);
  6251. if (mixin._without) { a_forEach.call(mixin._without, removeKeys); }
  6252. }
  6253. }
  6254. }
  6255. var IS_BINDING = Ember.IS_BINDING = /^.+Binding$/;
  6256. function detectBinding(obj, key, value, m) {
  6257. if (IS_BINDING.test(key)) {
  6258. var bindings = m.bindings;
  6259. if (!bindings) {
  6260. bindings = m.bindings = {};
  6261. } else if (!m.hasOwnProperty('bindings')) {
  6262. bindings = m.bindings = o_create(m.bindings);
  6263. }
  6264. bindings[key] = value;
  6265. }
  6266. }
  6267. function connectBindings(obj, m) {
  6268. // TODO Mixin.apply(instance) should disconnect binding if exists
  6269. var bindings = m.bindings, key, binding, to;
  6270. if (bindings) {
  6271. for (key in bindings) {
  6272. binding = bindings[key];
  6273. if (binding) {
  6274. to = key.slice(0, -7); // strip Binding off end
  6275. if (binding instanceof Ember.Binding) {
  6276. binding = binding.copy(); // copy prototypes' instance
  6277. binding.to(to);
  6278. } else { // binding is string path
  6279. binding = new Ember.Binding(to, binding);
  6280. }
  6281. binding.connect(obj);
  6282. obj[key] = binding;
  6283. }
  6284. }
  6285. // mark as applied
  6286. m.bindings = {};
  6287. }
  6288. }
  6289. function finishPartial(obj, m) {
  6290. connectBindings(obj, m || metaFor(obj));
  6291. return obj;
  6292. }
  6293. function followAlias(obj, desc, m, descs, values) {
  6294. var altKey = desc.methodName, value;
  6295. if (descs[altKey] || values[altKey]) {
  6296. value = values[altKey];
  6297. desc = descs[altKey];
  6298. } else if (m.descs[altKey]) {
  6299. desc = m.descs[altKey];
  6300. value = undefined;
  6301. } else {
  6302. desc = undefined;
  6303. value = obj[altKey];
  6304. }
  6305. return { desc: desc, value: value };
  6306. }
  6307. function updateObserversAndListeners(obj, key, observerOrListener, pathsKey, updateMethod) {
  6308. var paths = observerOrListener[pathsKey];
  6309. if (paths) {
  6310. for (var i=0, l=paths.length; i<l; i++) {
  6311. Ember[updateMethod](obj, paths[i], null, key);
  6312. }
  6313. }
  6314. }
  6315. function replaceObserversAndListeners(obj, key, observerOrListener) {
  6316. var prev = obj[key];
  6317. if ('function' === typeof prev) {
  6318. updateObserversAndListeners(obj, key, prev, '__ember_observesBefore__', 'removeBeforeObserver');
  6319. updateObserversAndListeners(obj, key, prev, '__ember_observes__', 'removeObserver');
  6320. updateObserversAndListeners(obj, key, prev, '__ember_listens__', 'removeListener');
  6321. }
  6322. if ('function' === typeof observerOrListener) {
  6323. updateObserversAndListeners(obj, key, observerOrListener, '__ember_observesBefore__', 'addBeforeObserver');
  6324. updateObserversAndListeners(obj, key, observerOrListener, '__ember_observes__', 'addObserver');
  6325. updateObserversAndListeners(obj, key, observerOrListener, '__ember_listens__', 'addListener');
  6326. }
  6327. }
  6328. function applyMixin(obj, mixins, partial) {
  6329. var descs = {}, values = {}, m = metaFor(obj),
  6330. key, value, desc, keys = [];
  6331. // Go through all mixins and hashes passed in, and:
  6332. //
  6333. // * Handle concatenated properties
  6334. // * Handle merged properties
  6335. // * Set up _super wrapping if necessary
  6336. // * Set up computed property descriptors
  6337. // * Copying `toString` in broken browsers
  6338. mergeMixins(mixins, mixinsMeta(obj), descs, values, obj, keys);
  6339. for(var i = 0, l = keys.length; i < l; i++) {
  6340. key = keys[i];
  6341. if (key === 'constructor' || !values.hasOwnProperty(key)) { continue; }
  6342. desc = descs[key];
  6343. value = values[key];
  6344. if (desc === REQUIRED) { continue; }
  6345. while (desc && desc instanceof Alias) {
  6346. var followed = followAlias(obj, desc, m, descs, values);
  6347. desc = followed.desc;
  6348. value = followed.value;
  6349. }
  6350. if (desc === undefined && value === undefined) { continue; }
  6351. replaceObserversAndListeners(obj, key, value);
  6352. detectBinding(obj, key, value, m);
  6353. defineProperty(obj, key, desc, value, m);
  6354. }
  6355. if (!partial) { // don't apply to prototype
  6356. finishPartial(obj, m);
  6357. }
  6358. return obj;
  6359. }
  6360. /**
  6361. @method mixin
  6362. @for Ember
  6363. @param obj
  6364. @param mixins*
  6365. @return obj
  6366. */
  6367. Ember.mixin = function(obj) {
  6368. var args = a_slice.call(arguments, 1);
  6369. applyMixin(obj, args, false);
  6370. return obj;
  6371. };
  6372. /**
  6373. The `Ember.Mixin` class allows you to create mixins, whose properties can be
  6374. added to other classes. For instance,
  6375. ```javascript
  6376. App.Editable = Ember.Mixin.create({
  6377. edit: function() {
  6378. console.log('starting to edit');
  6379. this.set('isEditing', true);
  6380. },
  6381. isEditing: false
  6382. });
  6383. // Mix mixins into classes by passing them as the first arguments to
  6384. // .extend.
  6385. App.CommentView = Ember.View.extend(App.Editable, {
  6386. template: Ember.Handlebars.compile('{{#if view.isEditing}}...{{else}}...{{/if}}')
  6387. });
  6388. commentView = App.CommentView.create();
  6389. commentView.edit(); // outputs 'starting to edit'
  6390. ```
  6391. Note that Mixins are created with `Ember.Mixin.create`, not
  6392. `Ember.Mixin.extend`.
  6393. Note that mixins extend a constructor's prototype so arrays and object literals
  6394. defined as properties will be shared amongst objects that implement the mixin.
  6395. If you want to define a property in a mixin that is not shared, you can define
  6396. it either as a computed property or have it be created on initialization of the object.
  6397. ```javascript
  6398. //filters array will be shared amongst any object implementing mixin
  6399. App.Filterable = Ember.Mixin.create({
  6400. filters: Ember.A()
  6401. });
  6402. //filters will be a separate array for every object implementing the mixin
  6403. App.Filterable = Ember.Mixin.create({
  6404. filters: Ember.computed(function(){return Ember.A();})
  6405. });
  6406. //filters will be created as a separate array during the object's initialization
  6407. App.Filterable = Ember.Mixin.create({
  6408. init: function() {
  6409. this._super();
  6410. this.set("filters", Ember.A());
  6411. }
  6412. });
  6413. ```
  6414. @class Mixin
  6415. @namespace Ember
  6416. */
  6417. Ember.Mixin = function() { return initMixin(this, arguments); };
  6418. Mixin = Ember.Mixin;
  6419. Mixin.prototype = {
  6420. properties: null,
  6421. mixins: null,
  6422. ownerConstructor: null
  6423. };
  6424. Mixin._apply = applyMixin;
  6425. Mixin.applyPartial = function(obj) {
  6426. var args = a_slice.call(arguments, 1);
  6427. return applyMixin(obj, args, true);
  6428. };
  6429. Mixin.finishPartial = finishPartial;
  6430. Ember.anyUnprocessedMixins = false;
  6431. /**
  6432. @method create
  6433. @static
  6434. @param arguments*
  6435. */
  6436. Mixin.create = function() {
  6437. Ember.anyUnprocessedMixins = true;
  6438. var M = this;
  6439. return initMixin(new M(), arguments);
  6440. };
  6441. var MixinPrototype = Mixin.prototype;
  6442. /**
  6443. @method reopen
  6444. @param arguments*
  6445. */
  6446. MixinPrototype.reopen = function() {
  6447. var mixin, tmp;
  6448. if (this.properties) {
  6449. mixin = Mixin.create();
  6450. mixin.properties = this.properties;
  6451. delete this.properties;
  6452. this.mixins = [mixin];
  6453. } else if (!this.mixins) {
  6454. this.mixins = [];
  6455. }
  6456. var len = arguments.length, mixins = this.mixins, idx;
  6457. for(idx=0; idx < len; idx++) {
  6458. mixin = arguments[idx];
  6459. Ember.assert('Expected hash or Mixin instance, got ' + Object.prototype.toString.call(mixin),
  6460. typeof mixin === 'object' && mixin !== null && Object.prototype.toString.call(mixin) !== '[object Array]');
  6461. if (mixin instanceof Mixin) {
  6462. mixins.push(mixin);
  6463. } else {
  6464. tmp = Mixin.create();
  6465. tmp.properties = mixin;
  6466. mixins.push(tmp);
  6467. }
  6468. }
  6469. return this;
  6470. };
  6471. /**
  6472. @method apply
  6473. @param obj
  6474. @return applied object
  6475. */
  6476. MixinPrototype.apply = function(obj) {
  6477. return applyMixin(obj, [this], false);
  6478. };
  6479. MixinPrototype.applyPartial = function(obj) {
  6480. return applyMixin(obj, [this], true);
  6481. };
  6482. function _detect(curMixin, targetMixin, seen) {
  6483. var guid = guidFor(curMixin);
  6484. if (seen[guid]) { return false; }
  6485. seen[guid] = true;
  6486. if (curMixin === targetMixin) { return true; }
  6487. var mixins = curMixin.mixins, loc = mixins ? mixins.length : 0;
  6488. while (--loc >= 0) {
  6489. if (_detect(mixins[loc], targetMixin, seen)) { return true; }
  6490. }
  6491. return false;
  6492. }
  6493. /**
  6494. @method detect
  6495. @param obj
  6496. @return {Boolean}
  6497. */
  6498. MixinPrototype.detect = function(obj) {
  6499. if (!obj) { return false; }
  6500. if (obj instanceof Mixin) { return _detect(obj, this, {}); }
  6501. var m = obj[META_KEY],
  6502. mixins = m && m.mixins;
  6503. if (mixins) {
  6504. return !!mixins[guidFor(this)];
  6505. }
  6506. return false;
  6507. };
  6508. MixinPrototype.without = function() {
  6509. var ret = new Mixin(this);
  6510. ret._without = a_slice.call(arguments);
  6511. return ret;
  6512. };
  6513. function _keys(ret, mixin, seen) {
  6514. if (seen[guidFor(mixin)]) { return; }
  6515. seen[guidFor(mixin)] = true;
  6516. if (mixin.properties) {
  6517. var props = mixin.properties;
  6518. for (var key in props) {
  6519. if (props.hasOwnProperty(key)) { ret[key] = true; }
  6520. }
  6521. } else if (mixin.mixins) {
  6522. a_forEach.call(mixin.mixins, function(x) { _keys(ret, x, seen); });
  6523. }
  6524. }
  6525. MixinPrototype.keys = function() {
  6526. var keys = {}, seen = {}, ret = [];
  6527. _keys(keys, this, seen);
  6528. for(var key in keys) {
  6529. if (keys.hasOwnProperty(key)) { ret.push(key); }
  6530. }
  6531. return ret;
  6532. };
  6533. // returns the mixins currently applied to the specified object
  6534. // TODO: Make Ember.mixin
  6535. Mixin.mixins = function(obj) {
  6536. var m = obj[META_KEY],
  6537. mixins = m && m.mixins, ret = [];
  6538. if (!mixins) { return ret; }
  6539. for (var key in mixins) {
  6540. var mixin = mixins[key];
  6541. // skip primitive mixins since these are always anonymous
  6542. if (!mixin.properties) { ret.push(mixin); }
  6543. }
  6544. return ret;
  6545. };
  6546. REQUIRED = new Ember.Descriptor();
  6547. REQUIRED.toString = function() { return '(Required Property)'; };
  6548. /**
  6549. Denotes a required property for a mixin
  6550. @method required
  6551. @for Ember
  6552. */
  6553. Ember.required = function() {
  6554. return REQUIRED;
  6555. };
  6556. Alias = function(methodName) {
  6557. this.methodName = methodName;
  6558. };
  6559. Alias.prototype = new Ember.Descriptor();
  6560. /**
  6561. Makes a method available via an additional name.
  6562. ```javascript
  6563. App.Person = Ember.Object.extend({
  6564. name: function() {
  6565. return 'Tomhuda Katzdale';
  6566. },
  6567. moniker: Ember.aliasMethod('name')
  6568. });
  6569. var goodGuy = App.Person.create()
  6570. ```
  6571. @method aliasMethod
  6572. @for Ember
  6573. @param {String} methodName name of the method to alias
  6574. @return {Ember.Descriptor}
  6575. */
  6576. Ember.aliasMethod = function(methodName) {
  6577. return new Alias(methodName);
  6578. };
  6579. // ..........................................................
  6580. // OBSERVER HELPER
  6581. //
  6582. /**
  6583. Specify a method that observes property changes.
  6584. ```javascript
  6585. Ember.Object.extend({
  6586. valueObserver: Ember.observer('value', function() {
  6587. // Executes whenever the "value" property changes
  6588. })
  6589. });
  6590. ```
  6591. In the future this method may become asynchronous. If you want to ensure
  6592. synchronous behavior, use `immediateObserver`.
  6593. Also available as `Function.prototype.observes` if prototype extensions are
  6594. enabled.
  6595. @method observer
  6596. @for Ember
  6597. @param {String} propertyNames*
  6598. @param {Function} func
  6599. @return func
  6600. */
  6601. Ember.observer = function() {
  6602. var func = a_slice.call(arguments, -1)[0];
  6603. var paths;
  6604. var addWatchedProperty = function (path) { paths.push(path); };
  6605. var _paths = a_slice.call(arguments, 0, -1);
  6606. if (typeof func !== "function") {
  6607. // revert to old, soft-deprecated argument ordering
  6608. func = arguments[0];
  6609. _paths = a_slice.call(arguments, 1);
  6610. }
  6611. paths = [];
  6612. for (var i=0; i<_paths.length; ++i) {
  6613. expandProperties(_paths[i], addWatchedProperty);
  6614. }
  6615. if (typeof func !== "function") {
  6616. throw new Ember.Error("Ember.observer called without a function");
  6617. }
  6618. func.__ember_observes__ = paths;
  6619. return func;
  6620. };
  6621. /**
  6622. Specify a method that observes property changes.
  6623. ```javascript
  6624. Ember.Object.extend({
  6625. valueObserver: Ember.immediateObserver('value', function() {
  6626. // Executes whenever the "value" property changes
  6627. })
  6628. });
  6629. ```
  6630. In the future, `Ember.observer` may become asynchronous. In this event,
  6631. `Ember.immediateObserver` will maintain the synchronous behavior.
  6632. Also available as `Function.prototype.observesImmediately` if prototype extensions are
  6633. enabled.
  6634. @method immediateObserver
  6635. @for Ember
  6636. @param {String} propertyNames*
  6637. @param {Function} func
  6638. @return func
  6639. */
  6640. Ember.immediateObserver = function() {
  6641. for (var i=0, l=arguments.length; i<l; i++) {
  6642. var arg = arguments[i];
  6643. Ember.assert("Immediate observers must observe internal properties only, not properties on other objects.", typeof arg !== "string" || arg.indexOf('.') === -1);
  6644. }
  6645. return Ember.observer.apply(this, arguments);
  6646. };
  6647. /**
  6648. When observers fire, they are called with the arguments `obj`, `keyName`.
  6649. Note, `@each.property` observer is called per each add or replace of an element
  6650. and it's not called with a specific enumeration item.
  6651. A `beforeObserver` fires before a property changes.
  6652. A `beforeObserver` is an alternative form of `.observesBefore()`.
  6653. ```javascript
  6654. App.PersonView = Ember.View.extend({
  6655. friends: [{ name: 'Tom' }, { name: 'Stefan' }, { name: 'Kris' }],
  6656. valueWillChange: Ember.beforeObserver('content.value', function(obj, keyName) {
  6657. this.changingFrom = obj.get(keyName);
  6658. }),
  6659. valueDidChange: Ember.observer('content.value', function(obj, keyName) {
  6660. // only run if updating a value already in the DOM
  6661. if (this.get('state') === 'inDOM') {
  6662. var color = obj.get(keyName) > this.changingFrom ? 'green' : 'red';
  6663. // logic
  6664. }
  6665. }),
  6666. friendsDidChange: Ember.observer('friends.@each.name', function(obj, keyName) {
  6667. // some logic
  6668. // obj.get(keyName) returns friends array
  6669. })
  6670. });
  6671. ```
  6672. Also available as `Function.prototype.observesBefore` if prototype extensions are
  6673. enabled.
  6674. @method beforeObserver
  6675. @for Ember
  6676. @param {String} propertyNames*
  6677. @param {Function} func
  6678. @return func
  6679. */
  6680. Ember.beforeObserver = function() {
  6681. var func = a_slice.call(arguments, -1)[0];
  6682. var paths;
  6683. var addWatchedProperty = function(path) { paths.push(path); };
  6684. var _paths = a_slice.call(arguments, 0, -1);
  6685. if (typeof func !== "function") {
  6686. // revert to old, soft-deprecated argument ordering
  6687. func = arguments[0];
  6688. _paths = a_slice.call(arguments, 1);
  6689. }
  6690. paths = [];
  6691. for (var i=0; i<_paths.length; ++i) {
  6692. expandProperties(_paths[i], addWatchedProperty);
  6693. }
  6694. if (typeof func !== "function") {
  6695. throw new Ember.Error("Ember.beforeObserver called without a function");
  6696. }
  6697. func.__ember_observesBefore__ = paths;
  6698. return func;
  6699. };
  6700. })();
  6701. (function() {
  6702. // Provides a way to register library versions with ember.
  6703. var forEach = Ember.EnumerableUtils.forEach,
  6704. indexOf = Ember.EnumerableUtils.indexOf;
  6705. Ember.libraries = function() {
  6706. var libraries = [];
  6707. var coreLibIndex = 0;
  6708. var getLibrary = function(name) {
  6709. for (var i = 0; i < libraries.length; i++) {
  6710. if (libraries[i].name === name) {
  6711. return libraries[i];
  6712. }
  6713. }
  6714. };
  6715. libraries.register = function(name, version) {
  6716. if (!getLibrary(name)) {
  6717. libraries.push({name: name, version: version});
  6718. }
  6719. };
  6720. libraries.registerCoreLibrary = function(name, version) {
  6721. if (!getLibrary(name)) {
  6722. libraries.splice(coreLibIndex++, 0, {name: name, version: version});
  6723. }
  6724. };
  6725. libraries.deRegister = function(name) {
  6726. var lib = getLibrary(name);
  6727. if (lib) libraries.splice(indexOf(libraries, lib), 1);
  6728. };
  6729. libraries.each = function (callback) {
  6730. forEach(libraries, function(lib) {
  6731. callback(lib.name, lib.version);
  6732. });
  6733. };
  6734. return libraries;
  6735. }();
  6736. Ember.libraries.registerCoreLibrary('Ember', Ember.VERSION);
  6737. })();
  6738. (function() {
  6739. /**
  6740. Ember Metal
  6741. @module ember
  6742. @submodule ember-metal
  6743. */
  6744. })();
  6745. (function() {
  6746. /**
  6747. @class RSVP
  6748. @module RSVP
  6749. */
  6750. define("rsvp/all",
  6751. ["./promise","exports"],
  6752. function(__dependency1__, __exports__) {
  6753. "use strict";
  6754. var Promise = __dependency1__["default"];
  6755. /**
  6756. This is a convenient alias for `RSVP.Promise.all`.
  6757. @method all
  6758. @for RSVP
  6759. @param {Array} array Array of promises.
  6760. @param {String} label An optional label. This is useful
  6761. for tooling.
  6762. @static
  6763. */
  6764. __exports__["default"] = function all(array, label) {
  6765. return Promise.all(array, label);
  6766. };
  6767. });
  6768. define("rsvp/all_settled",
  6769. ["./promise","./utils","exports"],
  6770. function(__dependency1__, __dependency2__, __exports__) {
  6771. "use strict";
  6772. var Promise = __dependency1__["default"];
  6773. var isArray = __dependency2__.isArray;
  6774. var isNonThenable = __dependency2__.isNonThenable;
  6775. /**
  6776. `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing
  6777. a fail-fast method, it waits until all the promises have returned and
  6778. shows you all the results. This is useful if you want to handle multiple
  6779. promises' failure states together as a set.
  6780. Returns a promise that is fulfilled when all the given promises have been
  6781. settled. The return promise is fulfilled with an array of the states of
  6782. the promises passed into the `promises` array argument.
  6783. Each state object will either indicate fulfillment or rejection, and
  6784. provide the corresponding value or reason. The states will take one of
  6785. the following formats:
  6786. ```javascript
  6787. { state: 'fulfilled', value: value }
  6788. or
  6789. { state: 'rejected', reason: reason }
  6790. ```
  6791. Example:
  6792. ```javascript
  6793. var promise1 = RSVP.Promise.resolve(1);
  6794. var promise2 = RSVP.Promise.reject(new Error('2'));
  6795. var promise3 = RSVP.Promise.reject(new Error('3'));
  6796. var promises = [ promise1, promise2, promise3 ];
  6797. RSVP.allSettled(promises).then(function(array){
  6798. // array == [
  6799. // { state: 'fulfilled', value: 1 },
  6800. // { state: 'rejected', reason: Error },
  6801. // { state: 'rejected', reason: Error }
  6802. // ]
  6803. // Note that for the second item, reason.message will be "2", and for the
  6804. // third item, reason.message will be "3".
  6805. }, function(error) {
  6806. // Not run. (This block would only be called if allSettled had failed,
  6807. // for instance if passed an incorrect argument type.)
  6808. });
  6809. ```
  6810. @method allSettled
  6811. @for RSVP
  6812. @param {Array} promises
  6813. @param {String} label - optional string that describes the promise.
  6814. Useful for tooling.
  6815. @return {Promise} promise that is fulfilled with an array of the settled
  6816. states of the constituent promises.
  6817. @static
  6818. */
  6819. __exports__["default"] = function allSettled(entries, label) {
  6820. return new Promise(function(resolve, reject) {
  6821. if (!isArray(entries)) {
  6822. throw new TypeError('You must pass an array to allSettled.');
  6823. }
  6824. var remaining = entries.length;
  6825. var entry;
  6826. if (remaining === 0) {
  6827. resolve([]);
  6828. return;
  6829. }
  6830. var results = new Array(remaining);
  6831. function fulfilledResolver(index) {
  6832. return function(value) {
  6833. resolveAll(index, fulfilled(value));
  6834. };
  6835. }
  6836. function rejectedResolver(index) {
  6837. return function(reason) {
  6838. resolveAll(index, rejected(reason));
  6839. };
  6840. }
  6841. function resolveAll(index, value) {
  6842. results[index] = value;
  6843. if (--remaining === 0) {
  6844. resolve(results);
  6845. }
  6846. }
  6847. for (var index = 0; index < entries.length; index++) {
  6848. entry = entries[index];
  6849. if (isNonThenable(entry)) {
  6850. resolveAll(index, fulfilled(entry));
  6851. } else {
  6852. Promise.cast(entry).then(fulfilledResolver(index), rejectedResolver(index));
  6853. }
  6854. }
  6855. }, label);
  6856. };
  6857. function fulfilled(value) {
  6858. return { state: 'fulfilled', value: value };
  6859. }
  6860. function rejected(reason) {
  6861. return { state: 'rejected', reason: reason };
  6862. }
  6863. });
  6864. define("rsvp/config",
  6865. ["./events","exports"],
  6866. function(__dependency1__, __exports__) {
  6867. "use strict";
  6868. var EventTarget = __dependency1__["default"];
  6869. var config = {
  6870. instrument: false
  6871. };
  6872. EventTarget.mixin(config);
  6873. function configure(name, value) {
  6874. if (name === 'onerror') {
  6875. // handle for legacy users that expect the actual
  6876. // error to be passed to their function added via
  6877. // `RSVP.configure('onerror', someFunctionHere);`
  6878. config.on('error', value);
  6879. return;
  6880. }
  6881. if (arguments.length === 2) {
  6882. config[name] = value;
  6883. } else {
  6884. return config[name];
  6885. }
  6886. }
  6887. __exports__.config = config;
  6888. __exports__.configure = configure;
  6889. });
  6890. define("rsvp/defer",
  6891. ["./promise","exports"],
  6892. function(__dependency1__, __exports__) {
  6893. "use strict";
  6894. var Promise = __dependency1__["default"];
  6895. /**
  6896. `RSVP.defer` returns an object similar to jQuery's `$.Deferred`.
  6897. `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s
  6898. interface. New code should use the `RSVP.Promise` constructor instead.
  6899. The object returned from `RSVP.defer` is a plain object with three properties:
  6900. * promise - an `RSVP.Promise`.
  6901. * reject - a function that causes the `promise` property on this object to
  6902. become rejected
  6903. * resolve - a function that causes the `promise` property on this object to
  6904. become fulfilled.
  6905. Example:
  6906. ```javascript
  6907. var deferred = RSVP.defer();
  6908. deferred.resolve("Success!");
  6909. defered.promise.then(function(value){
  6910. // value here is "Success!"
  6911. });
  6912. ```
  6913. @method defer
  6914. @for RSVP
  6915. @param {String} label optional string for labeling the promise.
  6916. Useful for tooling.
  6917. @return {Object}
  6918. */
  6919. __exports__["default"] = function defer(label) {
  6920. var deferred = { };
  6921. deferred.promise = new Promise(function(resolve, reject) {
  6922. deferred.resolve = resolve;
  6923. deferred.reject = reject;
  6924. }, label);
  6925. return deferred;
  6926. };
  6927. });
  6928. define("rsvp/events",
  6929. ["exports"],
  6930. function(__exports__) {
  6931. "use strict";
  6932. var indexOf = function(callbacks, callback) {
  6933. for (var i=0, l=callbacks.length; i<l; i++) {
  6934. if (callbacks[i] === callback) { return i; }
  6935. }
  6936. return -1;
  6937. };
  6938. var callbacksFor = function(object) {
  6939. var callbacks = object._promiseCallbacks;
  6940. if (!callbacks) {
  6941. callbacks = object._promiseCallbacks = {};
  6942. }
  6943. return callbacks;
  6944. };
  6945. /**
  6946. @class RSVP.EventTarget
  6947. */
  6948. __exports__["default"] = {
  6949. /**
  6950. `RSVP.EventTarget.mixin` extends an object with EventTarget methods. For
  6951. Example:
  6952. ```javascript
  6953. var object = {};
  6954. RSVP.EventTarget.mixin(object);
  6955. object.on("finished", function(event) {
  6956. // handle event
  6957. });
  6958. object.trigger("finished", { detail: value });
  6959. ```
  6960. `EventTarget.mixin` also works with prototypes:
  6961. ```javascript
  6962. var Person = function() {};
  6963. RSVP.EventTarget.mixin(Person.prototype);
  6964. var yehuda = new Person();
  6965. var tom = new Person();
  6966. yehuda.on("poke", function(event) {
  6967. console.log("Yehuda says OW");
  6968. });
  6969. tom.on("poke", function(event) {
  6970. console.log("Tom says OW");
  6971. });
  6972. yehuda.trigger("poke");
  6973. tom.trigger("poke");
  6974. ```
  6975. @method mixin
  6976. @param {Object} object object to extend with EventTarget methods
  6977. @private
  6978. */
  6979. mixin: function(object) {
  6980. object.on = this.on;
  6981. object.off = this.off;
  6982. object.trigger = this.trigger;
  6983. object._promiseCallbacks = undefined;
  6984. return object;
  6985. },
  6986. /**
  6987. Registers a callback to be executed when `eventName` is triggered
  6988. ```javascript
  6989. object.on('event', function(eventInfo){
  6990. // handle the event
  6991. });
  6992. object.trigger('event');
  6993. ```
  6994. @method on
  6995. @param {String} eventName name of the event to listen for
  6996. @param {Function} callback function to be called when the event is triggered.
  6997. @private
  6998. */
  6999. on: function(eventName, callback) {
  7000. var allCallbacks = callbacksFor(this), callbacks;
  7001. callbacks = allCallbacks[eventName];
  7002. if (!callbacks) {
  7003. callbacks = allCallbacks[eventName] = [];
  7004. }
  7005. if (indexOf(callbacks, callback) === -1) {
  7006. callbacks.push(callback);
  7007. }
  7008. },
  7009. /**
  7010. You can use `off` to stop firing a particular callback for an event:
  7011. ```javascript
  7012. function doStuff() { // do stuff! }
  7013. object.on('stuff', doStuff);
  7014. object.trigger('stuff'); // doStuff will be called
  7015. // Unregister ONLY the doStuff callback
  7016. object.off('stuff', doStuff);
  7017. object.trigger('stuff'); // doStuff will NOT be called
  7018. ```
  7019. If you don't pass a `callback` argument to `off`, ALL callbacks for the
  7020. event will not be executed when the event fires. For example:
  7021. ```javascript
  7022. var callback1 = function(){};
  7023. var callback2 = function(){};
  7024. object.on('stuff', callback1);
  7025. object.on('stuff', callback2);
  7026. object.trigger('stuff'); // callback1 and callback2 will be executed.
  7027. object.off('stuff');
  7028. object.trigger('stuff'); // callback1 and callback2 will not be executed!
  7029. ```
  7030. @method off
  7031. @param {String} eventName event to stop listening to
  7032. @param {Function} callback optional argument. If given, only the function
  7033. given will be removed from the event's callback queue. If no `callback`
  7034. argument is given, all callbacks will be removed from the event's callback
  7035. queue.
  7036. @private
  7037. */
  7038. off: function(eventName, callback) {
  7039. var allCallbacks = callbacksFor(this), callbacks, index;
  7040. if (!callback) {
  7041. allCallbacks[eventName] = [];
  7042. return;
  7043. }
  7044. callbacks = allCallbacks[eventName];
  7045. index = indexOf(callbacks, callback);
  7046. if (index !== -1) { callbacks.splice(index, 1); }
  7047. },
  7048. /**
  7049. Use `trigger` to fire custom events. For example:
  7050. ```javascript
  7051. object.on('foo', function(){
  7052. console.log('foo event happened!');
  7053. });
  7054. object.trigger('foo');
  7055. // 'foo event happened!' logged to the console
  7056. ```
  7057. You can also pass a value as a second argument to `trigger` that will be
  7058. passed as an argument to all event listeners for the event:
  7059. ```javascript
  7060. object.on('foo', function(value){
  7061. console.log(value.name);
  7062. });
  7063. object.trigger('foo', { name: 'bar' });
  7064. // 'bar' logged to the console
  7065. ```
  7066. @method trigger
  7067. @param {String} eventName name of the event to be triggered
  7068. @param {Any} options optional value to be passed to any event handlers for
  7069. the given `eventName`
  7070. @private
  7071. */
  7072. trigger: function(eventName, options) {
  7073. var allCallbacks = callbacksFor(this),
  7074. callbacks, callbackTuple, callback, binding;
  7075. if (callbacks = allCallbacks[eventName]) {
  7076. // Don't cache the callbacks.length since it may grow
  7077. for (var i=0; i<callbacks.length; i++) {
  7078. callback = callbacks[i];
  7079. callback(options);
  7080. }
  7081. }
  7082. }
  7083. };
  7084. });
  7085. define("rsvp/filter",
  7086. ["./all","./map","./utils","exports"],
  7087. function(__dependency1__, __dependency2__, __dependency3__, __exports__) {
  7088. "use strict";
  7089. var all = __dependency1__["default"];
  7090. var map = __dependency2__["default"];
  7091. var isFunction = __dependency3__.isFunction;
  7092. var isArray = __dependency3__.isArray;
  7093. /**
  7094. `RSVP.filter` is similar to JavaScript's native `filter` method, except that it
  7095. waits for all promises to become fulfilled before running the `filterFn` on
  7096. each item in given to `promises`. `RSVP.filter` returns a promise that will
  7097. become fulfilled with the result of running `filterFn` on the values the
  7098. promises become fulfilled with.
  7099. For example:
  7100. ```javascript
  7101. var promise1 = RSVP.resolve(1);
  7102. var promise2 = RSVP.resolve(2);
  7103. var promise3 = RSVP.resolve(3);
  7104. var filterFn = function(item){
  7105. return item > 1;
  7106. };
  7107. RSVP.filter(promises, filterFn).then(function(result){
  7108. // result is [ 2, 3 ]
  7109. });
  7110. ```
  7111. If any of the `promises` given to `RSVP.filter` are rejected, the first promise
  7112. that is rejected will be given as an argument to the returned promise's
  7113. rejection handler. For example:
  7114. ```javascript
  7115. var promise1 = RSVP.resolve(1);
  7116. var promise2 = RSVP.reject(new Error("2"));
  7117. var promise3 = RSVP.reject(new Error("3"));
  7118. var promises = [ promise1, promise2, promise3 ];
  7119. var filterFn = function(item){
  7120. return item > 1;
  7121. };
  7122. RSVP.filter(promises, filterFn).then(function(array){
  7123. // Code here never runs because there are rejected promises!
  7124. }, function(reason) {
  7125. // reason.message === "2"
  7126. });
  7127. ```
  7128. `RSVP.filter` will also wait for any promises returned from `filterFn`.
  7129. For instance, you may want to fetch a list of users then return a subset
  7130. of those users based on some asynchronous operation:
  7131. ```javascript
  7132. var alice = { name: 'alice' };
  7133. var bob = { name: 'bob' };
  7134. var users = [ alice, bob ];
  7135. var promises = users.map(function(user){
  7136. return RSVP.resolve(user);
  7137. });
  7138. var filterFn = function(user){
  7139. // Here, Alice has permissions to create a blog post, but Bob does not.
  7140. return getPrivilegesForUser(user).then(function(privs){
  7141. return privs.can_create_blog_post === true;
  7142. });
  7143. };
  7144. RSVP.filter(promises, filterFn).then(function(users){
  7145. // true, because the server told us only Alice can create a blog post.
  7146. users.length === 1;
  7147. // false, because Alice is the only user present in `users`
  7148. users[0] === bob;
  7149. });
  7150. ```
  7151. @method filter
  7152. @for RSVP
  7153. @param {Array} promises
  7154. @param {Function} filterFn - function to be called on each resolved value to
  7155. filter the final results.
  7156. @param {String} label optional string describing the promise. Useful for
  7157. tooling.
  7158. @return {Promise}
  7159. */
  7160. function filter(promises, filterFn, label) {
  7161. return all(promises, label).then(function(values){
  7162. if (!isArray(promises)) {
  7163. throw new TypeError('You must pass an array to filter.');
  7164. }
  7165. if (!isFunction(filterFn)){
  7166. throw new TypeError("You must pass a function to filter's second argument.");
  7167. }
  7168. return map(promises, filterFn, label).then(function(filterResults){
  7169. var i,
  7170. valuesLen = values.length,
  7171. filtered = [];
  7172. for (i = 0; i < valuesLen; i++){
  7173. if(filterResults[i]) filtered.push(values[i]);
  7174. }
  7175. return filtered;
  7176. });
  7177. });
  7178. }
  7179. __exports__["default"] = filter;
  7180. });
  7181. define("rsvp/hash",
  7182. ["./promise","./utils","exports"],
  7183. function(__dependency1__, __dependency2__, __exports__) {
  7184. "use strict";
  7185. var Promise = __dependency1__["default"];
  7186. var isNonThenable = __dependency2__.isNonThenable;
  7187. var keysOf = __dependency2__.keysOf;
  7188. /**
  7189. `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array
  7190. for its `promises` argument.
  7191. Returns a promise that is fulfilled when all the given promises have been
  7192. fulfilled, or rejected if any of them become rejected. The returned promise
  7193. is fulfilled with a hash that has the same key names as the `promises` object
  7194. argument. If any of the values in the object are not promises, they will
  7195. simply be copied over to the fulfilled object.
  7196. Example:
  7197. ```javascript
  7198. var promises = {
  7199. myPromise: RSVP.resolve(1),
  7200. yourPromise: RSVP.resolve(2),
  7201. theirPromise: RSVP.resolve(3),
  7202. notAPromise: 4
  7203. };
  7204. RSVP.hash(promises).then(function(hash){
  7205. // hash here is an object that looks like:
  7206. // {
  7207. // myPromise: 1,
  7208. // yourPromise: 2,
  7209. // theirPromise: 3,
  7210. // notAPromise: 4
  7211. // }
  7212. });
  7213. ````
  7214. If any of the `promises` given to `RSVP.hash` are rejected, the first promise
  7215. that is rejected will be given as the reason to the rejection handler.
  7216. Example:
  7217. ```javascript
  7218. var promises = {
  7219. myPromise: RSVP.resolve(1),
  7220. rejectedPromise: RSVP.reject(new Error("rejectedPromise")),
  7221. anotherRejectedPromise: RSVP.reject(new Error("anotherRejectedPromise")),
  7222. };
  7223. RSVP.hash(promises).then(function(hash){
  7224. // Code here never runs because there are rejected promises!
  7225. }, function(reason) {
  7226. // reason.message === "rejectedPromise"
  7227. });
  7228. ```
  7229. An important note: `RSVP.hash` is intended for plain JavaScript objects that
  7230. are just a set of keys and values. `RSVP.hash` will NOT preserve prototype
  7231. chains.
  7232. Example:
  7233. ```javascript
  7234. function MyConstructor(){
  7235. this.example = RSVP.resolve("Example");
  7236. }
  7237. MyConstructor.prototype = {
  7238. protoProperty: RSVP.resolve("Proto Property")
  7239. };
  7240. var myObject = new MyConstructor();
  7241. RSVP.hash(myObject).then(function(hash){
  7242. // protoProperty will not be present, instead you will just have an
  7243. // object that looks like:
  7244. // {
  7245. // example: "Example"
  7246. // }
  7247. //
  7248. // hash.hasOwnProperty('protoProperty'); // false
  7249. // 'undefined' === typeof hash.protoProperty
  7250. });
  7251. ```
  7252. @method hash
  7253. @for RSVP
  7254. @param {Object} promises
  7255. @param {String} label optional string that describes the promise.
  7256. Useful for tooling.
  7257. @return {Promise} promise that is fulfilled when all properties of `promises`
  7258. have been fulfilled, or rejected if any of them become rejected.
  7259. @static
  7260. */
  7261. __exports__["default"] = function hash(object, label) {
  7262. return new Promise(function(resolve, reject){
  7263. var results = {};
  7264. var keys = keysOf(object);
  7265. var remaining = keys.length;
  7266. var entry, property;
  7267. if (remaining === 0) {
  7268. resolve(results);
  7269. return;
  7270. }
  7271. function fulfilledTo(property) {
  7272. return function(value) {
  7273. results[property] = value;
  7274. if (--remaining === 0) {
  7275. resolve(results);
  7276. }
  7277. };
  7278. }
  7279. function onRejection(reason) {
  7280. remaining = 0;
  7281. reject(reason);
  7282. }
  7283. for (var i = 0; i < keys.length; i++) {
  7284. property = keys[i];
  7285. entry = object[property];
  7286. if (isNonThenable(entry)) {
  7287. results[property] = entry;
  7288. if (--remaining === 0) {
  7289. resolve(results);
  7290. }
  7291. } else {
  7292. Promise.cast(entry).then(fulfilledTo(property), onRejection);
  7293. }
  7294. }
  7295. });
  7296. };
  7297. });
  7298. define("rsvp/instrument",
  7299. ["./config","./utils","exports"],
  7300. function(__dependency1__, __dependency2__, __exports__) {
  7301. "use strict";
  7302. var config = __dependency1__.config;
  7303. var now = __dependency2__.now;
  7304. __exports__["default"] = function instrument(eventName, promise, child) {
  7305. // instrumentation should not disrupt normal usage.
  7306. try {
  7307. config.trigger(eventName, {
  7308. guid: promise._guidKey + promise._id,
  7309. eventName: eventName,
  7310. detail: promise._detail,
  7311. childGuid: child && promise._guidKey + child._id,
  7312. label: promise._label,
  7313. timeStamp: now(),
  7314. stack: new Error(promise._label).stack
  7315. });
  7316. } catch(error) {
  7317. setTimeout(function(){
  7318. throw error;
  7319. }, 0);
  7320. }
  7321. };
  7322. });
  7323. define("rsvp/map",
  7324. ["./promise","./all","./utils","exports"],
  7325. function(__dependency1__, __dependency2__, __dependency3__, __exports__) {
  7326. "use strict";
  7327. var Promise = __dependency1__["default"];
  7328. var all = __dependency2__["default"];
  7329. var isArray = __dependency3__.isArray;
  7330. var isFunction = __dependency3__.isFunction;
  7331. /**
  7332. `RSVP.map` is similar to JavaScript's native `map` method, except that it
  7333. waits for all promises to become fulfilled before running the `mapFn` on
  7334. each item in given to `promises`. `RSVP.map` returns a promise that will
  7335. become fulfilled with the result of running `mapFn` on the values the promises
  7336. become fulfilled with.
  7337. For example:
  7338. ```javascript
  7339. var promise1 = RSVP.resolve(1);
  7340. var promise2 = RSVP.resolve(2);
  7341. var promise3 = RSVP.resolve(3);
  7342. var promises = [ promise1, promise2, promise3 ];
  7343. var mapFn = function(item){
  7344. return item + 1;
  7345. };
  7346. RSVP.map(promises, mapFn).then(function(result){
  7347. // result is [ 2, 3, 4 ]
  7348. });
  7349. ```
  7350. If any of the `promises` given to `RSVP.map` are rejected, the first promise
  7351. that is rejected will be given as an argument to the returned promise's
  7352. rejection handler. For example:
  7353. ```javascript
  7354. var promise1 = RSVP.resolve(1);
  7355. var promise2 = RSVP.reject(new Error("2"));
  7356. var promise3 = RSVP.reject(new Error("3"));
  7357. var promises = [ promise1, promise2, promise3 ];
  7358. var mapFn = function(item){
  7359. return item + 1;
  7360. };
  7361. RSVP.map(promises, mapFn).then(function(array){
  7362. // Code here never runs because there are rejected promises!
  7363. }, function(reason) {
  7364. // reason.message === "2"
  7365. });
  7366. ```
  7367. `RSVP.map` will also wait if a promise is returned from `mapFn`. For example,
  7368. say you want to get all comments from a set of blog posts, but you need
  7369. the blog posts first becuase they contain a url to those comments.
  7370. ```javscript
  7371. var mapFn = function(blogPost){
  7372. // getComments does some ajax and returns an RSVP.Promise that is fulfilled
  7373. // with some comments data
  7374. return getComments(blogPost.comments_url);
  7375. };
  7376. // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled
  7377. // with some blog post data
  7378. RSVP.map(getBlogPosts(), mapFn).then(function(comments){
  7379. // comments is the result of asking the server for the comments
  7380. // of all blog posts returned from getBlogPosts()
  7381. });
  7382. ```
  7383. @method map
  7384. @for RSVP
  7385. @param {Array} promises
  7386. @param {Function} mapFn function to be called on each fulfilled promise.
  7387. @param {String} label optional string for labeling the promise.
  7388. Useful for tooling.
  7389. @return {Promise} promise that is fulfilled with the result of calling
  7390. `mapFn` on each fulfilled promise or value when they become fulfilled.
  7391. The promise will be rejected if any of the given `promises` become rejected.
  7392. @static
  7393. */
  7394. __exports__["default"] = function map(promises, mapFn, label) {
  7395. return all(promises, label).then(function(results){
  7396. if (!isArray(promises)) {
  7397. throw new TypeError('You must pass an array to map.');
  7398. }
  7399. if (!isFunction(mapFn)){
  7400. throw new TypeError("You must pass a function to map's second argument.");
  7401. }
  7402. var resultLen = results.length,
  7403. mappedResults = [],
  7404. i;
  7405. for (i = 0; i < resultLen; i++){
  7406. mappedResults.push(mapFn(results[i]));
  7407. }
  7408. return all(mappedResults, label);
  7409. });
  7410. };
  7411. });
  7412. define("rsvp/node",
  7413. ["./promise","exports"],
  7414. function(__dependency1__, __exports__) {
  7415. "use strict";
  7416. var Promise = __dependency1__["default"];
  7417. var slice = Array.prototype.slice;
  7418. function makeNodeCallbackFor(resolve, reject) {
  7419. return function (error, value) {
  7420. if (error) {
  7421. reject(error);
  7422. } else if (arguments.length > 2) {
  7423. resolve(slice.call(arguments, 1));
  7424. } else {
  7425. resolve(value);
  7426. }
  7427. };
  7428. }
  7429. /**
  7430. `RSVP.denodeify` takes a "node-style" function and returns a function that
  7431. will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the
  7432. browser when you'd prefer to use promises over using callbacks. For example,
  7433. `denodeify` transforms the following:
  7434. ```javascript
  7435. var fs = require('fs');
  7436. fs.readFile('myfile.txt', function(err, data){
  7437. if (err) return handleError(err);
  7438. handleData(data);
  7439. });
  7440. ```
  7441. into:
  7442. ```javascript
  7443. var fs = require('fs');
  7444. var readFile = RSVP.denodeify(fs.readFile);
  7445. readFile('myfile.txt').then(handleData, handleError);
  7446. ```
  7447. Using `denodeify` makes it easier to compose asynchronous operations instead
  7448. of using callbacks. For example, instead of:
  7449. ```javascript
  7450. var fs = require('fs');
  7451. var log = require('some-async-logger');
  7452. fs.readFile('myfile.txt', function(err, data){
  7453. if (err) return handleError(err);
  7454. fs.writeFile('myfile2.txt', data, function(err){
  7455. if (err) throw err;
  7456. log('success', function(err) {
  7457. if (err) throw err;
  7458. });
  7459. });
  7460. });
  7461. ```
  7462. You can chain the operations together using `then` from the returned promise:
  7463. ```javascript
  7464. var fs = require('fs');
  7465. var denodeify = RSVP.denodeify;
  7466. var readFile = denodeify(fs.readFile);
  7467. var writeFile = denodeify(fs.writeFile);
  7468. var log = denodeify(require('some-async-logger'));
  7469. readFile('myfile.txt').then(function(data){
  7470. return writeFile('myfile2.txt', data);
  7471. }).then(function(){
  7472. return log('SUCCESS');
  7473. }).then(function(){
  7474. // success handler
  7475. }, function(reason){
  7476. // rejection handler
  7477. });
  7478. ```
  7479. @method denodeify
  7480. @for RSVP
  7481. @param {Function} nodeFunc a "node-style" function that takes a callback as
  7482. its last argument. The callback expects an error to be passed as its first
  7483. argument (if an error occurred, otherwise null), and the value from the
  7484. operation as its second argument ("function(err, value){ }").
  7485. @param {Any} binding optional argument for binding the "this" value when
  7486. calling the `nodeFunc` function.
  7487. @return {Function} a function that wraps `nodeFunc` to return an
  7488. `RSVP.Promise`
  7489. @static
  7490. */
  7491. __exports__["default"] = function denodeify(nodeFunc, binding) {
  7492. return function() {
  7493. var nodeArgs = slice.call(arguments), resolve, reject;
  7494. var thisArg = this || binding;
  7495. return new Promise(function(resolve, reject) {
  7496. Promise.all(nodeArgs).then(function(nodeArgs) {
  7497. try {
  7498. nodeArgs.push(makeNodeCallbackFor(resolve, reject));
  7499. nodeFunc.apply(thisArg, nodeArgs);
  7500. } catch(e) {
  7501. reject(e);
  7502. }
  7503. });
  7504. });
  7505. };
  7506. };
  7507. });
  7508. define("rsvp/promise",
  7509. ["./config","./events","./instrument","./utils","./promise/cast","./promise/all","./promise/race","./promise/resolve","./promise/reject","exports"],
  7510. function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) {
  7511. "use strict";
  7512. var config = __dependency1__.config;
  7513. var EventTarget = __dependency2__["default"];
  7514. var instrument = __dependency3__["default"];
  7515. var objectOrFunction = __dependency4__.objectOrFunction;
  7516. var isFunction = __dependency4__.isFunction;
  7517. var now = __dependency4__.now;
  7518. var cast = __dependency5__["default"];
  7519. var all = __dependency6__["default"];
  7520. var race = __dependency7__["default"];
  7521. var Resolve = __dependency8__["default"];
  7522. var Reject = __dependency9__["default"];
  7523. var guidKey = 'rsvp_' + now() + '-';
  7524. var counter = 0;
  7525. function noop() {}
  7526. __exports__["default"] = Promise;
  7527. /**
  7528. Promise objects represent the eventual result of an asynchronous operation. The
  7529. primary way of interacting with a promise is through its `then` method, which
  7530. registers callbacks to receive either a promise’s eventual value or the reason
  7531. why the promise cannot be fulfilled.
  7532. Terminology
  7533. -----------
  7534. - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
  7535. - `thenable` is an object or function that defines a `then` method.
  7536. - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
  7537. - `exception` is a value that is thrown using the throw statement.
  7538. - `reason` is a value that indicates why a promise was rejected.
  7539. - `settled` the final resting state of a promise, fulfilled or rejected.
  7540. A promise can be in one of three states: pending, fulfilled, or rejected.
  7541. Promises that are fulfilled have a fulfillment value and are in the fulfilled
  7542. state. Promises that are rejected have a rejection reason and are in the
  7543. rejected state. A fulfillment value is never a thenable. Similarly, a
  7544. rejection reason is never a thenable.
  7545. Promises can also be said to *resolve* a value. If this value is also a
  7546. promise, then the original promise's settled state will match the value's
  7547. settled state. So a promise that *resolves* a promise that rejects will
  7548. itself reject, and a promise that *resolves* a promise that fulfills will
  7549. itself fulfill.
  7550. Basic Usage:
  7551. ------------
  7552. ```js
  7553. var promise = new Promise(function(resolve, reject) {
  7554. // on success
  7555. resolve(value);
  7556. // on failure
  7557. reject(reason);
  7558. });
  7559. promise.then(function(value) {
  7560. // on fulfillment
  7561. }, function(reason) {
  7562. // on rejection
  7563. });
  7564. ```
  7565. Advanced Usage:
  7566. ---------------
  7567. Promises shine when abstracting away asynchronous interactions such as
  7568. `XMLHttpRequest`s.
  7569. ```js
  7570. function getJSON(url) {
  7571. return new Promise(function(resolve, reject){
  7572. var xhr = new XMLHttpRequest();
  7573. xhr.open('GET', url);
  7574. xhr.onreadystatechange = handler;
  7575. xhr.responseType = 'json';
  7576. xhr.setRequestHeader('Accept', 'application/json');
  7577. xhr.send();
  7578. function handler() {
  7579. if (this.readyState === this.DONE) {
  7580. if (this.status === 200) {
  7581. resolve(this.response);
  7582. } else {
  7583. reject(new Error("getJSON: `" + url + "` failed with status: [" + this.status + "]");
  7584. }
  7585. }
  7586. };
  7587. });
  7588. }
  7589. getJSON('/posts.json').then(function(json) {
  7590. // on fulfillment
  7591. }, function(reason) {
  7592. // on rejection
  7593. });
  7594. ```
  7595. Unlike callbacks, promises are great composable primitives.
  7596. ```js
  7597. Promise.all([
  7598. getJSON('/posts'),
  7599. getJSON('/comments')
  7600. ]).then(function(values){
  7601. values[0] // => postsJSON
  7602. values[1] // => commentsJSON
  7603. return values;
  7604. });
  7605. ```
  7606. @class RSVP.Promise
  7607. @param {function}
  7608. @param {String} label optional string for labeling the promise.
  7609. Useful for tooling.
  7610. @constructor
  7611. */
  7612. function Promise(resolver, label) {
  7613. if (!isFunction(resolver)) {
  7614. throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
  7615. }
  7616. if (!(this instanceof Promise)) {
  7617. throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
  7618. }
  7619. this._id = counter++;
  7620. this._label = label;
  7621. this._subscribers = [];
  7622. if (config.instrument) {
  7623. instrument('created', this);
  7624. }
  7625. if (noop !== resolver) {
  7626. invokeResolver(resolver, this);
  7627. }
  7628. }
  7629. function invokeResolver(resolver, promise) {
  7630. function resolvePromise(value) {
  7631. resolve(promise, value);
  7632. }
  7633. function rejectPromise(reason) {
  7634. reject(promise, reason);
  7635. }
  7636. try {
  7637. resolver(resolvePromise, rejectPromise);
  7638. } catch(e) {
  7639. rejectPromise(e);
  7640. }
  7641. }
  7642. Promise.cast = cast;
  7643. Promise.all = all;
  7644. Promise.race = race;
  7645. Promise.resolve = Resolve;
  7646. Promise.reject = Reject;
  7647. var PENDING = void 0;
  7648. var SEALED = 0;
  7649. var FULFILLED = 1;
  7650. var REJECTED = 2;
  7651. function subscribe(parent, child, onFulfillment, onRejection) {
  7652. var subscribers = parent._subscribers;
  7653. var length = subscribers.length;
  7654. subscribers[length] = child;
  7655. subscribers[length + FULFILLED] = onFulfillment;
  7656. subscribers[length + REJECTED] = onRejection;
  7657. }
  7658. function publish(promise, settled) {
  7659. var child, callback, subscribers = promise._subscribers, detail = promise._detail;
  7660. if (config.instrument) {
  7661. instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise);
  7662. }
  7663. for (var i = 0; i < subscribers.length; i += 3) {
  7664. child = subscribers[i];
  7665. callback = subscribers[i + settled];
  7666. invokeCallback(settled, child, callback, detail);
  7667. }
  7668. promise._subscribers = null;
  7669. }
  7670. Promise.prototype = {
  7671. constructor: Promise,
  7672. _id: undefined,
  7673. _guidKey: guidKey,
  7674. _label: undefined,
  7675. _state: undefined,
  7676. _detail: undefined,
  7677. _subscribers: undefined,
  7678. _onerror: function (reason) {
  7679. config.trigger('error', reason);
  7680. },
  7681. /**
  7682. The primary way of interacting with a promise is through its `then` method,
  7683. which registers callbacks to receive either a promise's eventual value or the
  7684. reason why the promise cannot be fulfilled.
  7685. ```js
  7686. findUser().then(function(user){
  7687. // user is available
  7688. }, function(reason){
  7689. // user is unavailable, and you are given the reason why
  7690. });
  7691. ```
  7692. Chaining
  7693. --------
  7694. The return value of `then` is itself a promise. This second, "downstream"
  7695. promise is resolved with the return value of the first promise's fulfillment
  7696. or rejection handler, or rejected if the handler throws an exception.
  7697. ```js
  7698. findUser().then(function (user) {
  7699. return user.name;
  7700. }, function (reason) {
  7701. return "default name";
  7702. }).then(function (userName) {
  7703. // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
  7704. // will be `"default name"`
  7705. });
  7706. findUser().then(function (user) {
  7707. throw new Error("Found user, but still unhappy");
  7708. }, function (reason) {
  7709. throw new Error("`findUser` rejected and we're unhappy");
  7710. }).then(function (value) {
  7711. // never reached
  7712. }, function (reason) {
  7713. // if `findUser` fulfilled, `reason` will be "Found user, but still unhappy".
  7714. // If `findUser` rejected, `reason` will be "`findUser` rejected and we're unhappy".
  7715. });
  7716. ```
  7717. If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
  7718. ```js
  7719. findUser().then(function (user) {
  7720. throw new PedagogicalException("Upstream error");
  7721. }).then(function (value) {
  7722. // never reached
  7723. }).then(function (value) {
  7724. // never reached
  7725. }, function (reason) {
  7726. // The `PedgagocialException` is propagated all the way down to here
  7727. });
  7728. ```
  7729. Assimilation
  7730. ------------
  7731. Sometimes the value you want to propagate to a downstream promise can only be
  7732. retrieved asynchronously. This can be achieved by returning a promise in the
  7733. fulfillment or rejection handler. The downstream promise will then be pending
  7734. until the returned promise is settled. This is called *assimilation*.
  7735. ```js
  7736. findUser().then(function (user) {
  7737. return findCommentsByAuthor(user);
  7738. }).then(function (comments) {
  7739. // The user's comments are now available
  7740. });
  7741. ```
  7742. If the assimliated promise rejects, then the downstream promise will also reject.
  7743. ```js
  7744. findUser().then(function (user) {
  7745. return findCommentsByAuthor(user);
  7746. }).then(function (comments) {
  7747. // If `findCommentsByAuthor` fulfills, we'll have the value here
  7748. }, function (reason) {
  7749. // If `findCommentsByAuthor` rejects, we'll have the reason here
  7750. });
  7751. ```
  7752. Simple Example
  7753. --------------
  7754. Synchronous Example
  7755. ```javascript
  7756. var result;
  7757. try {
  7758. result = findResult();
  7759. // success
  7760. } catch(reason) {
  7761. // failure
  7762. }
  7763. ```
  7764. Errback Example
  7765. ```js
  7766. findResult(function(result, err){
  7767. if (err) {
  7768. // failure
  7769. } else {
  7770. // success
  7771. }
  7772. });
  7773. ```
  7774. Promise Example;
  7775. ```javascript
  7776. findResult().then(function(result){
  7777. // success
  7778. }, function(reason){
  7779. // failure
  7780. });
  7781. ```
  7782. Advanced Example
  7783. --------------
  7784. Synchronous Example
  7785. ```javascript
  7786. var author, books;
  7787. try {
  7788. author = findAuthor();
  7789. books = findBooksByAuthor(author);
  7790. // success
  7791. } catch(reason) {
  7792. // failure
  7793. }
  7794. ```
  7795. Errback Example
  7796. ```js
  7797. function foundBooks(books) {
  7798. }
  7799. function failure(reason) {
  7800. }
  7801. findAuthor(function(author, err){
  7802. if (err) {
  7803. failure(err);
  7804. // failure
  7805. } else {
  7806. try {
  7807. findBoooksByAuthor(author, function(books, err) {
  7808. if (err) {
  7809. failure(err);
  7810. } else {
  7811. try {
  7812. foundBooks(books);
  7813. } catch(reason) {
  7814. failure(reason);
  7815. }
  7816. }
  7817. });
  7818. } catch(error) {
  7819. failure(err);
  7820. }
  7821. // success
  7822. }
  7823. });
  7824. ```
  7825. Promise Example;
  7826. ```javascript
  7827. findAuthor().
  7828. then(findBooksByAuthor).
  7829. then(function(books){
  7830. // found books
  7831. }).catch(function(reason){
  7832. // something went wrong
  7833. });
  7834. ```
  7835. @method then
  7836. @param {Function} onFulfilled
  7837. @param {Function} onRejected
  7838. @param {String} label optional string for labeling the promise.
  7839. Useful for tooling.
  7840. @return {Promise}
  7841. */
  7842. then: function(onFulfillment, onRejection, label) {
  7843. var promise = this;
  7844. this._onerror = null;
  7845. var thenPromise = new this.constructor(noop, label);
  7846. if (this._state) {
  7847. var callbacks = arguments;
  7848. config.async(function invokePromiseCallback() {
  7849. invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail);
  7850. });
  7851. } else {
  7852. subscribe(this, thenPromise, onFulfillment, onRejection);
  7853. }
  7854. if (config.instrument) {
  7855. instrument('chained', promise, thenPromise);
  7856. }
  7857. return thenPromise;
  7858. },
  7859. /**
  7860. `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
  7861. as the catch block of a try/catch statement.
  7862. ```js
  7863. function findAuthor(){
  7864. throw new Error("couldn't find that author");
  7865. }
  7866. // synchronous
  7867. try {
  7868. findAuthor();
  7869. } catch(reason) {
  7870. // something went wrong
  7871. }
  7872. // async with promises
  7873. findAuthor().catch(function(reason){
  7874. // something went wrong
  7875. });
  7876. ```
  7877. @method catch
  7878. @param {Function} onRejection
  7879. @param {String} label optional string for labeling the promise.
  7880. Useful for tooling.
  7881. @return {Promise}
  7882. */
  7883. 'catch': function(onRejection, label) {
  7884. return this.then(null, onRejection, label);
  7885. },
  7886. /**
  7887. `finally` will be invoked regardless of the promise's fate just as native
  7888. try/catch/finally behaves
  7889. Synchronous example:
  7890. ```js
  7891. findAuthor() {
  7892. if (Math.random() > 0.5) {
  7893. throw new Error();
  7894. }
  7895. return new Author();
  7896. }
  7897. try {
  7898. return findAuthor(); // succeed or fail
  7899. } catch(error) {
  7900. return findOtherAuther();
  7901. } finally {
  7902. // always runs
  7903. // doesn't affect the return value
  7904. }
  7905. ```
  7906. Asynchronous example:
  7907. ```js
  7908. findAuthor().catch(function(reason){
  7909. return findOtherAuther();
  7910. }).finally(function(){
  7911. // author was either found, or not
  7912. });
  7913. ```
  7914. @method finally
  7915. @param {Function} callback
  7916. @param {String} label optional string for labeling the promise.
  7917. Useful for tooling.
  7918. @return {Promise}
  7919. */
  7920. 'finally': function(callback, label) {
  7921. var constructor = this.constructor;
  7922. return this.then(function(value) {
  7923. return constructor.cast(callback()).then(function(){
  7924. return value;
  7925. });
  7926. }, function(reason) {
  7927. return constructor.cast(callback()).then(function(){
  7928. throw reason;
  7929. });
  7930. }, label);
  7931. }
  7932. };
  7933. function invokeCallback(settled, promise, callback, detail) {
  7934. var hasCallback = isFunction(callback),
  7935. value, error, succeeded, failed;
  7936. if (hasCallback) {
  7937. try {
  7938. value = callback(detail);
  7939. succeeded = true;
  7940. } catch(e) {
  7941. failed = true;
  7942. error = e;
  7943. }
  7944. } else {
  7945. value = detail;
  7946. succeeded = true;
  7947. }
  7948. if (handleThenable(promise, value)) {
  7949. return;
  7950. } else if (hasCallback && succeeded) {
  7951. resolve(promise, value);
  7952. } else if (failed) {
  7953. reject(promise, error);
  7954. } else if (settled === FULFILLED) {
  7955. resolve(promise, value);
  7956. } else if (settled === REJECTED) {
  7957. reject(promise, value);
  7958. }
  7959. }
  7960. function handleThenable(promise, value) {
  7961. var then = null,
  7962. resolved;
  7963. try {
  7964. if (promise === value) {
  7965. throw new TypeError("A promises callback cannot return that same promise.");
  7966. }
  7967. if (objectOrFunction(value)) {
  7968. then = value.then;
  7969. if (isFunction(then)) {
  7970. then.call(value, function(val) {
  7971. if (resolved) { return true; }
  7972. resolved = true;
  7973. if (value !== val) {
  7974. resolve(promise, val);
  7975. } else {
  7976. fulfill(promise, val);
  7977. }
  7978. }, function(val) {
  7979. if (resolved) { return true; }
  7980. resolved = true;
  7981. reject(promise, val);
  7982. }, 'derived from: ' + (promise._label || ' unknown promise'));
  7983. return true;
  7984. }
  7985. }
  7986. } catch (error) {
  7987. if (resolved) { return true; }
  7988. reject(promise, error);
  7989. return true;
  7990. }
  7991. return false;
  7992. }
  7993. function resolve(promise, value) {
  7994. if (promise === value) {
  7995. fulfill(promise, value);
  7996. } else if (!handleThenable(promise, value)) {
  7997. fulfill(promise, value);
  7998. }
  7999. }
  8000. function fulfill(promise, value) {
  8001. if (promise._state !== PENDING) { return; }
  8002. promise._state = SEALED;
  8003. promise._detail = value;
  8004. config.async(publishFulfillment, promise);
  8005. }
  8006. function reject(promise, reason) {
  8007. if (promise._state !== PENDING) { return; }
  8008. promise._state = SEALED;
  8009. promise._detail = reason;
  8010. config.async(publishRejection, promise);
  8011. }
  8012. function publishFulfillment(promise) {
  8013. publish(promise, promise._state = FULFILLED);
  8014. }
  8015. function publishRejection(promise) {
  8016. if (promise._onerror) {
  8017. promise._onerror(promise._detail);
  8018. }
  8019. publish(promise, promise._state = REJECTED);
  8020. }
  8021. });
  8022. define("rsvp/promise/all",
  8023. ["../utils","exports"],
  8024. function(__dependency1__, __exports__) {
  8025. "use strict";
  8026. var isArray = __dependency1__.isArray;
  8027. var isNonThenable = __dependency1__.isNonThenable;
  8028. /**
  8029. `RSVP.Promise.all` accepts an array of promises, and returns a new promise which
  8030. is fulfilled with an array of fulfillment values for the passed promises, or
  8031. rejected with the reason of the first passed promise to be rejected. It casts all
  8032. elements of the passed iterable to promises as it runs this algorithm.
  8033. Example:
  8034. ```javascript
  8035. var promise1 = RSVP.resolve(1);
  8036. var promise2 = RSVP.resolve(2);
  8037. var promise3 = RSVP.resolve(3);
  8038. var promises = [ promise1, promise2, promise3 ];
  8039. RSVP.Promise.all(promises).then(function(array){
  8040. // The array here would be [ 1, 2, 3 ];
  8041. });
  8042. ```
  8043. If any of the `promises` given to `RSVP.all` are rejected, the first promise
  8044. that is rejected will be given as an argument to the returned promises's
  8045. rejection handler. For example:
  8046. Example:
  8047. ```javascript
  8048. var promise1 = RSVP.resolve(1);
  8049. var promise2 = RSVP.reject(new Error("2"));
  8050. var promise3 = RSVP.reject(new Error("3"));
  8051. var promises = [ promise1, promise2, promise3 ];
  8052. RSVP.Promise.all(promises).then(function(array){
  8053. // Code here never runs because there are rejected promises!
  8054. }, function(error) {
  8055. // error.message === "2"
  8056. });
  8057. ```
  8058. @method all
  8059. @for Ember.RSVP.Promise
  8060. @param {Array} entries array of promises
  8061. @param {String} label optional string for labeling the promise.
  8062. Useful for tooling.
  8063. @return {Promise} promise that is fulfilled when all `promises` have been
  8064. fulfilled, or rejected if any of them become rejected.
  8065. @static
  8066. */
  8067. __exports__["default"] = function all(entries, label) {
  8068. /*jshint validthis:true */
  8069. var Constructor = this;
  8070. return new Constructor(function(resolve, reject) {
  8071. if (!isArray(entries)) {
  8072. throw new TypeError('You must pass an array to all.');
  8073. }
  8074. var remaining = entries.length;
  8075. var results = new Array(remaining);
  8076. var entry, pending = true;
  8077. if (remaining === 0) {
  8078. resolve(results);
  8079. return;
  8080. }
  8081. function fulfillmentAt(index) {
  8082. return function(value) {
  8083. results[index] = value;
  8084. if (--remaining === 0) {
  8085. resolve(results);
  8086. }
  8087. };
  8088. }
  8089. function onRejection(reason) {
  8090. remaining = 0;
  8091. reject(reason);
  8092. }
  8093. for (var index = 0; index < entries.length; index++) {
  8094. entry = entries[index];
  8095. if (isNonThenable(entry)) {
  8096. results[index] = entry;
  8097. if (--remaining === 0) {
  8098. resolve(results);
  8099. }
  8100. } else {
  8101. Constructor.cast(entry).then(fulfillmentAt(index), onRejection);
  8102. }
  8103. }
  8104. }, label);
  8105. };
  8106. });
  8107. define("rsvp/promise/cast",
  8108. ["exports"],
  8109. function(__exports__) {
  8110. "use strict";
  8111. /**
  8112. `RSVP.Promise.cast` coerces its argument to a promise, or returns the
  8113. argument if it is already a promise which shares a constructor with the caster.
  8114. Example:
  8115. ```javascript
  8116. var promise = RSVP.Promise.resolve(1);
  8117. var casted = RSVP.Promise.cast(promise);
  8118. console.log(promise === casted); // true
  8119. ```
  8120. In the case of a promise whose constructor does not match, it is assimilated.
  8121. The resulting promise will fulfill or reject based on the outcome of the
  8122. promise being casted.
  8123. Example:
  8124. ```javascript
  8125. var thennable = $.getJSON('/api/foo');
  8126. var casted = RSVP.Promise.cast(thennable);
  8127. console.log(thennable === casted); // false
  8128. console.log(casted instanceof RSVP.Promise) // true
  8129. casted.then(function(data) {
  8130. // data is the value getJSON fulfills with
  8131. });
  8132. ```
  8133. In the case of a non-promise, a promise which will fulfill with that value is
  8134. returned.
  8135. Example:
  8136. ```javascript
  8137. var value = 1; // could be a number, boolean, string, undefined...
  8138. var casted = RSVP.Promise.cast(value);
  8139. console.log(value === casted); // false
  8140. console.log(casted instanceof RSVP.Promise) // true
  8141. casted.then(function(val) {
  8142. val === value // => true
  8143. });
  8144. ```
  8145. `RSVP.Promise.cast` is similar to `RSVP.Promise.resolve`, but `RSVP.Promise.cast` differs in the
  8146. following ways:
  8147. * `RSVP.Promise.cast` serves as a memory-efficient way of getting a promise, when you
  8148. have something that could either be a promise or a value. RSVP.resolve
  8149. will have the same effect but will create a new promise wrapper if the
  8150. argument is a promise.
  8151. * `RSVP.Promise.cast` is a way of casting incoming thenables or promise subclasses to
  8152. promises of the exact class specified, so that the resulting object's `then` is
  8153. ensured to have the behavior of the constructor you are calling cast on (i.e., RSVP.Promise).
  8154. @method cast
  8155. @param {Object} object to be casted
  8156. @param {String} label optional string for labeling the promise.
  8157. Useful for tooling.
  8158. @return {Promise} promise
  8159. @static
  8160. */
  8161. __exports__["default"] = function cast(object, label) {
  8162. /*jshint validthis:true */
  8163. var Constructor = this;
  8164. if (object && typeof object === 'object' && object.constructor === Constructor) {
  8165. return object;
  8166. }
  8167. return new Constructor(function(resolve) {
  8168. resolve(object);
  8169. }, label);
  8170. };
  8171. });
  8172. define("rsvp/promise/race",
  8173. ["../utils","exports"],
  8174. function(__dependency1__, __exports__) {
  8175. "use strict";
  8176. /* global toString */
  8177. var isArray = __dependency1__.isArray;
  8178. var isFunction = __dependency1__.isFunction;
  8179. var isNonThenable = __dependency1__.isNonThenable;
  8180. /**
  8181. `RSVP.Promise.race` returns a new promise which is settled in the same way as the
  8182. first passed promise to settle.
  8183. Example:
  8184. ```javascript
  8185. var promise1 = new RSVP.Promise(function(resolve, reject){
  8186. setTimeout(function(){
  8187. resolve("promise 1");
  8188. }, 200);
  8189. });
  8190. var promise2 = new RSVP.Promise(function(resolve, reject){
  8191. setTimeout(function(){
  8192. resolve("promise 2");
  8193. }, 100);
  8194. });
  8195. RSVP.Promise.race([promise1, promise2]).then(function(result){
  8196. // result === "promise 2" because it was resolved before promise1
  8197. // was resolved.
  8198. });
  8199. ```
  8200. `RSVP.Promise.race` is deterministic in that only the state of the first
  8201. settled promise matters. For example, even if other promises given to the
  8202. `promises` array argument are resolved, but the first settled promise has
  8203. become rejected before the other promises became fulfilled, the returned
  8204. promise will become rejected:
  8205. ```javascript
  8206. var promise1 = new RSVP.Promise(function(resolve, reject){
  8207. setTimeout(function(){
  8208. resolve("promise 1");
  8209. }, 200);
  8210. });
  8211. var promise2 = new RSVP.Promise(function(resolve, reject){
  8212. setTimeout(function(){
  8213. reject(new Error("promise 2"));
  8214. }, 100);
  8215. });
  8216. RSVP.Promise.race([promise1, promise2]).then(function(result){
  8217. // Code here never runs
  8218. }, function(reason){
  8219. // reason.message === "promise2" because promise 2 became rejected before
  8220. // promise 1 became fulfilled
  8221. });
  8222. ```
  8223. An example real-world use case is implementing timeouts:
  8224. ```javascript
  8225. RSVP.Promise.race([ajax('foo.json'), timeout(5000)])
  8226. ```
  8227. @method race
  8228. @param {Array} promises array of promises to observe
  8229. @param {String} label optional string for describing the promise returned.
  8230. Useful for tooling.
  8231. @return {Promise} a promise which settles in the same way as the first passed
  8232. promise to settle.
  8233. @static
  8234. */
  8235. __exports__["default"] = function race(entries, label) {
  8236. /*jshint validthis:true */
  8237. var Constructor = this, entry;
  8238. return new Constructor(function(resolve, reject) {
  8239. if (!isArray(entries)) {
  8240. throw new TypeError('You must pass an array to race.');
  8241. }
  8242. var pending = true;
  8243. function onFulfillment(value) { if (pending) { pending = false; resolve(value); } }
  8244. function onRejection(reason) { if (pending) { pending = false; reject(reason); } }
  8245. for (var i = 0; i < entries.length; i++) {
  8246. entry = entries[i];
  8247. if (isNonThenable(entry)) {
  8248. pending = false;
  8249. resolve(entry);
  8250. return;
  8251. } else {
  8252. Constructor.cast(entry).then(onFulfillment, onRejection);
  8253. }
  8254. }
  8255. }, label);
  8256. };
  8257. });
  8258. define("rsvp/promise/reject",
  8259. ["exports"],
  8260. function(__exports__) {
  8261. "use strict";
  8262. /**
  8263. `RSVP.Promise.reject` returns a promise rejected with the passed `reason`.
  8264. It is shorthand for the following:
  8265. ```javascript
  8266. var promise = new RSVP.Promise(function(resolve, reject){
  8267. reject(new Error('WHOOPS'));
  8268. });
  8269. promise.then(function(value){
  8270. // Code here doesn't run because the promise is rejected!
  8271. }, function(reason){
  8272. // reason.message === 'WHOOPS'
  8273. });
  8274. ```
  8275. Instead of writing the above, your code now simply becomes the following:
  8276. ```javascript
  8277. var promise = RSVP.Promise.reject(new Error('WHOOPS'));
  8278. promise.then(function(value){
  8279. // Code here doesn't run because the promise is rejected!
  8280. }, function(reason){
  8281. // reason.message === 'WHOOPS'
  8282. });
  8283. ```
  8284. @method reject
  8285. @param {Any} reason value that the returned promise will be rejected with.
  8286. @param {String} label optional string for identifying the returned promise.
  8287. Useful for tooling.
  8288. @return {Promise} a promise rejected with the given `reason`.
  8289. @static
  8290. */
  8291. __exports__["default"] = function reject(reason, label) {
  8292. /*jshint validthis:true */
  8293. var Constructor = this;
  8294. return new Constructor(function (resolve, reject) {
  8295. reject(reason);
  8296. }, label);
  8297. };
  8298. });
  8299. define("rsvp/promise/resolve",
  8300. ["exports"],
  8301. function(__exports__) {
  8302. "use strict";
  8303. /**
  8304. `RSVP.Promise.resolve` returns a promise that will become resolved with the
  8305. passed `value`. It is shorthand for the following:
  8306. ```javascript
  8307. var promise = new RSVP.Promise(function(resolve, reject){
  8308. resolve(1);
  8309. });
  8310. promise.then(function(value){
  8311. // value === 1
  8312. });
  8313. ```
  8314. Instead of writing the above, your code now simply becomes the following:
  8315. ```javascript
  8316. var promise = RSVP.Promise.resolve(1);
  8317. promise.then(function(value){
  8318. // value === 1
  8319. });
  8320. ```
  8321. @method resolve
  8322. @param {Any} value value that the returned promise will be resolved with
  8323. @param {String} label optional string for identifying the returned promise.
  8324. Useful for tooling.
  8325. @return {Promise} a promise that will become fulfilled with the given
  8326. `value`
  8327. @static
  8328. */
  8329. __exports__["default"] = function resolve(value, label) {
  8330. /*jshint validthis:true */
  8331. var Constructor = this;
  8332. return new Constructor(function(resolve, reject) {
  8333. resolve(value);
  8334. }, label);
  8335. };
  8336. });
  8337. define("rsvp/race",
  8338. ["./promise","exports"],
  8339. function(__dependency1__, __exports__) {
  8340. "use strict";
  8341. var Promise = __dependency1__["default"];
  8342. /**
  8343. This is a convenient alias for `RSVP.Promise.race`.
  8344. @method race
  8345. @param {Array} array Array of promises.
  8346. @param {String} label An optional label. This is useful
  8347. for tooling.
  8348. @static
  8349. */
  8350. __exports__["default"] = function race(array, label) {
  8351. return Promise.race(array, label);
  8352. };
  8353. });
  8354. define("rsvp/reject",
  8355. ["./promise","exports"],
  8356. function(__dependency1__, __exports__) {
  8357. "use strict";
  8358. var Promise = __dependency1__["default"];
  8359. /**
  8360. This is a convenient alias for `RSVP.Promise.reject`.
  8361. @method reject
  8362. @for RSVP
  8363. @param {Any} reason value that the returned promise will be rejected with.
  8364. @param {String} label optional string for identifying the returned promise.
  8365. Useful for tooling.
  8366. @return {Promise} a promise rejected with the given `reason`.
  8367. @static
  8368. */
  8369. __exports__["default"] = function reject(reason, label) {
  8370. return Promise.reject(reason, label);
  8371. };
  8372. });
  8373. define("rsvp/resolve",
  8374. ["./promise","exports"],
  8375. function(__dependency1__, __exports__) {
  8376. "use strict";
  8377. var Promise = __dependency1__["default"];
  8378. /**
  8379. This is a convenient alias for `RSVP.Promise.resolve`.
  8380. @method resolve
  8381. @for RSVP
  8382. @param {Any} value value that the returned promise will be resolved with
  8383. @param {String} label optional string for identifying the returned promise.
  8384. Useful for tooling.
  8385. @return {Promise} a promise that will become fulfilled with the given
  8386. `value`
  8387. @static
  8388. */
  8389. __exports__["default"] = function resolve(value, label) {
  8390. return Promise.resolve(value, label);
  8391. };
  8392. });
  8393. define("rsvp/rethrow",
  8394. ["exports"],
  8395. function(__exports__) {
  8396. "use strict";
  8397. /**
  8398. `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event
  8399. loop in order to aid debugging.
  8400. Promises A+ specifies that any exceptions that occur with a promise must be
  8401. caught by the promises implementation and bubbled to the last handler. For
  8402. this reason, it is recommended that you always specify a second rejection
  8403. handler function to `then`. However, `RSVP.rethrow` will throw the exception
  8404. outside of the promise, so it bubbles up to your console if in the browser,
  8405. or domain/cause uncaught exception in Node. `rethrow` will also throw the
  8406. error again so the error can be handled by the promise per the spec.
  8407. ```javascript
  8408. function throws(){
  8409. throw new Error('Whoops!');
  8410. }
  8411. var promise = new RSVP.Promise(function(resolve, reject){
  8412. throws();
  8413. });
  8414. promise.catch(RSVP.rethrow).then(function(){
  8415. // Code here doesn't run because the promise became rejected due to an
  8416. // error!
  8417. }, function (err){
  8418. // handle the error here
  8419. });
  8420. ```
  8421. The 'Whoops' error will be thrown on the next turn of the event loop
  8422. and you can watch for it in your console. You can also handle it using a
  8423. rejection handler given to `.then` or `.catch` on the returned promise.
  8424. @method rethrow
  8425. @for RSVP
  8426. @param {Error} reason reason the promise became rejected.
  8427. @throws Error
  8428. @static
  8429. */
  8430. __exports__["default"] = function rethrow(reason) {
  8431. setTimeout(function() {
  8432. throw reason;
  8433. });
  8434. throw reason;
  8435. };
  8436. });
  8437. define("rsvp/utils",
  8438. ["exports"],
  8439. function(__exports__) {
  8440. "use strict";
  8441. function objectOrFunction(x) {
  8442. return typeof x === "function" || (typeof x === "object" && x !== null);
  8443. }
  8444. __exports__.objectOrFunction = objectOrFunction;function isFunction(x) {
  8445. return typeof x === "function";
  8446. }
  8447. __exports__.isFunction = isFunction;function isNonThenable(x) {
  8448. return !objectOrFunction(x);
  8449. }
  8450. __exports__.isNonThenable = isNonThenable;function isArray(x) {
  8451. return Object.prototype.toString.call(x) === "[object Array]";
  8452. }
  8453. __exports__.isArray = isArray;// Date.now is not available in browsers < IE9
  8454. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility
  8455. var now = Date.now || function() { return new Date().getTime(); };
  8456. __exports__.now = now;
  8457. var keysOf = Object.keys || function(object) {
  8458. var result = [];
  8459. for (var prop in object) {
  8460. result.push(prop);
  8461. }
  8462. return result;
  8463. };
  8464. __exports__.keysOf = keysOf;
  8465. });
  8466. define("rsvp",
  8467. ["./rsvp/promise","./rsvp/events","./rsvp/node","./rsvp/all","./rsvp/all_settled","./rsvp/race","./rsvp/hash","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/map","./rsvp/resolve","./rsvp/reject","./rsvp/filter","exports"],
  8468. function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __exports__) {
  8469. "use strict";
  8470. var Promise = __dependency1__["default"];
  8471. var EventTarget = __dependency2__["default"];
  8472. var denodeify = __dependency3__["default"];
  8473. var all = __dependency4__["default"];
  8474. var allSettled = __dependency5__["default"];
  8475. var race = __dependency6__["default"];
  8476. var hash = __dependency7__["default"];
  8477. var rethrow = __dependency8__["default"];
  8478. var defer = __dependency9__["default"];
  8479. var config = __dependency10__.config;
  8480. var configure = __dependency10__.configure;
  8481. var map = __dependency11__["default"];
  8482. var resolve = __dependency12__["default"];
  8483. var reject = __dependency13__["default"];
  8484. var filter = __dependency14__["default"];
  8485. function async(callback, arg) {
  8486. config.async(callback, arg);
  8487. }
  8488. function on() {
  8489. config.on.apply(config, arguments);
  8490. }
  8491. function off() {
  8492. config.off.apply(config, arguments);
  8493. }
  8494. // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__`
  8495. if (typeof window !== 'undefined' && typeof window.__PROMISE_INSTRUMENTATION__ === 'object') {
  8496. var callbacks = window.__PROMISE_INSTRUMENTATION__;
  8497. configure('instrument', true);
  8498. for (var eventName in callbacks) {
  8499. if (callbacks.hasOwnProperty(eventName)) {
  8500. on(eventName, callbacks[eventName]);
  8501. }
  8502. }
  8503. }
  8504. __exports__.Promise = Promise;
  8505. __exports__.EventTarget = EventTarget;
  8506. __exports__.all = all;
  8507. __exports__.allSettled = allSettled;
  8508. __exports__.race = race;
  8509. __exports__.hash = hash;
  8510. __exports__.rethrow = rethrow;
  8511. __exports__.defer = defer;
  8512. __exports__.denodeify = denodeify;
  8513. __exports__.configure = configure;
  8514. __exports__.on = on;
  8515. __exports__.off = off;
  8516. __exports__.resolve = resolve;
  8517. __exports__.reject = reject;
  8518. __exports__.async = async;
  8519. __exports__.map = map;
  8520. __exports__.filter = filter;
  8521. });
  8522. })();
  8523. (function() {
  8524. /**
  8525. Public api for the container is still in flux.
  8526. The public api, specified on the application namespace should be considered the stable api.
  8527. // @module container
  8528. @private
  8529. */
  8530. /*
  8531. Flag to enable/disable model factory injections (disabled by default)
  8532. If model factory injections are enabled, models should not be
  8533. accessed globally (only through `container.lookupFactory('model:modelName'))`);
  8534. */
  8535. Ember.MODEL_FACTORY_INJECTIONS = false || !!Ember.ENV.MODEL_FACTORY_INJECTIONS;
  8536. define("container",
  8537. [],
  8538. function() {
  8539. "use strict";
  8540. // A safe and simple inheriting object.
  8541. function InheritingDict(parent) {
  8542. this.parent = parent;
  8543. this.dict = {};
  8544. }
  8545. InheritingDict.prototype = {
  8546. /**
  8547. @property parent
  8548. @type InheritingDict
  8549. @default null
  8550. */
  8551. parent: null,
  8552. /**
  8553. Object used to store the current nodes data.
  8554. @property dict
  8555. @type Object
  8556. @default Object
  8557. */
  8558. dict: null,
  8559. /**
  8560. Retrieve the value given a key, if the value is present at the current
  8561. level use it, otherwise walk up the parent hierarchy and try again. If
  8562. no matching key is found, return undefined.
  8563. @method get
  8564. @param {String} key
  8565. @return {any}
  8566. */
  8567. get: function(key) {
  8568. var dict = this.dict;
  8569. if (dict.hasOwnProperty(key)) {
  8570. return dict[key];
  8571. }
  8572. if (this.parent) {
  8573. return this.parent.get(key);
  8574. }
  8575. },
  8576. /**
  8577. Set the given value for the given key, at the current level.
  8578. @method set
  8579. @param {String} key
  8580. @param {Any} value
  8581. */
  8582. set: function(key, value) {
  8583. this.dict[key] = value;
  8584. },
  8585. /**
  8586. Delete the given key
  8587. @method remove
  8588. @param {String} key
  8589. */
  8590. remove: function(key) {
  8591. delete this.dict[key];
  8592. },
  8593. /**
  8594. Check for the existence of given a key, if the key is present at the current
  8595. level return true, otherwise walk up the parent hierarchy and try again. If
  8596. no matching key is found, return false.
  8597. @method has
  8598. @param {String} key
  8599. @return {Boolean}
  8600. */
  8601. has: function(key) {
  8602. var dict = this.dict;
  8603. if (dict.hasOwnProperty(key)) {
  8604. return true;
  8605. }
  8606. if (this.parent) {
  8607. return this.parent.has(key);
  8608. }
  8609. return false;
  8610. },
  8611. /**
  8612. Iterate and invoke a callback for each local key-value pair.
  8613. @method eachLocal
  8614. @param {Function} callback
  8615. @param {Object} binding
  8616. */
  8617. eachLocal: function(callback, binding) {
  8618. var dict = this.dict;
  8619. for (var prop in dict) {
  8620. if (dict.hasOwnProperty(prop)) {
  8621. callback.call(binding, prop, dict[prop]);
  8622. }
  8623. }
  8624. }
  8625. };
  8626. // A lightweight container that helps to assemble and decouple components.
  8627. // Public api for the container is still in flux.
  8628. // The public api, specified on the application namespace should be considered the stable api.
  8629. function Container(parent) {
  8630. this.parent = parent;
  8631. this.children = [];
  8632. this.resolver = parent && parent.resolver || function() {};
  8633. this.registry = new InheritingDict(parent && parent.registry);
  8634. this.cache = new InheritingDict(parent && parent.cache);
  8635. this.factoryCache = new InheritingDict(parent && parent.factoryCache);
  8636. this.resolveCache = new InheritingDict(parent && parent.resolveCache);
  8637. this.typeInjections = new InheritingDict(parent && parent.typeInjections);
  8638. this.injections = {};
  8639. this.factoryTypeInjections = new InheritingDict(parent && parent.factoryTypeInjections);
  8640. this.factoryInjections = {};
  8641. this._options = new InheritingDict(parent && parent._options);
  8642. this._typeOptions = new InheritingDict(parent && parent._typeOptions);
  8643. }
  8644. Container.prototype = {
  8645. /**
  8646. @property parent
  8647. @type Container
  8648. @default null
  8649. */
  8650. parent: null,
  8651. /**
  8652. @property children
  8653. @type Array
  8654. @default []
  8655. */
  8656. children: null,
  8657. /**
  8658. @property resolver
  8659. @type function
  8660. */
  8661. resolver: null,
  8662. /**
  8663. @property registry
  8664. @type InheritingDict
  8665. */
  8666. registry: null,
  8667. /**
  8668. @property cache
  8669. @type InheritingDict
  8670. */
  8671. cache: null,
  8672. /**
  8673. @property typeInjections
  8674. @type InheritingDict
  8675. */
  8676. typeInjections: null,
  8677. /**
  8678. @property injections
  8679. @type Object
  8680. @default {}
  8681. */
  8682. injections: null,
  8683. /**
  8684. @private
  8685. @property _options
  8686. @type InheritingDict
  8687. @default null
  8688. */
  8689. _options: null,
  8690. /**
  8691. @private
  8692. @property _typeOptions
  8693. @type InheritingDict
  8694. */
  8695. _typeOptions: null,
  8696. /**
  8697. Returns a new child of the current container. These children are configured
  8698. to correctly inherit from the current container.
  8699. @method child
  8700. @return {Container}
  8701. */
  8702. child: function() {
  8703. var container = new Container(this);
  8704. this.children.push(container);
  8705. return container;
  8706. },
  8707. /**
  8708. Sets a key-value pair on the current container. If a parent container,
  8709. has the same key, once set on a child, the parent and child will diverge
  8710. as expected.
  8711. @method set
  8712. @param {Object} object
  8713. @param {String} key
  8714. @param {any} value
  8715. */
  8716. set: function(object, key, value) {
  8717. object[key] = value;
  8718. },
  8719. /**
  8720. Registers a factory for later injection.
  8721. Example:
  8722. ```javascript
  8723. var container = new Container();
  8724. container.register('model:user', Person, {singleton: false });
  8725. container.register('fruit:favorite', Orange);
  8726. container.register('communication:main', Email, {singleton: false});
  8727. ```
  8728. @method register
  8729. @param {String} fullName
  8730. @param {Function} factory
  8731. @param {Object} options
  8732. */
  8733. register: function(fullName, factory, options) {
  8734. validateFullName(fullName);
  8735. if (factory === undefined) {
  8736. throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`');
  8737. }
  8738. var normalizedName = this.normalize(fullName);
  8739. if (this.cache.has(normalizedName)) {
  8740. throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.');
  8741. }
  8742. this.registry.set(normalizedName, factory);
  8743. this._options.set(normalizedName, options || {});
  8744. },
  8745. /**
  8746. Unregister a fullName
  8747. ```javascript
  8748. var container = new Container();
  8749. container.register('model:user', User);
  8750. container.lookup('model:user') instanceof User //=> true
  8751. container.unregister('model:user')
  8752. container.lookup('model:user') === undefined //=> true
  8753. ```
  8754. @method unregister
  8755. @param {String} fullName
  8756. */
  8757. unregister: function(fullName) {
  8758. validateFullName(fullName);
  8759. var normalizedName = this.normalize(fullName);
  8760. this.registry.remove(normalizedName);
  8761. this.cache.remove(normalizedName);
  8762. this.factoryCache.remove(normalizedName);
  8763. this.resolveCache.remove(normalizedName);
  8764. this._options.remove(normalizedName);
  8765. },
  8766. /**
  8767. Given a fullName return the corresponding factory.
  8768. By default `resolve` will retrieve the factory from
  8769. its container's registry.
  8770. ```javascript
  8771. var container = new Container();
  8772. container.register('api:twitter', Twitter);
  8773. container.resolve('api:twitter') // => Twitter
  8774. ```
  8775. Optionally the container can be provided with a custom resolver.
  8776. If provided, `resolve` will first provide the custom resolver
  8777. the oppertunity to resolve the fullName, otherwise it will fallback
  8778. to the registry.
  8779. ```javascript
  8780. var container = new Container();
  8781. container.resolver = function(fullName) {
  8782. // lookup via the module system of choice
  8783. };
  8784. // the twitter factory is added to the module system
  8785. container.resolve('api:twitter') // => Twitter
  8786. ```
  8787. @method resolve
  8788. @param {String} fullName
  8789. @return {Function} fullName's factory
  8790. */
  8791. resolve: function(fullName) {
  8792. validateFullName(fullName);
  8793. var normalizedName = this.normalize(fullName);
  8794. var cached = this.resolveCache.get(normalizedName);
  8795. if (cached) { return cached; }
  8796. var resolved = this.resolver(normalizedName) || this.registry.get(normalizedName);
  8797. this.resolveCache.set(normalizedName, resolved);
  8798. return resolved;
  8799. },
  8800. /**
  8801. A hook that can be used to describe how the resolver will
  8802. attempt to find the factory.
  8803. For example, the default Ember `.describe` returns the full
  8804. class name (including namespace) where Ember's resolver expects
  8805. to find the `fullName`.
  8806. @method describe
  8807. @param {String} fullName
  8808. @return {string} described fullName
  8809. */
  8810. describe: function(fullName) {
  8811. return fullName;
  8812. },
  8813. /**
  8814. A hook to enable custom fullName normalization behaviour
  8815. @method normalize
  8816. @param {String} fullName
  8817. @return {string} normalized fullName
  8818. */
  8819. normalize: function(fullName) {
  8820. return fullName;
  8821. },
  8822. /**
  8823. @method makeToString
  8824. @param {any} factory
  8825. @param {string} fullName
  8826. @return {function} toString function
  8827. */
  8828. makeToString: function(factory, fullName) {
  8829. return factory.toString();
  8830. },
  8831. /**
  8832. Given a fullName return a corresponding instance.
  8833. The default behaviour is for lookup to return a singleton instance.
  8834. The singleton is scoped to the container, allowing multiple containers
  8835. to all have their own locally scoped singletons.
  8836. ```javascript
  8837. var container = new Container();
  8838. container.register('api:twitter', Twitter);
  8839. var twitter = container.lookup('api:twitter');
  8840. twitter instanceof Twitter; // => true
  8841. // by default the container will return singletons
  8842. var twitter2 = container.lookup('api:twitter');
  8843. twitter instanceof Twitter; // => true
  8844. twitter === twitter2; //=> true
  8845. ```
  8846. If singletons are not wanted an optional flag can be provided at lookup.
  8847. ```javascript
  8848. var container = new Container();
  8849. container.register('api:twitter', Twitter);
  8850. var twitter = container.lookup('api:twitter', { singleton: false });
  8851. var twitter2 = container.lookup('api:twitter', { singleton: false });
  8852. twitter === twitter2; //=> false
  8853. ```
  8854. @method lookup
  8855. @param {String} fullName
  8856. @param {Object} options
  8857. @return {any}
  8858. */
  8859. lookup: function(fullName, options) {
  8860. validateFullName(fullName);
  8861. return lookup(this, this.normalize(fullName), options);
  8862. },
  8863. /**
  8864. Given a fullName return the corresponding factory.
  8865. @method lookupFactory
  8866. @param {String} fullName
  8867. @return {any}
  8868. */
  8869. lookupFactory: function(fullName) {
  8870. validateFullName(fullName);
  8871. return factoryFor(this, this.normalize(fullName));
  8872. },
  8873. /**
  8874. Given a fullName check if the container is aware of its factory
  8875. or singleton instance.
  8876. @method has
  8877. @param {String} fullName
  8878. @return {Boolean}
  8879. */
  8880. has: function(fullName) {
  8881. validateFullName(fullName);
  8882. return has(this, this.normalize(fullName));
  8883. },
  8884. /**
  8885. Allow registering options for all factories of a type.
  8886. ```javascript
  8887. var container = new Container();
  8888. // if all of type `connection` must not be singletons
  8889. container.optionsForType('connection', { singleton: false });
  8890. container.register('connection:twitter', TwitterConnection);
  8891. container.register('connection:facebook', FacebookConnection);
  8892. var twitter = container.lookup('connection:twitter');
  8893. var twitter2 = container.lookup('connection:twitter');
  8894. twitter === twitter2; // => false
  8895. var facebook = container.lookup('connection:facebook');
  8896. var facebook2 = container.lookup('connection:facebook');
  8897. facebook === facebook2; // => false
  8898. ```
  8899. @method optionsForType
  8900. @param {String} type
  8901. @param {Object} options
  8902. */
  8903. optionsForType: function(type, options) {
  8904. if (this.parent) { illegalChildOperation('optionsForType'); }
  8905. this._typeOptions.set(type, options);
  8906. },
  8907. /**
  8908. @method options
  8909. @param {String} type
  8910. @param {Object} options
  8911. */
  8912. options: function(type, options) {
  8913. this.optionsForType(type, options);
  8914. },
  8915. /**
  8916. Used only via `injection`.
  8917. Provides a specialized form of injection, specifically enabling
  8918. all objects of one type to be injected with a reference to another
  8919. object.
  8920. For example, provided each object of type `controller` needed a `router`.
  8921. one would do the following:
  8922. ```javascript
  8923. var container = new Container();
  8924. container.register('router:main', Router);
  8925. container.register('controller:user', UserController);
  8926. container.register('controller:post', PostController);
  8927. container.typeInjection('controller', 'router', 'router:main');
  8928. var user = container.lookup('controller:user');
  8929. var post = container.lookup('controller:post');
  8930. user.router instanceof Router; //=> true
  8931. post.router instanceof Router; //=> true
  8932. // both controllers share the same router
  8933. user.router === post.router; //=> true
  8934. ```
  8935. @private
  8936. @method typeInjection
  8937. @param {String} type
  8938. @param {String} property
  8939. @param {String} fullName
  8940. */
  8941. typeInjection: function(type, property, fullName) {
  8942. validateFullName(fullName);
  8943. if (this.parent) { illegalChildOperation('typeInjection'); }
  8944. addTypeInjection(this.typeInjections, type, property, fullName);
  8945. },
  8946. /**
  8947. Defines injection rules.
  8948. These rules are used to inject dependencies onto objects when they
  8949. are instantiated.
  8950. Two forms of injections are possible:
  8951. * Injecting one fullName on another fullName
  8952. * Injecting one fullName on a type
  8953. Example:
  8954. ```javascript
  8955. var container = new Container();
  8956. container.register('source:main', Source);
  8957. container.register('model:user', User);
  8958. container.register('model:post', Post);
  8959. // injecting one fullName on another fullName
  8960. // eg. each user model gets a post model
  8961. container.injection('model:user', 'post', 'model:post');
  8962. // injecting one fullName on another type
  8963. container.injection('model', 'source', 'source:main');
  8964. var user = container.lookup('model:user');
  8965. var post = container.lookup('model:post');
  8966. user.source instanceof Source; //=> true
  8967. post.source instanceof Source; //=> true
  8968. user.post instanceof Post; //=> true
  8969. // and both models share the same source
  8970. user.source === post.source; //=> true
  8971. ```
  8972. @method injection
  8973. @param {String} factoryName
  8974. @param {String} property
  8975. @param {String} injectionName
  8976. */
  8977. injection: function(fullName, property, injectionName) {
  8978. if (this.parent) { illegalChildOperation('injection'); }
  8979. validateFullName(injectionName);
  8980. var normalizedInjectionName = this.normalize(injectionName);
  8981. if (fullName.indexOf(':') === -1) {
  8982. return this.typeInjection(fullName, property, normalizedInjectionName);
  8983. }
  8984. validateFullName(fullName);
  8985. var normalizedName = this.normalize(fullName);
  8986. addInjection(this.injections, normalizedName, property, normalizedInjectionName);
  8987. },
  8988. /**
  8989. Used only via `factoryInjection`.
  8990. Provides a specialized form of injection, specifically enabling
  8991. all factory of one type to be injected with a reference to another
  8992. object.
  8993. For example, provided each factory of type `model` needed a `store`.
  8994. one would do the following:
  8995. ```javascript
  8996. var container = new Container();
  8997. container.register('store:main', SomeStore);
  8998. container.factoryTypeInjection('model', 'store', 'store:main');
  8999. var store = container.lookup('store:main');
  9000. var UserFactory = container.lookupFactory('model:user');
  9001. UserFactory.store instanceof SomeStore; //=> true
  9002. ```
  9003. @private
  9004. @method factoryTypeInjection
  9005. @param {String} type
  9006. @param {String} property
  9007. @param {String} fullName
  9008. */
  9009. factoryTypeInjection: function(type, property, fullName) {
  9010. if (this.parent) { illegalChildOperation('factoryTypeInjection'); }
  9011. addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName));
  9012. },
  9013. /**
  9014. Defines factory injection rules.
  9015. Similar to regular injection rules, but are run against factories, via
  9016. `Container#lookupFactory`.
  9017. These rules are used to inject objects onto factories when they
  9018. are looked up.
  9019. Two forms of injections are possible:
  9020. * Injecting one fullName on another fullName
  9021. * Injecting one fullName on a type
  9022. Example:
  9023. ```javascript
  9024. var container = new Container();
  9025. container.register('store:main', Store);
  9026. container.register('store:secondary', OtherStore);
  9027. container.register('model:user', User);
  9028. container.register('model:post', Post);
  9029. // injecting one fullName on another type
  9030. container.factoryInjection('model', 'store', 'store:main');
  9031. // injecting one fullName on another fullName
  9032. container.factoryInjection('model:post', 'secondaryStore', 'store:secondary');
  9033. var UserFactory = container.lookupFactory('model:user');
  9034. var PostFactory = container.lookupFactory('model:post');
  9035. var store = container.lookup('store:main');
  9036. UserFactory.store instanceof Store; //=> true
  9037. UserFactory.secondaryStore instanceof OtherStore; //=> false
  9038. PostFactory.store instanceof Store; //=> true
  9039. PostFactory.secondaryStore instanceof OtherStore; //=> true
  9040. // and both models share the same source instance
  9041. UserFactory.store === PostFactory.store; //=> true
  9042. ```
  9043. @method factoryInjection
  9044. @param {String} factoryName
  9045. @param {String} property
  9046. @param {String} injectionName
  9047. */
  9048. factoryInjection: function(fullName, property, injectionName) {
  9049. if (this.parent) { illegalChildOperation('injection'); }
  9050. var normalizedName = this.normalize(fullName);
  9051. var normalizedInjectionName = this.normalize(injectionName);
  9052. validateFullName(injectionName);
  9053. if (fullName.indexOf(':') === -1) {
  9054. return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName);
  9055. }
  9056. validateFullName(fullName);
  9057. addInjection(this.factoryInjections, normalizedName, property, normalizedInjectionName);
  9058. },
  9059. /**
  9060. A depth first traversal, destroying the container, its descendant containers and all
  9061. their managed objects.
  9062. @method destroy
  9063. */
  9064. destroy: function() {
  9065. for (var i=0, l=this.children.length; i<l; i++) {
  9066. this.children[i].destroy();
  9067. }
  9068. this.children = [];
  9069. eachDestroyable(this, function(item) {
  9070. item.destroy();
  9071. });
  9072. this.parent = undefined;
  9073. this.isDestroyed = true;
  9074. },
  9075. /**
  9076. @method reset
  9077. */
  9078. reset: function() {
  9079. for (var i=0, l=this.children.length; i<l; i++) {
  9080. resetCache(this.children[i]);
  9081. }
  9082. resetCache(this);
  9083. }
  9084. };
  9085. function has(container, fullName){
  9086. if (container.cache.has(fullName)) {
  9087. return true;
  9088. }
  9089. return !!container.resolve(fullName);
  9090. }
  9091. function lookup(container, fullName, options) {
  9092. options = options || {};
  9093. if (container.cache.has(fullName) && options.singleton !== false) {
  9094. return container.cache.get(fullName);
  9095. }
  9096. var value = instantiate(container, fullName);
  9097. if (value === undefined) { return; }
  9098. if (isSingleton(container, fullName) && options.singleton !== false) {
  9099. container.cache.set(fullName, value);
  9100. }
  9101. return value;
  9102. }
  9103. function illegalChildOperation(operation) {
  9104. throw new Error(operation + " is not currently supported on child containers");
  9105. }
  9106. function isSingleton(container, fullName) {
  9107. var singleton = option(container, fullName, 'singleton');
  9108. return singleton !== false;
  9109. }
  9110. function buildInjections(container, injections) {
  9111. var hash = {};
  9112. if (!injections) { return hash; }
  9113. var injection, injectable;
  9114. for (var i=0, l=injections.length; i<l; i++) {
  9115. injection = injections[i];
  9116. injectable = lookup(container, injection.fullName);
  9117. if (injectable !== undefined) {
  9118. hash[injection.property] = injectable;
  9119. } else {
  9120. throw new Error('Attempting to inject an unknown injection: `' + injection.fullName + '`');
  9121. }
  9122. }
  9123. return hash;
  9124. }
  9125. function option(container, fullName, optionName) {
  9126. var options = container._options.get(fullName);
  9127. if (options && options[optionName] !== undefined) {
  9128. return options[optionName];
  9129. }
  9130. var type = fullName.split(":")[0];
  9131. options = container._typeOptions.get(type);
  9132. if (options) {
  9133. return options[optionName];
  9134. }
  9135. }
  9136. function factoryFor(container, fullName) {
  9137. var name = fullName;
  9138. var factory = container.resolve(name);
  9139. var injectedFactory;
  9140. var cache = container.factoryCache;
  9141. var type = fullName.split(":")[0];
  9142. if (factory === undefined) { return; }
  9143. if (cache.has(fullName)) {
  9144. return cache.get(fullName);
  9145. }
  9146. if (!factory || typeof factory.extend !== 'function' || (!Ember.MODEL_FACTORY_INJECTIONS && type === 'model')) {
  9147. // TODO: think about a 'safe' merge style extension
  9148. // for now just fallback to create time injection
  9149. return factory;
  9150. } else {
  9151. var injections = injectionsFor(container, fullName);
  9152. var factoryInjections = factoryInjectionsFor(container, fullName);
  9153. factoryInjections._toString = container.makeToString(factory, fullName);
  9154. injectedFactory = factory.extend(injections);
  9155. injectedFactory.reopenClass(factoryInjections);
  9156. cache.set(fullName, injectedFactory);
  9157. return injectedFactory;
  9158. }
  9159. }
  9160. function injectionsFor(container ,fullName) {
  9161. var splitName = fullName.split(":"),
  9162. type = splitName[0],
  9163. injections = [];
  9164. injections = injections.concat(container.typeInjections.get(type) || []);
  9165. injections = injections.concat(container.injections[fullName] || []);
  9166. injections = buildInjections(container, injections);
  9167. injections._debugContainerKey = fullName;
  9168. injections.container = container;
  9169. return injections;
  9170. }
  9171. function factoryInjectionsFor(container, fullName) {
  9172. var splitName = fullName.split(":"),
  9173. type = splitName[0],
  9174. factoryInjections = [];
  9175. factoryInjections = factoryInjections.concat(container.factoryTypeInjections.get(type) || []);
  9176. factoryInjections = factoryInjections.concat(container.factoryInjections[fullName] || []);
  9177. factoryInjections = buildInjections(container, factoryInjections);
  9178. factoryInjections._debugContainerKey = fullName;
  9179. return factoryInjections;
  9180. }
  9181. function instantiate(container, fullName) {
  9182. var factory = factoryFor(container, fullName);
  9183. if (option(container, fullName, 'instantiate') === false) {
  9184. return factory;
  9185. }
  9186. if (factory) {
  9187. if (typeof factory.extend === 'function') {
  9188. // assume the factory was extendable and is already injected
  9189. return factory.create();
  9190. } else {
  9191. // assume the factory was extendable
  9192. // to create time injections
  9193. // TODO: support new'ing for instantiation and merge injections for pure JS Functions
  9194. return factory.create(injectionsFor(container, fullName));
  9195. }
  9196. }
  9197. }
  9198. function eachDestroyable(container, callback) {
  9199. container.cache.eachLocal(function(key, value) {
  9200. if (option(container, key, 'instantiate') === false) { return; }
  9201. callback(value);
  9202. });
  9203. }
  9204. function resetCache(container) {
  9205. container.cache.eachLocal(function(key, value) {
  9206. if (option(container, key, 'instantiate') === false) { return; }
  9207. value.destroy();
  9208. });
  9209. container.cache.dict = {};
  9210. }
  9211. function addTypeInjection(rules, type, property, fullName) {
  9212. var injections = rules.get(type);
  9213. if (!injections) {
  9214. injections = [];
  9215. rules.set(type, injections);
  9216. }
  9217. injections.push({
  9218. property: property,
  9219. fullName: fullName
  9220. });
  9221. }
  9222. var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/;
  9223. function validateFullName(fullName) {
  9224. if (!VALID_FULL_NAME_REGEXP.test(fullName)) {
  9225. throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName);
  9226. }
  9227. }
  9228. function addInjection(rules, factoryName, property, injectionName) {
  9229. var injections = rules[factoryName] = rules[factoryName] || [];
  9230. injections.push({ property: property, fullName: injectionName });
  9231. }
  9232. return Container;
  9233. });
  9234. })();
  9235. (function() {
  9236. /*globals ENV */
  9237. /**
  9238. @module ember
  9239. @submodule ember-runtime
  9240. */
  9241. var indexOf = Ember.EnumerableUtils.indexOf;
  9242. /**
  9243. This will compare two javascript values of possibly different types.
  9244. It will tell you which one is greater than the other by returning:
  9245. - -1 if the first is smaller than the second,
  9246. - 0 if both are equal,
  9247. - 1 if the first is greater than the second.
  9248. The order is calculated based on `Ember.ORDER_DEFINITION`, if types are different.
  9249. In case they have the same type an appropriate comparison for this type is made.
  9250. ```javascript
  9251. Ember.compare('hello', 'hello'); // 0
  9252. Ember.compare('abc', 'dfg'); // -1
  9253. Ember.compare(2, 1); // 1
  9254. ```
  9255. @method compare
  9256. @for Ember
  9257. @param {Object} v First value to compare
  9258. @param {Object} w Second value to compare
  9259. @return {Number} -1 if v < w, 0 if v = w and 1 if v > w.
  9260. */
  9261. Ember.compare = function compare(v, w) {
  9262. if (v === w) { return 0; }
  9263. var type1 = Ember.typeOf(v);
  9264. var type2 = Ember.typeOf(w);
  9265. var Comparable = Ember.Comparable;
  9266. if (Comparable) {
  9267. if (type1==='instance' && Comparable.detect(v.constructor)) {
  9268. return v.constructor.compare(v, w);
  9269. }
  9270. if (type2 === 'instance' && Comparable.detect(w.constructor)) {
  9271. return 1-w.constructor.compare(w, v);
  9272. }
  9273. }
  9274. // If we haven't yet generated a reverse-mapping of Ember.ORDER_DEFINITION,
  9275. // do so now.
  9276. var mapping = Ember.ORDER_DEFINITION_MAPPING;
  9277. if (!mapping) {
  9278. var order = Ember.ORDER_DEFINITION;
  9279. mapping = Ember.ORDER_DEFINITION_MAPPING = {};
  9280. var idx, len;
  9281. for (idx = 0, len = order.length; idx < len; ++idx) {
  9282. mapping[order[idx]] = idx;
  9283. }
  9284. // We no longer need Ember.ORDER_DEFINITION.
  9285. delete Ember.ORDER_DEFINITION;
  9286. }
  9287. var type1Index = mapping[type1];
  9288. var type2Index = mapping[type2];
  9289. if (type1Index < type2Index) { return -1; }
  9290. if (type1Index > type2Index) { return 1; }
  9291. // types are equal - so we have to check values now
  9292. switch (type1) {
  9293. case 'boolean':
  9294. case 'number':
  9295. if (v < w) { return -1; }
  9296. if (v > w) { return 1; }
  9297. return 0;
  9298. case 'string':
  9299. var comp = v.localeCompare(w);
  9300. if (comp < 0) { return -1; }
  9301. if (comp > 0) { return 1; }
  9302. return 0;
  9303. case 'array':
  9304. var vLen = v.length;
  9305. var wLen = w.length;
  9306. var l = Math.min(vLen, wLen);
  9307. var r = 0;
  9308. var i = 0;
  9309. while (r === 0 && i < l) {
  9310. r = compare(v[i],w[i]);
  9311. i++;
  9312. }
  9313. if (r !== 0) { return r; }
  9314. // all elements are equal now
  9315. // shorter array should be ordered first
  9316. if (vLen < wLen) { return -1; }
  9317. if (vLen > wLen) { return 1; }
  9318. // arrays are equal now
  9319. return 0;
  9320. case 'instance':
  9321. if (Ember.Comparable && Ember.Comparable.detect(v)) {
  9322. return v.compare(v, w);
  9323. }
  9324. return 0;
  9325. case 'date':
  9326. var vNum = v.getTime();
  9327. var wNum = w.getTime();
  9328. if (vNum < wNum) { return -1; }
  9329. if (vNum > wNum) { return 1; }
  9330. return 0;
  9331. default:
  9332. return 0;
  9333. }
  9334. };
  9335. function _copy(obj, deep, seen, copies) {
  9336. var ret, loc, key;
  9337. // primitive data types are immutable, just return them.
  9338. if ('object' !== typeof obj || obj===null) return obj;
  9339. // avoid cyclical loops
  9340. if (deep && (loc=indexOf(seen, obj))>=0) return copies[loc];
  9341. Ember.assert('Cannot clone an Ember.Object that does not implement Ember.Copyable', !(obj instanceof Ember.Object) || (Ember.Copyable && Ember.Copyable.detect(obj)));
  9342. // IMPORTANT: this specific test will detect a native array only. Any other
  9343. // object will need to implement Copyable.
  9344. if (Ember.typeOf(obj) === 'array') {
  9345. ret = obj.slice();
  9346. if (deep) {
  9347. loc = ret.length;
  9348. while(--loc>=0) ret[loc] = _copy(ret[loc], deep, seen, copies);
  9349. }
  9350. } else if (Ember.Copyable && Ember.Copyable.detect(obj)) {
  9351. ret = obj.copy(deep, seen, copies);
  9352. } else {
  9353. ret = {};
  9354. for(key in obj) {
  9355. if (!obj.hasOwnProperty(key)) continue;
  9356. // Prevents browsers that don't respect non-enumerability from
  9357. // copying internal Ember properties
  9358. if (key.substring(0,2) === '__') continue;
  9359. ret[key] = deep ? _copy(obj[key], deep, seen, copies) : obj[key];
  9360. }
  9361. }
  9362. if (deep) {
  9363. seen.push(obj);
  9364. copies.push(ret);
  9365. }
  9366. return ret;
  9367. }
  9368. /**
  9369. Creates a clone of the passed object. This function can take just about
  9370. any type of object and create a clone of it, including primitive values
  9371. (which are not actually cloned because they are immutable).
  9372. If the passed object implements the `clone()` method, then this function
  9373. will simply call that method and return the result.
  9374. @method copy
  9375. @for Ember
  9376. @param {Object} obj The object to clone
  9377. @param {Boolean} deep If true, a deep copy of the object is made
  9378. @return {Object} The cloned object
  9379. */
  9380. Ember.copy = function(obj, deep) {
  9381. // fast paths
  9382. if ('object' !== typeof obj || obj===null) return obj; // can't copy primitives
  9383. if (Ember.Copyable && Ember.Copyable.detect(obj)) return obj.copy(deep);
  9384. return _copy(obj, deep, deep ? [] : null, deep ? [] : null);
  9385. };
  9386. /**
  9387. Compares two objects, returning true if they are logically equal. This is
  9388. a deeper comparison than a simple triple equal. For sets it will compare the
  9389. internal objects. For any other object that implements `isEqual()` it will
  9390. respect that method.
  9391. ```javascript
  9392. Ember.isEqual('hello', 'hello'); // true
  9393. Ember.isEqual(1, 2); // false
  9394. Ember.isEqual([4,2], [4,2]); // false
  9395. ```
  9396. @method isEqual
  9397. @for Ember
  9398. @param {Object} a first object to compare
  9399. @param {Object} b second object to compare
  9400. @return {Boolean}
  9401. */
  9402. Ember.isEqual = function(a, b) {
  9403. if (a && 'function'===typeof a.isEqual) return a.isEqual(b);
  9404. return a === b;
  9405. };
  9406. // Used by Ember.compare
  9407. Ember.ORDER_DEFINITION = Ember.ENV.ORDER_DEFINITION || [
  9408. 'undefined',
  9409. 'null',
  9410. 'boolean',
  9411. 'number',
  9412. 'string',
  9413. 'array',
  9414. 'object',
  9415. 'instance',
  9416. 'function',
  9417. 'class',
  9418. 'date'
  9419. ];
  9420. /**
  9421. Returns all of the keys defined on an object or hash. This is useful
  9422. when inspecting objects for debugging. On browsers that support it, this
  9423. uses the native `Object.keys` implementation.
  9424. @method keys
  9425. @for Ember
  9426. @param {Object} obj
  9427. @return {Array} Array containing keys of obj
  9428. */
  9429. Ember.keys = Object.keys;
  9430. if (!Ember.keys || Ember.create.isSimulated) {
  9431. var prototypeProperties = [
  9432. 'constructor',
  9433. 'hasOwnProperty',
  9434. 'isPrototypeOf',
  9435. 'propertyIsEnumerable',
  9436. 'valueOf',
  9437. 'toLocaleString',
  9438. 'toString'
  9439. ],
  9440. pushPropertyName = function(obj, array, key) {
  9441. // Prevents browsers that don't respect non-enumerability from
  9442. // copying internal Ember properties
  9443. if (key.substring(0,2) === '__') return;
  9444. if (key === '_super') return;
  9445. if (indexOf(array, key) >= 0) return;
  9446. if (!obj.hasOwnProperty(key)) return;
  9447. array.push(key);
  9448. };
  9449. Ember.keys = function(obj) {
  9450. var ret = [], key;
  9451. for (key in obj) {
  9452. pushPropertyName(obj, ret, key);
  9453. }
  9454. // IE8 doesn't enumerate property that named the same as prototype properties.
  9455. for (var i = 0, l = prototypeProperties.length; i < l; i++) {
  9456. key = prototypeProperties[i];
  9457. pushPropertyName(obj, ret, key);
  9458. }
  9459. return ret;
  9460. };
  9461. }
  9462. })();
  9463. (function() {
  9464. /**
  9465. @module ember
  9466. @submodule ember-runtime
  9467. */
  9468. var STRING_DASHERIZE_REGEXP = (/[ _]/g);
  9469. var STRING_DASHERIZE_CACHE = {};
  9470. var STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g);
  9471. var STRING_CAMELIZE_REGEXP = (/(\-|_|\.|\s)+(.)?/g);
  9472. var STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g);
  9473. var STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g);
  9474. var STRING_PARAMETERIZE_REGEXP_1 = (/[_|\/|\s]+/g);
  9475. var STRING_PARAMETERIZE_REGEXP_2 = (/[^a-z0-9\-]+/gi);
  9476. var STRING_PARAMETERIZE_REGEXP_3 = (/[\-]+/g);
  9477. var STRING_PARAMETERIZE_REGEXP_4 = (/^-+|-+$/g);
  9478. /**
  9479. Defines the hash of localized strings for the current language. Used by
  9480. the `Ember.String.loc()` helper. To localize, add string values to this
  9481. hash.
  9482. @property STRINGS
  9483. @for Ember
  9484. @type Hash
  9485. */
  9486. Ember.STRINGS = {};
  9487. /**
  9488. Defines string helper methods including string formatting and localization.
  9489. Unless `Ember.EXTEND_PROTOTYPES.String` is `false` these methods will also be
  9490. added to the `String.prototype` as well.
  9491. @class String
  9492. @namespace Ember
  9493. @static
  9494. */
  9495. Ember.String = {
  9496. /**
  9497. Apply formatting options to the string. This will look for occurrences
  9498. of "%@" in your string and substitute them with the arguments you pass into
  9499. this method. If you want to control the specific order of replacement,
  9500. you can add a number after the key as well to indicate which argument
  9501. you want to insert.
  9502. Ordered insertions are most useful when building loc strings where values
  9503. you need to insert may appear in different orders.
  9504. ```javascript
  9505. "Hello %@ %@".fmt('John', 'Doe'); // "Hello John Doe"
  9506. "Hello %@2, %@1".fmt('John', 'Doe'); // "Hello Doe, John"
  9507. ```
  9508. @method fmt
  9509. @param {String} str The string to format
  9510. @param {Array} formats An array of parameters to interpolate into string.
  9511. @return {String} formatted string
  9512. */
  9513. fmt: function(str, formats) {
  9514. // first, replace any ORDERED replacements.
  9515. var idx = 0; // the current index for non-numerical replacements
  9516. return str.replace(/%@([0-9]+)?/g, function(s, argIndex) {
  9517. argIndex = (argIndex) ? parseInt(argIndex, 10) - 1 : idx++;
  9518. s = formats[argIndex];
  9519. return (s === null) ? '(null)' : (s === undefined) ? '' : Ember.inspect(s);
  9520. }) ;
  9521. },
  9522. /**
  9523. Formats the passed string, but first looks up the string in the localized
  9524. strings hash. This is a convenient way to localize text. See
  9525. `Ember.String.fmt()` for more information on formatting.
  9526. Note that it is traditional but not required to prefix localized string
  9527. keys with an underscore or other character so you can easily identify
  9528. localized strings.
  9529. ```javascript
  9530. Ember.STRINGS = {
  9531. '_Hello World': 'Bonjour le monde',
  9532. '_Hello %@ %@': 'Bonjour %@ %@'
  9533. };
  9534. Ember.String.loc("_Hello World"); // 'Bonjour le monde';
  9535. Ember.String.loc("_Hello %@ %@", ["John", "Smith"]); // "Bonjour John Smith";
  9536. ```
  9537. @method loc
  9538. @param {String} str The string to format
  9539. @param {Array} formats Optional array of parameters to interpolate into string.
  9540. @return {String} formatted string
  9541. */
  9542. loc: function(str, formats) {
  9543. str = Ember.STRINGS[str] || str;
  9544. return Ember.String.fmt(str, formats) ;
  9545. },
  9546. /**
  9547. Splits a string into separate units separated by spaces, eliminating any
  9548. empty strings in the process. This is a convenience method for split that
  9549. is mostly useful when applied to the `String.prototype`.
  9550. ```javascript
  9551. Ember.String.w("alpha beta gamma").forEach(function(key) {
  9552. console.log(key);
  9553. });
  9554. // > alpha
  9555. // > beta
  9556. // > gamma
  9557. ```
  9558. @method w
  9559. @param {String} str The string to split
  9560. @return {String} split string
  9561. */
  9562. w: function(str) { return str.split(/\s+/); },
  9563. /**
  9564. Converts a camelized string into all lower case separated by underscores.
  9565. ```javascript
  9566. 'innerHTML'.decamelize(); // 'inner_html'
  9567. 'action_name'.decamelize(); // 'action_name'
  9568. 'css-class-name'.decamelize(); // 'css-class-name'
  9569. 'my favorite items'.decamelize(); // 'my favorite items'
  9570. ```
  9571. @method decamelize
  9572. @param {String} str The string to decamelize.
  9573. @return {String} the decamelized string.
  9574. */
  9575. decamelize: function(str) {
  9576. return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase();
  9577. },
  9578. /**
  9579. Replaces underscores, spaces, or camelCase with dashes.
  9580. ```javascript
  9581. 'innerHTML'.dasherize(); // 'inner-html'
  9582. 'action_name'.dasherize(); // 'action-name'
  9583. 'css-class-name'.dasherize(); // 'css-class-name'
  9584. 'my favorite items'.dasherize(); // 'my-favorite-items'
  9585. ```
  9586. @method dasherize
  9587. @param {String} str The string to dasherize.
  9588. @return {String} the dasherized string.
  9589. */
  9590. dasherize: function(str) {
  9591. var cache = STRING_DASHERIZE_CACHE,
  9592. hit = cache.hasOwnProperty(str),
  9593. ret;
  9594. if (hit) {
  9595. return cache[str];
  9596. } else {
  9597. ret = Ember.String.decamelize(str).replace(STRING_DASHERIZE_REGEXP,'-');
  9598. cache[str] = ret;
  9599. }
  9600. return ret;
  9601. },
  9602. /**
  9603. Returns the lowerCamelCase form of a string.
  9604. ```javascript
  9605. 'innerHTML'.camelize(); // 'innerHTML'
  9606. 'action_name'.camelize(); // 'actionName'
  9607. 'css-class-name'.camelize(); // 'cssClassName'
  9608. 'my favorite items'.camelize(); // 'myFavoriteItems'
  9609. 'My Favorite Items'.camelize(); // 'myFavoriteItems'
  9610. ```
  9611. @method camelize
  9612. @param {String} str The string to camelize.
  9613. @return {String} the camelized string.
  9614. */
  9615. camelize: function(str) {
  9616. return str.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) {
  9617. return chr ? chr.toUpperCase() : '';
  9618. }).replace(/^([A-Z])/, function(match, separator, chr) {
  9619. return match.toLowerCase();
  9620. });
  9621. },
  9622. /**
  9623. Returns the UpperCamelCase form of a string.
  9624. ```javascript
  9625. 'innerHTML'.classify(); // 'InnerHTML'
  9626. 'action_name'.classify(); // 'ActionName'
  9627. 'css-class-name'.classify(); // 'CssClassName'
  9628. 'my favorite items'.classify(); // 'MyFavoriteItems'
  9629. ```
  9630. @method classify
  9631. @param {String} str the string to classify
  9632. @return {String} the classified string
  9633. */
  9634. classify: function(str) {
  9635. var parts = str.split("."),
  9636. out = [];
  9637. for (var i=0, l=parts.length; i<l; i++) {
  9638. var camelized = Ember.String.camelize(parts[i]);
  9639. out.push(camelized.charAt(0).toUpperCase() + camelized.substr(1));
  9640. }
  9641. return out.join(".");
  9642. },
  9643. /**
  9644. More general than decamelize. Returns the lower\_case\_and\_underscored
  9645. form of a string.
  9646. ```javascript
  9647. 'innerHTML'.underscore(); // 'inner_html'
  9648. 'action_name'.underscore(); // 'action_name'
  9649. 'css-class-name'.underscore(); // 'css_class_name'
  9650. 'my favorite items'.underscore(); // 'my_favorite_items'
  9651. ```
  9652. @method underscore
  9653. @param {String} str The string to underscore.
  9654. @return {String} the underscored string.
  9655. */
  9656. underscore: function(str) {
  9657. return str.replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2').
  9658. replace(STRING_UNDERSCORE_REGEXP_2, '_').toLowerCase();
  9659. },
  9660. /**
  9661. Returns the Capitalized form of a string
  9662. ```javascript
  9663. 'innerHTML'.capitalize() // 'InnerHTML'
  9664. 'action_name'.capitalize() // 'Action_name'
  9665. 'css-class-name'.capitalize() // 'Css-class-name'
  9666. 'my favorite items'.capitalize() // 'My favorite items'
  9667. ```
  9668. @method capitalize
  9669. @param {String} str The string to capitalize.
  9670. @return {String} The capitalized string.
  9671. */
  9672. capitalize: function(str) {
  9673. return str.charAt(0).toUpperCase() + str.substr(1);
  9674. }
  9675. };
  9676. })();
  9677. (function() {
  9678. /**
  9679. @module ember
  9680. @submodule ember-runtime
  9681. */
  9682. var fmt = Ember.String.fmt,
  9683. w = Ember.String.w,
  9684. loc = Ember.String.loc,
  9685. camelize = Ember.String.camelize,
  9686. decamelize = Ember.String.decamelize,
  9687. dasherize = Ember.String.dasherize,
  9688. underscore = Ember.String.underscore,
  9689. capitalize = Ember.String.capitalize,
  9690. classify = Ember.String.classify;
  9691. if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
  9692. /**
  9693. See [Ember.String.fmt](/api/classes/Ember.String.html#method_fmt).
  9694. @method fmt
  9695. @for String
  9696. */
  9697. String.prototype.fmt = function() {
  9698. return fmt(this, arguments);
  9699. };
  9700. /**
  9701. See [Ember.String.w](/api/classes/Ember.String.html#method_w).
  9702. @method w
  9703. @for String
  9704. */
  9705. String.prototype.w = function() {
  9706. return w(this);
  9707. };
  9708. /**
  9709. See [Ember.String.loc](/api/classes/Ember.String.html#method_loc).
  9710. @method loc
  9711. @for String
  9712. */
  9713. String.prototype.loc = function() {
  9714. return loc(this, arguments);
  9715. };
  9716. /**
  9717. See [Ember.String.camelize](/api/classes/Ember.String.html#method_camelize).
  9718. @method camelize
  9719. @for String
  9720. */
  9721. String.prototype.camelize = function() {
  9722. return camelize(this);
  9723. };
  9724. /**
  9725. See [Ember.String.decamelize](/api/classes/Ember.String.html#method_decamelize).
  9726. @method decamelize
  9727. @for String
  9728. */
  9729. String.prototype.decamelize = function() {
  9730. return decamelize(this);
  9731. };
  9732. /**
  9733. See [Ember.String.dasherize](/api/classes/Ember.String.html#method_dasherize).
  9734. @method dasherize
  9735. @for String
  9736. */
  9737. String.prototype.dasherize = function() {
  9738. return dasherize(this);
  9739. };
  9740. /**
  9741. See [Ember.String.underscore](/api/classes/Ember.String.html#method_underscore).
  9742. @method underscore
  9743. @for String
  9744. */
  9745. String.prototype.underscore = function() {
  9746. return underscore(this);
  9747. };
  9748. /**
  9749. See [Ember.String.classify](/api/classes/Ember.String.html#method_classify).
  9750. @method classify
  9751. @for String
  9752. */
  9753. String.prototype.classify = function() {
  9754. return classify(this);
  9755. };
  9756. /**
  9757. See [Ember.String.capitalize](/api/classes/Ember.String.html#method_capitalize).
  9758. @method capitalize
  9759. @for String
  9760. */
  9761. String.prototype.capitalize = function() {
  9762. return capitalize(this);
  9763. };
  9764. }
  9765. })();
  9766. (function() {
  9767. /**
  9768. @module ember
  9769. @submodule ember-runtime
  9770. */
  9771. var get = Ember.get,
  9772. set = Ember.set,
  9773. slice = Array.prototype.slice,
  9774. getProperties = Ember.getProperties;
  9775. /**
  9776. ## Overview
  9777. This mixin provides properties and property observing functionality, core
  9778. features of the Ember object model.
  9779. Properties and observers allow one object to observe changes to a
  9780. property on another object. This is one of the fundamental ways that
  9781. models, controllers and views communicate with each other in an Ember
  9782. application.
  9783. Any object that has this mixin applied can be used in observer
  9784. operations. That includes `Ember.Object` and most objects you will
  9785. interact with as you write your Ember application.
  9786. Note that you will not generally apply this mixin to classes yourself,
  9787. but you will use the features provided by this module frequently, so it
  9788. is important to understand how to use it.
  9789. ## Using `get()` and `set()`
  9790. Because of Ember's support for bindings and observers, you will always
  9791. access properties using the get method, and set properties using the
  9792. set method. This allows the observing objects to be notified and
  9793. computed properties to be handled properly.
  9794. More documentation about `get` and `set` are below.
  9795. ## Observing Property Changes
  9796. You typically observe property changes simply by adding the `observes`
  9797. call to the end of your method declarations in classes that you write.
  9798. For example:
  9799. ```javascript
  9800. Ember.Object.extend({
  9801. valueObserver: function() {
  9802. // Executes whenever the "value" property changes
  9803. }.observes('value')
  9804. });
  9805. ```
  9806. Although this is the most common way to add an observer, this capability
  9807. is actually built into the `Ember.Object` class on top of two methods
  9808. defined in this mixin: `addObserver` and `removeObserver`. You can use
  9809. these two methods to add and remove observers yourself if you need to
  9810. do so at runtime.
  9811. To add an observer for a property, call:
  9812. ```javascript
  9813. object.addObserver('propertyKey', targetObject, targetAction)
  9814. ```
  9815. This will call the `targetAction` method on the `targetObject` whenever
  9816. the value of the `propertyKey` changes.
  9817. Note that if `propertyKey` is a computed property, the observer will be
  9818. called when any of the property dependencies are changed, even if the
  9819. resulting value of the computed property is unchanged. This is necessary
  9820. because computed properties are not computed until `get` is called.
  9821. @class Observable
  9822. @namespace Ember
  9823. */
  9824. Ember.Observable = Ember.Mixin.create({
  9825. /**
  9826. Retrieves the value of a property from the object.
  9827. This method is usually similar to using `object[keyName]` or `object.keyName`,
  9828. however it supports both computed properties and the unknownProperty
  9829. handler.
  9830. Because `get` unifies the syntax for accessing all these kinds
  9831. of properties, it can make many refactorings easier, such as replacing a
  9832. simple property with a computed property, or vice versa.
  9833. ### Computed Properties
  9834. Computed properties are methods defined with the `property` modifier
  9835. declared at the end, such as:
  9836. ```javascript
  9837. fullName: function() {
  9838. return this.get('firstName') + ' ' + this.get('lastName');
  9839. }.property('firstName', 'lastName')
  9840. ```
  9841. When you call `get` on a computed property, the function will be
  9842. called and the return value will be returned instead of the function
  9843. itself.
  9844. ### Unknown Properties
  9845. Likewise, if you try to call `get` on a property whose value is
  9846. `undefined`, the `unknownProperty()` method will be called on the object.
  9847. If this method returns any value other than `undefined`, it will be returned
  9848. instead. This allows you to implement "virtual" properties that are
  9849. not defined upfront.
  9850. @method get
  9851. @param {String} keyName The property to retrieve
  9852. @return {Object} The property value or undefined.
  9853. */
  9854. get: function(keyName) {
  9855. return get(this, keyName);
  9856. },
  9857. /**
  9858. To get multiple properties at once, call `getProperties`
  9859. with a list of strings or an array:
  9860. ```javascript
  9861. record.getProperties('firstName', 'lastName', 'zipCode'); // { firstName: 'John', lastName: 'Doe', zipCode: '10011' }
  9862. ```
  9863. is equivalent to:
  9864. ```javascript
  9865. record.getProperties(['firstName', 'lastName', 'zipCode']); // { firstName: 'John', lastName: 'Doe', zipCode: '10011' }
  9866. ```
  9867. @method getProperties
  9868. @param {String...|Array} list of keys to get
  9869. @return {Hash}
  9870. */
  9871. getProperties: function() {
  9872. return getProperties.apply(null, [this].concat(slice.call(arguments)));
  9873. },
  9874. /**
  9875. Sets the provided key or path to the value.
  9876. This method is generally very similar to calling `object[key] = value` or
  9877. `object.key = value`, except that it provides support for computed
  9878. properties, the `setUnknownProperty()` method and property observers.
  9879. ### Computed Properties
  9880. If you try to set a value on a key that has a computed property handler
  9881. defined (see the `get()` method for an example), then `set()` will call
  9882. that method, passing both the value and key instead of simply changing
  9883. the value itself. This is useful for those times when you need to
  9884. implement a property that is composed of one or more member
  9885. properties.
  9886. ### Unknown Properties
  9887. If you try to set a value on a key that is undefined in the target
  9888. object, then the `setUnknownProperty()` handler will be called instead. This
  9889. gives you an opportunity to implement complex "virtual" properties that
  9890. are not predefined on the object. If `setUnknownProperty()` returns
  9891. undefined, then `set()` will simply set the value on the object.
  9892. ### Property Observers
  9893. In addition to changing the property, `set()` will also register a property
  9894. change with the object. Unless you have placed this call inside of a
  9895. `beginPropertyChanges()` and `endPropertyChanges(),` any "local" observers
  9896. (i.e. observer methods declared on the same object), will be called
  9897. immediately. Any "remote" observers (i.e. observer methods declared on
  9898. another object) will be placed in a queue and called at a later time in a
  9899. coalesced manner.
  9900. ### Chaining
  9901. In addition to property changes, `set()` returns the value of the object
  9902. itself so you can do chaining like this:
  9903. ```javascript
  9904. record.set('firstName', 'Charles').set('lastName', 'Jolley');
  9905. ```
  9906. @method set
  9907. @param {String} keyName The property to set
  9908. @param {Object} value The value to set or `null`.
  9909. @return {Ember.Observable}
  9910. */
  9911. set: function(keyName, value) {
  9912. set(this, keyName, value);
  9913. return this;
  9914. },
  9915. /**
  9916. Sets a list of properties at once. These properties are set inside
  9917. a single `beginPropertyChanges` and `endPropertyChanges` batch, so
  9918. observers will be buffered.
  9919. ```javascript
  9920. record.setProperties({ firstName: 'Charles', lastName: 'Jolley' });
  9921. ```
  9922. @method setProperties
  9923. @param {Hash} hash the hash of keys and values to set
  9924. @return {Ember.Observable}
  9925. */
  9926. setProperties: function(hash) {
  9927. return Ember.setProperties(this, hash);
  9928. },
  9929. /**
  9930. Begins a grouping of property changes.
  9931. You can use this method to group property changes so that notifications
  9932. will not be sent until the changes are finished. If you plan to make a
  9933. large number of changes to an object at one time, you should call this
  9934. method at the beginning of the changes to begin deferring change
  9935. notifications. When you are done making changes, call
  9936. `endPropertyChanges()` to deliver the deferred change notifications and end
  9937. deferring.
  9938. @method beginPropertyChanges
  9939. @return {Ember.Observable}
  9940. */
  9941. beginPropertyChanges: function() {
  9942. Ember.beginPropertyChanges();
  9943. return this;
  9944. },
  9945. /**
  9946. Ends a grouping of property changes.
  9947. You can use this method to group property changes so that notifications
  9948. will not be sent until the changes are finished. If you plan to make a
  9949. large number of changes to an object at one time, you should call
  9950. `beginPropertyChanges()` at the beginning of the changes to defer change
  9951. notifications. When you are done making changes, call this method to
  9952. deliver the deferred change notifications and end deferring.
  9953. @method endPropertyChanges
  9954. @return {Ember.Observable}
  9955. */
  9956. endPropertyChanges: function() {
  9957. Ember.endPropertyChanges();
  9958. return this;
  9959. },
  9960. /**
  9961. Notify the observer system that a property is about to change.
  9962. Sometimes you need to change a value directly or indirectly without
  9963. actually calling `get()` or `set()` on it. In this case, you can use this
  9964. method and `propertyDidChange()` instead. Calling these two methods
  9965. together will notify all observers that the property has potentially
  9966. changed value.
  9967. Note that you must always call `propertyWillChange` and `propertyDidChange`
  9968. as a pair. If you do not, it may get the property change groups out of
  9969. order and cause notifications to be delivered more often than you would
  9970. like.
  9971. @method propertyWillChange
  9972. @param {String} keyName The property key that is about to change.
  9973. @return {Ember.Observable}
  9974. */
  9975. propertyWillChange: function(keyName) {
  9976. Ember.propertyWillChange(this, keyName);
  9977. return this;
  9978. },
  9979. /**
  9980. Notify the observer system that a property has just changed.
  9981. Sometimes you need to change a value directly or indirectly without
  9982. actually calling `get()` or `set()` on it. In this case, you can use this
  9983. method and `propertyWillChange()` instead. Calling these two methods
  9984. together will notify all observers that the property has potentially
  9985. changed value.
  9986. Note that you must always call `propertyWillChange` and `propertyDidChange`
  9987. as a pair. If you do not, it may get the property change groups out of
  9988. order and cause notifications to be delivered more often than you would
  9989. like.
  9990. @method propertyDidChange
  9991. @param {String} keyName The property key that has just changed.
  9992. @return {Ember.Observable}
  9993. */
  9994. propertyDidChange: function(keyName) {
  9995. Ember.propertyDidChange(this, keyName);
  9996. return this;
  9997. },
  9998. /**
  9999. Convenience method to call `propertyWillChange` and `propertyDidChange` in
  10000. succession.
  10001. @method notifyPropertyChange
  10002. @param {String} keyName The property key to be notified about.
  10003. @return {Ember.Observable}
  10004. */
  10005. notifyPropertyChange: function(keyName) {
  10006. this.propertyWillChange(keyName);
  10007. this.propertyDidChange(keyName);
  10008. return this;
  10009. },
  10010. addBeforeObserver: function(key, target, method) {
  10011. Ember.addBeforeObserver(this, key, target, method);
  10012. },
  10013. /**
  10014. Adds an observer on a property.
  10015. This is the core method used to register an observer for a property.
  10016. Once you call this method, any time the key's value is set, your observer
  10017. will be notified. Note that the observers are triggered any time the
  10018. value is set, regardless of whether it has actually changed. Your
  10019. observer should be prepared to handle that.
  10020. You can also pass an optional context parameter to this method. The
  10021. context will be passed to your observer method whenever it is triggered.
  10022. Note that if you add the same target/method pair on a key multiple times
  10023. with different context parameters, your observer will only be called once
  10024. with the last context you passed.
  10025. ### Observer Methods
  10026. Observer methods you pass should generally have the following signature if
  10027. you do not pass a `context` parameter:
  10028. ```javascript
  10029. fooDidChange: function(sender, key, value, rev) { };
  10030. ```
  10031. The sender is the object that changed. The key is the property that
  10032. changes. The value property is currently reserved and unused. The rev
  10033. is the last property revision of the object when it changed, which you can
  10034. use to detect if the key value has really changed or not.
  10035. If you pass a `context` parameter, the context will be passed before the
  10036. revision like so:
  10037. ```javascript
  10038. fooDidChange: function(sender, key, value, context, rev) { };
  10039. ```
  10040. Usually you will not need the value, context or revision parameters at
  10041. the end. In this case, it is common to write observer methods that take
  10042. only a sender and key value as parameters or, if you aren't interested in
  10043. any of these values, to write an observer that has no parameters at all.
  10044. @method addObserver
  10045. @param {String} key The key to observer
  10046. @param {Object} target The target object to invoke
  10047. @param {String|Function} method The method to invoke.
  10048. @return {Ember.Object} self
  10049. */
  10050. addObserver: function(key, target, method) {
  10051. Ember.addObserver(this, key, target, method);
  10052. },
  10053. /**
  10054. Remove an observer you have previously registered on this object. Pass
  10055. the same key, target, and method you passed to `addObserver()` and your
  10056. target will no longer receive notifications.
  10057. @method removeObserver
  10058. @param {String} key The key to observer
  10059. @param {Object} target The target object to invoke
  10060. @param {String|Function} method The method to invoke.
  10061. @return {Ember.Observable} receiver
  10062. */
  10063. removeObserver: function(key, target, method) {
  10064. Ember.removeObserver(this, key, target, method);
  10065. },
  10066. /**
  10067. Returns `true` if the object currently has observers registered for a
  10068. particular key. You can use this method to potentially defer performing
  10069. an expensive action until someone begins observing a particular property
  10070. on the object.
  10071. @method hasObserverFor
  10072. @param {String} key Key to check
  10073. @return {Boolean}
  10074. */
  10075. hasObserverFor: function(key) {
  10076. return Ember.hasListeners(this, key+':change');
  10077. },
  10078. /**
  10079. Retrieves the value of a property, or a default value in the case that the
  10080. property returns `undefined`.
  10081. ```javascript
  10082. person.getWithDefault('lastName', 'Doe');
  10083. ```
  10084. @method getWithDefault
  10085. @param {String} keyName The name of the property to retrieve
  10086. @param {Object} defaultValue The value to return if the property value is undefined
  10087. @return {Object} The property value or the defaultValue.
  10088. */
  10089. getWithDefault: function(keyName, defaultValue) {
  10090. return Ember.getWithDefault(this, keyName, defaultValue);
  10091. },
  10092. /**
  10093. Set the value of a property to the current value plus some amount.
  10094. ```javascript
  10095. person.incrementProperty('age');
  10096. team.incrementProperty('score', 2);
  10097. ```
  10098. @method incrementProperty
  10099. @param {String} keyName The name of the property to increment
  10100. @param {Number} increment The amount to increment by. Defaults to 1
  10101. @return {Number} The new property value
  10102. */
  10103. incrementProperty: function(keyName, increment) {
  10104. if (Ember.isNone(increment)) { increment = 1; }
  10105. Ember.assert("Must pass a numeric value to incrementProperty", (!isNaN(parseFloat(increment)) && isFinite(increment)));
  10106. set(this, keyName, (get(this, keyName) || 0) + increment);
  10107. return get(this, keyName);
  10108. },
  10109. /**
  10110. Set the value of a property to the current value minus some amount.
  10111. ```javascript
  10112. player.decrementProperty('lives');
  10113. orc.decrementProperty('health', 5);
  10114. ```
  10115. @method decrementProperty
  10116. @param {String} keyName The name of the property to decrement
  10117. @param {Number} decrement The amount to decrement by. Defaults to 1
  10118. @return {Number} The new property value
  10119. */
  10120. decrementProperty: function(keyName, decrement) {
  10121. if (Ember.isNone(decrement)) { decrement = 1; }
  10122. Ember.assert("Must pass a numeric value to decrementProperty", (!isNaN(parseFloat(decrement)) && isFinite(decrement)));
  10123. set(this, keyName, (get(this, keyName) || 0) - decrement);
  10124. return get(this, keyName);
  10125. },
  10126. /**
  10127. Set the value of a boolean property to the opposite of it's
  10128. current value.
  10129. ```javascript
  10130. starship.toggleProperty('warpDriveEngaged');
  10131. ```
  10132. @method toggleProperty
  10133. @param {String} keyName The name of the property to toggle
  10134. @return {Object} The new property value
  10135. */
  10136. toggleProperty: function(keyName) {
  10137. set(this, keyName, !get(this, keyName));
  10138. return get(this, keyName);
  10139. },
  10140. /**
  10141. Returns the cached value of a computed property, if it exists.
  10142. This allows you to inspect the value of a computed property
  10143. without accidentally invoking it if it is intended to be
  10144. generated lazily.
  10145. @method cacheFor
  10146. @param {String} keyName
  10147. @return {Object} The cached value of the computed property, if any
  10148. */
  10149. cacheFor: function(keyName) {
  10150. return Ember.cacheFor(this, keyName);
  10151. },
  10152. // intended for debugging purposes
  10153. observersForKey: function(keyName) {
  10154. return Ember.observersFor(this, keyName);
  10155. }
  10156. });
  10157. })();
  10158. (function() {
  10159. /**
  10160. @module ember
  10161. @submodule ember-runtime
  10162. */
  10163. // NOTE: this object should never be included directly. Instead use `Ember.Object`.
  10164. // We only define this separately so that `Ember.Set` can depend on it.
  10165. var set = Ember.set, get = Ember.get,
  10166. o_create = Ember.create,
  10167. o_defineProperty = Ember.platform.defineProperty,
  10168. GUID_KEY = Ember.GUID_KEY,
  10169. guidFor = Ember.guidFor,
  10170. generateGuid = Ember.generateGuid,
  10171. meta = Ember.meta,
  10172. META_KEY = Ember.META_KEY,
  10173. rewatch = Ember.rewatch,
  10174. finishChains = Ember.finishChains,
  10175. sendEvent = Ember.sendEvent,
  10176. destroy = Ember.destroy,
  10177. schedule = Ember.run.schedule,
  10178. Mixin = Ember.Mixin,
  10179. applyMixin = Mixin._apply,
  10180. finishPartial = Mixin.finishPartial,
  10181. reopen = Mixin.prototype.reopen,
  10182. MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER,
  10183. indexOf = Ember.EnumerableUtils.indexOf;
  10184. var undefinedDescriptor = {
  10185. configurable: true,
  10186. writable: true,
  10187. enumerable: false,
  10188. value: undefined
  10189. };
  10190. function makeCtor() {
  10191. // Note: avoid accessing any properties on the object since it makes the
  10192. // method a lot faster. This is glue code so we want it to be as fast as
  10193. // possible.
  10194. var wasApplied = false, initMixins, initProperties;
  10195. var Class = function() {
  10196. if (!wasApplied) {
  10197. Class.proto(); // prepare prototype...
  10198. }
  10199. o_defineProperty(this, GUID_KEY, undefinedDescriptor);
  10200. o_defineProperty(this, '_super', undefinedDescriptor);
  10201. var m = meta(this), proto = m.proto;
  10202. m.proto = this;
  10203. if (initMixins) {
  10204. // capture locally so we can clear the closed over variable
  10205. var mixins = initMixins;
  10206. initMixins = null;
  10207. this.reopen.apply(this, mixins);
  10208. }
  10209. if (initProperties) {
  10210. // capture locally so we can clear the closed over variable
  10211. var props = initProperties;
  10212. initProperties = null;
  10213. var concatenatedProperties = this.concatenatedProperties;
  10214. for (var i = 0, l = props.length; i < l; i++) {
  10215. var properties = props[i];
  10216. Ember.assert("Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead.", !(properties instanceof Ember.Mixin));
  10217. if (typeof properties !== 'object' && properties !== undefined) {
  10218. throw new Ember.Error("Ember.Object.create only accepts objects.");
  10219. }
  10220. if (!properties) { continue; }
  10221. var keyNames = Ember.keys(properties);
  10222. for (var j = 0, ll = keyNames.length; j < ll; j++) {
  10223. var keyName = keyNames[j];
  10224. if (!properties.hasOwnProperty(keyName)) { continue; }
  10225. var value = properties[keyName],
  10226. IS_BINDING = Ember.IS_BINDING;
  10227. if (IS_BINDING.test(keyName)) {
  10228. var bindings = m.bindings;
  10229. if (!bindings) {
  10230. bindings = m.bindings = {};
  10231. } else if (!m.hasOwnProperty('bindings')) {
  10232. bindings = m.bindings = o_create(m.bindings);
  10233. }
  10234. bindings[keyName] = value;
  10235. }
  10236. var desc = m.descs[keyName];
  10237. Ember.assert("Ember.Object.create no longer supports defining computed properties.", !(value instanceof Ember.ComputedProperty));
  10238. Ember.assert("Ember.Object.create no longer supports defining methods that call _super.", !(typeof value === 'function' && value.toString().indexOf('._super') !== -1));
  10239. Ember.assert("`actions` must be provided at extend time, not at create " +
  10240. "time, when Ember.ActionHandler is used (i.e. views, " +
  10241. "controllers & routes).", !((keyName === 'actions') && Ember.ActionHandler.detect(this)));
  10242. if (concatenatedProperties && indexOf(concatenatedProperties, keyName) >= 0) {
  10243. var baseValue = this[keyName];
  10244. if (baseValue) {
  10245. if ('function' === typeof baseValue.concat) {
  10246. value = baseValue.concat(value);
  10247. } else {
  10248. value = Ember.makeArray(baseValue).concat(value);
  10249. }
  10250. } else {
  10251. value = Ember.makeArray(value);
  10252. }
  10253. }
  10254. if (desc) {
  10255. desc.set(this, keyName, value);
  10256. } else {
  10257. if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) {
  10258. this.setUnknownProperty(keyName, value);
  10259. } else if (MANDATORY_SETTER) {
  10260. Ember.defineProperty(this, keyName, null, value); // setup mandatory setter
  10261. } else {
  10262. this[keyName] = value;
  10263. }
  10264. }
  10265. }
  10266. }
  10267. }
  10268. finishPartial(this, m);
  10269. this.init.apply(this, arguments);
  10270. m.proto = proto;
  10271. finishChains(this);
  10272. sendEvent(this, "init");
  10273. };
  10274. Class.toString = Mixin.prototype.toString;
  10275. Class.willReopen = function() {
  10276. if (wasApplied) {
  10277. Class.PrototypeMixin = Mixin.create(Class.PrototypeMixin);
  10278. }
  10279. wasApplied = false;
  10280. };
  10281. Class._initMixins = function(args) { initMixins = args; };
  10282. Class._initProperties = function(args) { initProperties = args; };
  10283. Class.proto = function() {
  10284. var superclass = Class.superclass;
  10285. if (superclass) { superclass.proto(); }
  10286. if (!wasApplied) {
  10287. wasApplied = true;
  10288. Class.PrototypeMixin.applyPartial(Class.prototype);
  10289. rewatch(Class.prototype);
  10290. }
  10291. return this.prototype;
  10292. };
  10293. return Class;
  10294. }
  10295. /**
  10296. @class CoreObject
  10297. @namespace Ember
  10298. */
  10299. var CoreObject = makeCtor();
  10300. CoreObject.toString = function() { return "Ember.CoreObject"; };
  10301. CoreObject.PrototypeMixin = Mixin.create({
  10302. reopen: function() {
  10303. applyMixin(this, arguments, true);
  10304. return this;
  10305. },
  10306. /**
  10307. An overridable method called when objects are instantiated. By default,
  10308. does nothing unless it is overridden during class definition.
  10309. Example:
  10310. ```javascript
  10311. App.Person = Ember.Object.extend({
  10312. init: function() {
  10313. alert('Name is ' + this.get('name'));
  10314. }
  10315. });
  10316. var steve = App.Person.create({
  10317. name: "Steve"
  10318. });
  10319. // alerts 'Name is Steve'.
  10320. ```
  10321. NOTE: If you do override `init` for a framework class like `Ember.View` or
  10322. `Ember.ArrayController`, be sure to call `this._super()` in your
  10323. `init` declaration! If you don't, Ember may not have an opportunity to
  10324. do important setup work, and you'll see strange behavior in your
  10325. application.
  10326. @method init
  10327. */
  10328. init: function() {},
  10329. /**
  10330. Defines the properties that will be concatenated from the superclass
  10331. (instead of overridden).
  10332. By default, when you extend an Ember class a property defined in
  10333. the subclass overrides a property with the same name that is defined
  10334. in the superclass. However, there are some cases where it is preferable
  10335. to build up a property's value by combining the superclass' property
  10336. value with the subclass' value. An example of this in use within Ember
  10337. is the `classNames` property of `Ember.View`.
  10338. Here is some sample code showing the difference between a concatenated
  10339. property and a normal one:
  10340. ```javascript
  10341. App.BarView = Ember.View.extend({
  10342. someNonConcatenatedProperty: ['bar'],
  10343. classNames: ['bar']
  10344. });
  10345. App.FooBarView = App.BarView.extend({
  10346. someNonConcatenatedProperty: ['foo'],
  10347. classNames: ['foo'],
  10348. });
  10349. var fooBarView = App.FooBarView.create();
  10350. fooBarView.get('someNonConcatenatedProperty'); // ['foo']
  10351. fooBarView.get('classNames'); // ['ember-view', 'bar', 'foo']
  10352. ```
  10353. This behavior extends to object creation as well. Continuing the
  10354. above example:
  10355. ```javascript
  10356. var view = App.FooBarView.create({
  10357. someNonConcatenatedProperty: ['baz'],
  10358. classNames: ['baz']
  10359. })
  10360. view.get('someNonConcatenatedProperty'); // ['baz']
  10361. view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
  10362. ```
  10363. Adding a single property that is not an array will just add it in the array:
  10364. ```javascript
  10365. var view = App.FooBarView.create({
  10366. classNames: 'baz'
  10367. })
  10368. view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
  10369. ```
  10370. Using the `concatenatedProperties` property, we can tell to Ember that mix
  10371. the content of the properties.
  10372. In `Ember.View` the `classNameBindings` and `attributeBindings` properties
  10373. are also concatenated, in addition to `classNames`.
  10374. This feature is available for you to use throughout the Ember object model,
  10375. although typical app developers are likely to use it infrequently. Since
  10376. it changes expectations about behavior of properties, you should properly
  10377. document its usage in each individual concatenated property (to not
  10378. mislead your users to think they can override the property in a subclass).
  10379. @property concatenatedProperties
  10380. @type Array
  10381. @default null
  10382. */
  10383. concatenatedProperties: null,
  10384. /**
  10385. Destroyed object property flag.
  10386. if this property is `true` the observers and bindings were already
  10387. removed by the effect of calling the `destroy()` method.
  10388. @property isDestroyed
  10389. @default false
  10390. */
  10391. isDestroyed: false,
  10392. /**
  10393. Destruction scheduled flag. The `destroy()` method has been called.
  10394. The object stays intact until the end of the run loop at which point
  10395. the `isDestroyed` flag is set.
  10396. @property isDestroying
  10397. @default false
  10398. */
  10399. isDestroying: false,
  10400. /**
  10401. Destroys an object by setting the `isDestroyed` flag and removing its
  10402. metadata, which effectively destroys observers and bindings.
  10403. If you try to set a property on a destroyed object, an exception will be
  10404. raised.
  10405. Note that destruction is scheduled for the end of the run loop and does not
  10406. happen immediately. It will set an isDestroying flag immediately.
  10407. @method destroy
  10408. @return {Ember.Object} receiver
  10409. */
  10410. destroy: function() {
  10411. if (this.isDestroying) { return; }
  10412. this.isDestroying = true;
  10413. schedule('actions', this, this.willDestroy);
  10414. schedule('destroy', this, this._scheduledDestroy);
  10415. return this;
  10416. },
  10417. /**
  10418. Override to implement teardown.
  10419. @method willDestroy
  10420. */
  10421. willDestroy: Ember.K,
  10422. /**
  10423. Invoked by the run loop to actually destroy the object. This is
  10424. scheduled for execution by the `destroy` method.
  10425. @private
  10426. @method _scheduledDestroy
  10427. */
  10428. _scheduledDestroy: function() {
  10429. if (this.isDestroyed) { return; }
  10430. destroy(this);
  10431. this.isDestroyed = true;
  10432. },
  10433. bind: function(to, from) {
  10434. if (!(from instanceof Ember.Binding)) { from = Ember.Binding.from(from); }
  10435. from.to(to).connect(this);
  10436. return from;
  10437. },
  10438. /**
  10439. Returns a string representation which attempts to provide more information
  10440. than Javascript's `toString` typically does, in a generic way for all Ember
  10441. objects.
  10442. ```javascript
  10443. App.Person = Em.Object.extend()
  10444. person = App.Person.create()
  10445. person.toString() //=> "<App.Person:ember1024>"
  10446. ```
  10447. If the object's class is not defined on an Ember namespace, it will
  10448. indicate it is a subclass of the registered superclass:
  10449. ```javascript
  10450. Student = App.Person.extend()
  10451. student = Student.create()
  10452. student.toString() //=> "<(subclass of App.Person):ember1025>"
  10453. ```
  10454. If the method `toStringExtension` is defined, its return value will be
  10455. included in the output.
  10456. ```javascript
  10457. App.Teacher = App.Person.extend({
  10458. toStringExtension: function() {
  10459. return this.get('fullName');
  10460. }
  10461. });
  10462. teacher = App.Teacher.create()
  10463. teacher.toString(); //=> "<App.Teacher:ember1026:Tom Dale>"
  10464. ```
  10465. @method toString
  10466. @return {String} string representation
  10467. */
  10468. toString: function toString() {
  10469. var hasToStringExtension = typeof this.toStringExtension === 'function',
  10470. extension = hasToStringExtension ? ":" + this.toStringExtension() : '';
  10471. var ret = '<'+this.constructor.toString()+':'+guidFor(this)+extension+'>';
  10472. this.toString = makeToString(ret);
  10473. return ret;
  10474. }
  10475. });
  10476. CoreObject.PrototypeMixin.ownerConstructor = CoreObject;
  10477. function makeToString(ret) {
  10478. return function() { return ret; };
  10479. }
  10480. if (Ember.config.overridePrototypeMixin) {
  10481. Ember.config.overridePrototypeMixin(CoreObject.PrototypeMixin);
  10482. }
  10483. CoreObject.__super__ = null;
  10484. var ClassMixin = Mixin.create({
  10485. ClassMixin: Ember.required(),
  10486. PrototypeMixin: Ember.required(),
  10487. isClass: true,
  10488. isMethod: false,
  10489. /**
  10490. Creates a new subclass.
  10491. ```javascript
  10492. App.Person = Ember.Object.extend({
  10493. say: function(thing) {
  10494. alert(thing);
  10495. }
  10496. });
  10497. ```
  10498. This defines a new subclass of Ember.Object: `App.Person`. It contains one method: `say()`.
  10499. You can also create a subclass from any existing class by calling its `extend()` method. For example, you might want to create a subclass of Ember's built-in `Ember.View` class:
  10500. ```javascript
  10501. App.PersonView = Ember.View.extend({
  10502. tagName: 'li',
  10503. classNameBindings: ['isAdministrator']
  10504. });
  10505. ```
  10506. When defining a subclass, you can override methods but still access the implementation of your parent class by calling the special `_super()` method:
  10507. ```javascript
  10508. App.Person = Ember.Object.extend({
  10509. say: function(thing) {
  10510. var name = this.get('name');
  10511. alert(name + ' says: ' + thing);
  10512. }
  10513. });
  10514. App.Soldier = App.Person.extend({
  10515. say: function(thing) {
  10516. this._super(thing + ", sir!");
  10517. },
  10518. march: function(numberOfHours) {
  10519. alert(this.get('name') + ' marches for ' + numberOfHours + ' hours.')
  10520. }
  10521. });
  10522. var yehuda = App.Soldier.create({
  10523. name: "Yehuda Katz"
  10524. });
  10525. yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!"
  10526. ```
  10527. The `create()` on line #17 creates an *instance* of the `App.Soldier` class. The `extend()` on line #8 creates a *subclass* of `App.Person`. Any instance of the `App.Person` class will *not* have the `march()` method.
  10528. You can also pass `Ember.Mixin` classes to add additional properties to the subclass.
  10529. ```javascript
  10530. App.Person = Ember.Object.extend({
  10531. say: function(thing) {
  10532. alert(this.get('name') + ' says: ' + thing);
  10533. }
  10534. });
  10535. App.SingingMixin = Ember.Mixin.create({
  10536. sing: function(thing){
  10537. alert(this.get('name') + ' sings: la la la ' + thing);
  10538. }
  10539. });
  10540. App.BroadwayStar = App.Person.extend(App.SingingMixin, {
  10541. dance: function() {
  10542. alert(this.get('name') + ' dances: tap tap tap tap ');
  10543. }
  10544. });
  10545. ```
  10546. The `App.BroadwayStar` class contains three methods: `say()`, `sing()`, and `dance()`.
  10547. @method extend
  10548. @static
  10549. @param {Ember.Mixin} [mixins]* One or more Ember.Mixin classes
  10550. @param {Object} [arguments]* Object containing values to use within the new class
  10551. */
  10552. extend: function() {
  10553. var Class = makeCtor(), proto;
  10554. Class.ClassMixin = Mixin.create(this.ClassMixin);
  10555. Class.PrototypeMixin = Mixin.create(this.PrototypeMixin);
  10556. Class.ClassMixin.ownerConstructor = Class;
  10557. Class.PrototypeMixin.ownerConstructor = Class;
  10558. reopen.apply(Class.PrototypeMixin, arguments);
  10559. Class.superclass = this;
  10560. Class.__super__ = this.prototype;
  10561. proto = Class.prototype = o_create(this.prototype);
  10562. proto.constructor = Class;
  10563. generateGuid(proto);
  10564. meta(proto).proto = proto; // this will disable observers on prototype
  10565. Class.ClassMixin.apply(Class);
  10566. return Class;
  10567. },
  10568. /**
  10569. Equivalent to doing `extend(arguments).create()`.
  10570. If possible use the normal `create` method instead.
  10571. @method createWithMixins
  10572. @static
  10573. @param [arguments]*
  10574. */
  10575. createWithMixins: function() {
  10576. var C = this;
  10577. if (arguments.length>0) { this._initMixins(arguments); }
  10578. return new C();
  10579. },
  10580. /**
  10581. Creates an instance of a class. Accepts either no arguments, or an object
  10582. containing values to initialize the newly instantiated object with.
  10583. ```javascript
  10584. App.Person = Ember.Object.extend({
  10585. helloWorld: function() {
  10586. alert("Hi, my name is " + this.get('name'));
  10587. }
  10588. });
  10589. var tom = App.Person.create({
  10590. name: 'Tom Dale'
  10591. });
  10592. tom.helloWorld(); // alerts "Hi, my name is Tom Dale".
  10593. ```
  10594. `create` will call the `init` function if defined during
  10595. `Ember.AnyObject.extend`
  10596. If no arguments are passed to `create`, it will not set values to the new
  10597. instance during initialization:
  10598. ```javascript
  10599. var noName = App.Person.create();
  10600. noName.helloWorld(); // alerts undefined
  10601. ```
  10602. NOTE: For performance reasons, you cannot declare methods or computed
  10603. properties during `create`. You should instead declare methods and computed
  10604. properties when using `extend` or use the `createWithMixins` shorthand.
  10605. @method create
  10606. @static
  10607. @param [arguments]*
  10608. */
  10609. create: function() {
  10610. var C = this;
  10611. if (arguments.length>0) { this._initProperties(arguments); }
  10612. return new C();
  10613. },
  10614. /**
  10615. Augments a constructor's prototype with additional
  10616. properties and functions:
  10617. ```javascript
  10618. MyObject = Ember.Object.extend({
  10619. name: 'an object'
  10620. });
  10621. o = MyObject.create();
  10622. o.get('name'); // 'an object'
  10623. MyObject.reopen({
  10624. say: function(msg){
  10625. console.log(msg);
  10626. }
  10627. })
  10628. o2 = MyObject.create();
  10629. o2.say("hello"); // logs "hello"
  10630. o.say("goodbye"); // logs "goodbye"
  10631. ```
  10632. To add functions and properties to the constructor itself,
  10633. see `reopenClass`
  10634. @method reopen
  10635. */
  10636. reopen: function() {
  10637. this.willReopen();
  10638. reopen.apply(this.PrototypeMixin, arguments);
  10639. return this;
  10640. },
  10641. /**
  10642. Augments a constructor's own properties and functions:
  10643. ```javascript
  10644. MyObject = Ember.Object.extend({
  10645. name: 'an object'
  10646. });
  10647. MyObject.reopenClass({
  10648. canBuild: false
  10649. });
  10650. MyObject.canBuild; // false
  10651. o = MyObject.create();
  10652. ```
  10653. In other words, this creates static properties and functions for the class. These are only available on the class
  10654. and not on any instance of that class.
  10655. ```javascript
  10656. App.Person = Ember.Object.extend({
  10657. name : "",
  10658. sayHello : function(){
  10659. alert("Hello. My name is " + this.get('name'));
  10660. }
  10661. });
  10662. App.Person.reopenClass({
  10663. species : "Homo sapiens",
  10664. createPerson: function(newPersonsName){
  10665. return App.Person.create({
  10666. name:newPersonsName
  10667. });
  10668. }
  10669. });
  10670. var tom = App.Person.create({
  10671. name : "Tom Dale"
  10672. });
  10673. var yehuda = App.Person.createPerson("Yehuda Katz");
  10674. tom.sayHello(); // "Hello. My name is Tom Dale"
  10675. yehuda.sayHello(); // "Hello. My name is Yehuda Katz"
  10676. alert(App.Person.species); // "Homo sapiens"
  10677. ```
  10678. Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda`
  10679. variables. They are only valid on `App.Person`.
  10680. To add functions and properties to instances of
  10681. a constructor by extending the constructor's prototype
  10682. see `reopen`
  10683. @method reopenClass
  10684. */
  10685. reopenClass: function() {
  10686. reopen.apply(this.ClassMixin, arguments);
  10687. applyMixin(this, arguments, false);
  10688. return this;
  10689. },
  10690. detect: function(obj) {
  10691. if ('function' !== typeof obj) { return false; }
  10692. while(obj) {
  10693. if (obj===this) { return true; }
  10694. obj = obj.superclass;
  10695. }
  10696. return false;
  10697. },
  10698. detectInstance: function(obj) {
  10699. return obj instanceof this;
  10700. },
  10701. /**
  10702. In some cases, you may want to annotate computed properties with additional
  10703. metadata about how they function or what values they operate on. For
  10704. example, computed property functions may close over variables that are then
  10705. no longer available for introspection.
  10706. You can pass a hash of these values to a computed property like this:
  10707. ```javascript
  10708. person: function() {
  10709. var personId = this.get('personId');
  10710. return App.Person.create({ id: personId });
  10711. }.property().meta({ type: App.Person })
  10712. ```
  10713. Once you've done this, you can retrieve the values saved to the computed
  10714. property from your class like this:
  10715. ```javascript
  10716. MyClass.metaForProperty('person');
  10717. ```
  10718. This will return the original hash that was passed to `meta()`.
  10719. @method metaForProperty
  10720. @param key {String} property name
  10721. */
  10722. metaForProperty: function(key) {
  10723. var meta = this.proto()[META_KEY],
  10724. desc = meta && meta.descs[key];
  10725. Ember.assert("metaForProperty() could not find a computed property with key '"+key+"'.", !!desc && desc instanceof Ember.ComputedProperty);
  10726. return desc._meta || {};
  10727. },
  10728. /**
  10729. Iterate over each computed property for the class, passing its name
  10730. and any associated metadata (see `metaForProperty`) to the callback.
  10731. @method eachComputedProperty
  10732. @param {Function} callback
  10733. @param {Object} binding
  10734. */
  10735. eachComputedProperty: function(callback, binding) {
  10736. var proto = this.proto(),
  10737. descs = meta(proto).descs,
  10738. empty = {},
  10739. property;
  10740. for (var name in descs) {
  10741. property = descs[name];
  10742. if (property instanceof Ember.ComputedProperty) {
  10743. callback.call(binding || this, name, property._meta || empty);
  10744. }
  10745. }
  10746. }
  10747. });
  10748. ClassMixin.ownerConstructor = CoreObject;
  10749. if (Ember.config.overrideClassMixin) {
  10750. Ember.config.overrideClassMixin(ClassMixin);
  10751. }
  10752. CoreObject.ClassMixin = ClassMixin;
  10753. ClassMixin.apply(CoreObject);
  10754. Ember.CoreObject = CoreObject;
  10755. })();
  10756. (function() {
  10757. /**
  10758. @module ember
  10759. @submodule ember-runtime
  10760. */
  10761. /**
  10762. `Ember.Object` is the main base class for all Ember objects. It is a subclass
  10763. of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details,
  10764. see the documentation for each of these.
  10765. @class Object
  10766. @namespace Ember
  10767. @extends Ember.CoreObject
  10768. @uses Ember.Observable
  10769. */
  10770. Ember.Object = Ember.CoreObject.extend(Ember.Observable);
  10771. Ember.Object.toString = function() { return "Ember.Object"; };
  10772. })();
  10773. (function() {
  10774. /**
  10775. @module ember
  10776. @submodule ember-runtime
  10777. */
  10778. var get = Ember.get, indexOf = Ember.ArrayPolyfills.indexOf;
  10779. /**
  10780. A Namespace is an object usually used to contain other objects or methods
  10781. such as an application or framework. Create a namespace anytime you want
  10782. to define one of these new containers.
  10783. # Example Usage
  10784. ```javascript
  10785. MyFramework = Ember.Namespace.create({
  10786. VERSION: '1.0.0'
  10787. });
  10788. ```
  10789. @class Namespace
  10790. @namespace Ember
  10791. @extends Ember.Object
  10792. */
  10793. var Namespace = Ember.Namespace = Ember.Object.extend({
  10794. isNamespace: true,
  10795. init: function() {
  10796. Ember.Namespace.NAMESPACES.push(this);
  10797. Ember.Namespace.PROCESSED = false;
  10798. },
  10799. toString: function() {
  10800. var name = get(this, 'name');
  10801. if (name) { return name; }
  10802. findNamespaces();
  10803. return this[Ember.GUID_KEY+'_name'];
  10804. },
  10805. nameClasses: function() {
  10806. processNamespace([this.toString()], this, {});
  10807. },
  10808. destroy: function() {
  10809. var namespaces = Ember.Namespace.NAMESPACES;
  10810. Ember.lookup[this.toString()] = undefined;
  10811. namespaces.splice(indexOf.call(namespaces, this), 1);
  10812. this._super();
  10813. }
  10814. });
  10815. Namespace.reopenClass({
  10816. NAMESPACES: [Ember],
  10817. NAMESPACES_BY_ID: {},
  10818. PROCESSED: false,
  10819. processAll: processAllNamespaces,
  10820. byName: function(name) {
  10821. if (!Ember.BOOTED) {
  10822. processAllNamespaces();
  10823. }
  10824. return NAMESPACES_BY_ID[name];
  10825. }
  10826. });
  10827. var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID;
  10828. var hasOwnProp = ({}).hasOwnProperty,
  10829. guidFor = Ember.guidFor;
  10830. function processNamespace(paths, root, seen) {
  10831. var idx = paths.length;
  10832. NAMESPACES_BY_ID[paths.join('.')] = root;
  10833. // Loop over all of the keys in the namespace, looking for classes
  10834. for(var key in root) {
  10835. if (!hasOwnProp.call(root, key)) { continue; }
  10836. var obj = root[key];
  10837. // If we are processing the `Ember` namespace, for example, the
  10838. // `paths` will start with `["Ember"]`. Every iteration through
  10839. // the loop will update the **second** element of this list with
  10840. // the key, so processing `Ember.View` will make the Array
  10841. // `['Ember', 'View']`.
  10842. paths[idx] = key;
  10843. // If we have found an unprocessed class
  10844. if (obj && obj.toString === classToString) {
  10845. // Replace the class' `toString` with the dot-separated path
  10846. // and set its `NAME_KEY`
  10847. obj.toString = makeToString(paths.join('.'));
  10848. obj[NAME_KEY] = paths.join('.');
  10849. // Support nested namespaces
  10850. } else if (obj && obj.isNamespace) {
  10851. // Skip aliased namespaces
  10852. if (seen[guidFor(obj)]) { continue; }
  10853. seen[guidFor(obj)] = true;
  10854. // Process the child namespace
  10855. processNamespace(paths, obj, seen);
  10856. }
  10857. }
  10858. paths.length = idx; // cut out last item
  10859. }
  10860. function findNamespaces() {
  10861. var Namespace = Ember.Namespace, lookup = Ember.lookup, obj, isNamespace;
  10862. if (Namespace.PROCESSED) { return; }
  10863. for (var prop in lookup) {
  10864. // These don't raise exceptions but can cause warnings
  10865. if (prop === "parent" || prop === "top" || prop === "frameElement" || prop === "webkitStorageInfo") { continue; }
  10866. // get(window.globalStorage, 'isNamespace') would try to read the storage for domain isNamespace and cause exception in Firefox.
  10867. // globalStorage is a storage obsoleted by the WhatWG storage specification. See https://developer.mozilla.org/en/DOM/Storage#globalStorage
  10868. if (prop === "globalStorage" && lookup.StorageList && lookup.globalStorage instanceof lookup.StorageList) { continue; }
  10869. // Unfortunately, some versions of IE don't support window.hasOwnProperty
  10870. if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { continue; }
  10871. // At times we are not allowed to access certain properties for security reasons.
  10872. // There are also times where even if we can access them, we are not allowed to access their properties.
  10873. try {
  10874. obj = Ember.lookup[prop];
  10875. isNamespace = obj && obj.isNamespace;
  10876. } catch (e) {
  10877. continue;
  10878. }
  10879. if (isNamespace) {
  10880. Ember.deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop));
  10881. obj[NAME_KEY] = prop;
  10882. }
  10883. }
  10884. }
  10885. var NAME_KEY = Ember.NAME_KEY = Ember.GUID_KEY + '_name';
  10886. function superClassString(mixin) {
  10887. var superclass = mixin.superclass;
  10888. if (superclass) {
  10889. if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; }
  10890. else { return superClassString(superclass); }
  10891. } else {
  10892. return;
  10893. }
  10894. }
  10895. function classToString() {
  10896. if (!Ember.BOOTED && !this[NAME_KEY]) {
  10897. processAllNamespaces();
  10898. }
  10899. var ret;
  10900. if (this[NAME_KEY]) {
  10901. ret = this[NAME_KEY];
  10902. } else if (this._toString) {
  10903. ret = this._toString;
  10904. } else {
  10905. var str = superClassString(this);
  10906. if (str) {
  10907. ret = "(subclass of " + str + ")";
  10908. } else {
  10909. ret = "(unknown mixin)";
  10910. }
  10911. this.toString = makeToString(ret);
  10912. }
  10913. return ret;
  10914. }
  10915. function processAllNamespaces() {
  10916. var unprocessedNamespaces = !Namespace.PROCESSED,
  10917. unprocessedMixins = Ember.anyUnprocessedMixins;
  10918. if (unprocessedNamespaces) {
  10919. findNamespaces();
  10920. Namespace.PROCESSED = true;
  10921. }
  10922. if (unprocessedNamespaces || unprocessedMixins) {
  10923. var namespaces = Namespace.NAMESPACES, namespace;
  10924. for (var i=0, l=namespaces.length; i<l; i++) {
  10925. namespace = namespaces[i];
  10926. processNamespace([namespace.toString()], namespace, {});
  10927. }
  10928. Ember.anyUnprocessedMixins = false;
  10929. }
  10930. }
  10931. function makeToString(ret) {
  10932. return function() { return ret; };
  10933. }
  10934. Ember.Mixin.prototype.toString = classToString;
  10935. })();
  10936. (function() {
  10937. /**
  10938. @module ember
  10939. @submodule ember-runtime
  10940. */
  10941. var get = Ember.get,
  10942. set = Ember.set,
  10943. fmt = Ember.String.fmt,
  10944. addBeforeObserver = Ember.addBeforeObserver,
  10945. addObserver = Ember.addObserver,
  10946. removeBeforeObserver = Ember.removeBeforeObserver,
  10947. removeObserver = Ember.removeObserver,
  10948. propertyWillChange = Ember.propertyWillChange,
  10949. propertyDidChange = Ember.propertyDidChange,
  10950. meta = Ember.meta,
  10951. defineProperty = Ember.defineProperty;
  10952. function contentPropertyWillChange(content, contentKey) {
  10953. var key = contentKey.slice(8); // remove "content."
  10954. if (key in this) { return; } // if shadowed in proxy
  10955. propertyWillChange(this, key);
  10956. }
  10957. function contentPropertyDidChange(content, contentKey) {
  10958. var key = contentKey.slice(8); // remove "content."
  10959. if (key in this) { return; } // if shadowed in proxy
  10960. propertyDidChange(this, key);
  10961. }
  10962. /**
  10963. `Ember.ObjectProxy` forwards all properties not defined by the proxy itself
  10964. to a proxied `content` object.
  10965. ```javascript
  10966. object = Ember.Object.create({
  10967. name: 'Foo'
  10968. });
  10969. proxy = Ember.ObjectProxy.create({
  10970. content: object
  10971. });
  10972. // Access and change existing properties
  10973. proxy.get('name') // 'Foo'
  10974. proxy.set('name', 'Bar');
  10975. object.get('name') // 'Bar'
  10976. // Create new 'description' property on `object`
  10977. proxy.set('description', 'Foo is a whizboo baz');
  10978. object.get('description') // 'Foo is a whizboo baz'
  10979. ```
  10980. While `content` is unset, setting a property to be delegated will throw an
  10981. Error.
  10982. ```javascript
  10983. proxy = Ember.ObjectProxy.create({
  10984. content: null,
  10985. flag: null
  10986. });
  10987. proxy.set('flag', true);
  10988. proxy.get('flag'); // true
  10989. proxy.get('foo'); // undefined
  10990. proxy.set('foo', 'data'); // throws Error
  10991. ```
  10992. Delegated properties can be bound to and will change when content is updated.
  10993. Computed properties on the proxy itself can depend on delegated properties.
  10994. ```javascript
  10995. ProxyWithComputedProperty = Ember.ObjectProxy.extend({
  10996. fullName: function () {
  10997. var firstName = this.get('firstName'),
  10998. lastName = this.get('lastName');
  10999. if (firstName && lastName) {
  11000. return firstName + ' ' + lastName;
  11001. }
  11002. return firstName || lastName;
  11003. }.property('firstName', 'lastName')
  11004. });
  11005. proxy = ProxyWithComputedProperty.create();
  11006. proxy.get('fullName'); // undefined
  11007. proxy.set('content', {
  11008. firstName: 'Tom', lastName: 'Dale'
  11009. }); // triggers property change for fullName on proxy
  11010. proxy.get('fullName'); // 'Tom Dale'
  11011. ```
  11012. @class ObjectProxy
  11013. @namespace Ember
  11014. @extends Ember.Object
  11015. */
  11016. Ember.ObjectProxy = Ember.Object.extend({
  11017. /**
  11018. The object whose properties will be forwarded.
  11019. @property content
  11020. @type Ember.Object
  11021. @default null
  11022. */
  11023. content: null,
  11024. _contentDidChange: Ember.observer('content', function() {
  11025. Ember.assert("Can't set ObjectProxy's content to itself", this.get('content') !== this);
  11026. }),
  11027. isTruthy: Ember.computed.bool('content'),
  11028. _debugContainerKey: null,
  11029. willWatchProperty: function (key) {
  11030. var contentKey = 'content.' + key;
  11031. addBeforeObserver(this, contentKey, null, contentPropertyWillChange);
  11032. addObserver(this, contentKey, null, contentPropertyDidChange);
  11033. },
  11034. didUnwatchProperty: function (key) {
  11035. var contentKey = 'content.' + key;
  11036. removeBeforeObserver(this, contentKey, null, contentPropertyWillChange);
  11037. removeObserver(this, contentKey, null, contentPropertyDidChange);
  11038. },
  11039. unknownProperty: function (key) {
  11040. var content = get(this, 'content');
  11041. if (content) {
  11042. return get(content, key);
  11043. }
  11044. },
  11045. setUnknownProperty: function (key, value) {
  11046. var m = meta(this);
  11047. if (m.proto === this) {
  11048. // if marked as prototype then just defineProperty
  11049. // rather than delegate
  11050. defineProperty(this, key, null, value);
  11051. return value;
  11052. }
  11053. var content = get(this, 'content');
  11054. Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of object proxy %@: its 'content' is undefined.", [key, value, this]), content);
  11055. return set(content, key, value);
  11056. }
  11057. });
  11058. })();
  11059. (function() {
  11060. /**
  11061. @module ember
  11062. @submodule ember-runtime
  11063. */
  11064. // ..........................................................
  11065. // HELPERS
  11066. //
  11067. var get = Ember.get, set = Ember.set;
  11068. var a_slice = Array.prototype.slice;
  11069. var a_indexOf = Ember.EnumerableUtils.indexOf;
  11070. var contexts = [];
  11071. function popCtx() {
  11072. return contexts.length===0 ? {} : contexts.pop();
  11073. }
  11074. function pushCtx(ctx) {
  11075. contexts.push(ctx);
  11076. return null;
  11077. }
  11078. function iter(key, value) {
  11079. var valueProvided = arguments.length === 2;
  11080. function i(item) {
  11081. var cur = get(item, key);
  11082. return valueProvided ? value===cur : !!cur;
  11083. }
  11084. return i ;
  11085. }
  11086. /**
  11087. This mixin defines the common interface implemented by enumerable objects
  11088. in Ember. Most of these methods follow the standard Array iteration
  11089. API defined up to JavaScript 1.8 (excluding language-specific features that
  11090. cannot be emulated in older versions of JavaScript).
  11091. This mixin is applied automatically to the Array class on page load, so you
  11092. can use any of these methods on simple arrays. If Array already implements
  11093. one of these methods, the mixin will not override them.
  11094. ## Writing Your Own Enumerable
  11095. To make your own custom class enumerable, you need two items:
  11096. 1. You must have a length property. This property should change whenever
  11097. the number of items in your enumerable object changes. If you use this
  11098. with an `Ember.Object` subclass, you should be sure to change the length
  11099. property using `set().`
  11100. 2. You must implement `nextObject().` See documentation.
  11101. Once you have these two methods implemented, apply the `Ember.Enumerable` mixin
  11102. to your class and you will be able to enumerate the contents of your object
  11103. like any other collection.
  11104. ## Using Ember Enumeration with Other Libraries
  11105. Many other libraries provide some kind of iterator or enumeration like
  11106. facility. This is often where the most common API conflicts occur.
  11107. Ember's API is designed to be as friendly as possible with other
  11108. libraries by implementing only methods that mostly correspond to the
  11109. JavaScript 1.8 API.
  11110. @class Enumerable
  11111. @namespace Ember
  11112. @since Ember 0.9
  11113. */
  11114. Ember.Enumerable = Ember.Mixin.create({
  11115. /**
  11116. Implement this method to make your class enumerable.
  11117. This method will be call repeatedly during enumeration. The index value
  11118. will always begin with 0 and increment monotonically. You don't have to
  11119. rely on the index value to determine what object to return, but you should
  11120. always check the value and start from the beginning when you see the
  11121. requested index is 0.
  11122. The `previousObject` is the object that was returned from the last call
  11123. to `nextObject` for the current iteration. This is a useful way to
  11124. manage iteration if you are tracing a linked list, for example.
  11125. Finally the context parameter will always contain a hash you can use as
  11126. a "scratchpad" to maintain any other state you need in order to iterate
  11127. properly. The context object is reused and is not reset between
  11128. iterations so make sure you setup the context with a fresh state whenever
  11129. the index parameter is 0.
  11130. Generally iterators will continue to call `nextObject` until the index
  11131. reaches the your current length-1. If you run out of data before this
  11132. time for some reason, you should simply return undefined.
  11133. The default implementation of this method simply looks up the index.
  11134. This works great on any Array-like objects.
  11135. @method nextObject
  11136. @param {Number} index the current index of the iteration
  11137. @param {Object} previousObject the value returned by the last call to
  11138. `nextObject`.
  11139. @param {Object} context a context object you can use to maintain state.
  11140. @return {Object} the next object in the iteration or undefined
  11141. */
  11142. nextObject: Ember.required(Function),
  11143. /**
  11144. Helper method returns the first object from a collection. This is usually
  11145. used by bindings and other parts of the framework to extract a single
  11146. object if the enumerable contains only one item.
  11147. If you override this method, you should implement it so that it will
  11148. always return the same value each time it is called. If your enumerable
  11149. contains only one object, this method should always return that object.
  11150. If your enumerable is empty, this method should return `undefined`.
  11151. ```javascript
  11152. var arr = ["a", "b", "c"];
  11153. arr.get('firstObject'); // "a"
  11154. var arr = [];
  11155. arr.get('firstObject'); // undefined
  11156. ```
  11157. @property firstObject
  11158. @return {Object} the object or undefined
  11159. */
  11160. firstObject: Ember.computed(function() {
  11161. if (get(this, 'length')===0) return undefined ;
  11162. // handle generic enumerables
  11163. var context = popCtx(), ret;
  11164. ret = this.nextObject(0, null, context);
  11165. pushCtx(context);
  11166. return ret ;
  11167. }).property('[]'),
  11168. /**
  11169. Helper method returns the last object from a collection. If your enumerable
  11170. contains only one object, this method should always return that object.
  11171. If your enumerable is empty, this method should return `undefined`.
  11172. ```javascript
  11173. var arr = ["a", "b", "c"];
  11174. arr.get('lastObject'); // "c"
  11175. var arr = [];
  11176. arr.get('lastObject'); // undefined
  11177. ```
  11178. @property lastObject
  11179. @return {Object} the last object or undefined
  11180. */
  11181. lastObject: Ember.computed(function() {
  11182. var len = get(this, 'length');
  11183. if (len===0) return undefined ;
  11184. var context = popCtx(), idx=0, cur, last = null;
  11185. do {
  11186. last = cur;
  11187. cur = this.nextObject(idx++, last, context);
  11188. } while (cur !== undefined);
  11189. pushCtx(context);
  11190. return last;
  11191. }).property('[]'),
  11192. /**
  11193. Returns `true` if the passed object can be found in the receiver. The
  11194. default version will iterate through the enumerable until the object
  11195. is found. You may want to override this with a more efficient version.
  11196. ```javascript
  11197. var arr = ["a", "b", "c"];
  11198. arr.contains("a"); // true
  11199. arr.contains("z"); // false
  11200. ```
  11201. @method contains
  11202. @param {Object} obj The object to search for.
  11203. @return {Boolean} `true` if object is found in enumerable.
  11204. */
  11205. contains: function(obj) {
  11206. return this.find(function(item) { return item===obj; }) !== undefined;
  11207. },
  11208. /**
  11209. Iterates through the enumerable, calling the passed function on each
  11210. item. This method corresponds to the `forEach()` method defined in
  11211. JavaScript 1.6.
  11212. The callback method you provide should have the following signature (all
  11213. parameters are optional):
  11214. ```javascript
  11215. function(item, index, enumerable);
  11216. ```
  11217. - `item` is the current item in the iteration.
  11218. - `index` is the current index in the iteration.
  11219. - `enumerable` is the enumerable object itself.
  11220. Note that in addition to a callback, you can also pass an optional target
  11221. object that will be set as `this` on the context. This is a good way
  11222. to give your iterator function access to the current object.
  11223. @method forEach
  11224. @param {Function} callback The callback to execute
  11225. @param {Object} [target] The target object to use
  11226. @return {Object} receiver
  11227. */
  11228. forEach: function(callback, target) {
  11229. if (typeof callback !== "function") throw new TypeError() ;
  11230. var len = get(this, 'length'), last = null, context = popCtx();
  11231. if (target === undefined) target = null;
  11232. for(var idx=0;idx<len;idx++) {
  11233. var next = this.nextObject(idx, last, context) ;
  11234. callback.call(target, next, idx, this);
  11235. last = next ;
  11236. }
  11237. last = null ;
  11238. context = pushCtx(context);
  11239. return this ;
  11240. },
  11241. /**
  11242. Alias for `mapBy`
  11243. @method getEach
  11244. @param {String} key name of the property
  11245. @return {Array} The mapped array.
  11246. */
  11247. getEach: function(key) {
  11248. return this.mapBy(key);
  11249. },
  11250. /**
  11251. Sets the value on the named property for each member. This is more
  11252. efficient than using other methods defined on this helper. If the object
  11253. implements Ember.Observable, the value will be changed to `set(),` otherwise
  11254. it will be set directly. `null` objects are skipped.
  11255. @method setEach
  11256. @param {String} key The key to set
  11257. @param {Object} value The object to set
  11258. @return {Object} receiver
  11259. */
  11260. setEach: function(key, value) {
  11261. return this.forEach(function(item) {
  11262. set(item, key, value);
  11263. });
  11264. },
  11265. /**
  11266. Maps all of the items in the enumeration to another value, returning
  11267. a new array. This method corresponds to `map()` defined in JavaScript 1.6.
  11268. The callback method you provide should have the following signature (all
  11269. parameters are optional):
  11270. ```javascript
  11271. function(item, index, enumerable);
  11272. ```
  11273. - `item` is the current item in the iteration.
  11274. - `index` is the current index in the iteration.
  11275. - `enumerable` is the enumerable object itself.
  11276. It should return the mapped value.
  11277. Note that in addition to a callback, you can also pass an optional target
  11278. object that will be set as `this` on the context. This is a good way
  11279. to give your iterator function access to the current object.
  11280. @method map
  11281. @param {Function} callback The callback to execute
  11282. @param {Object} [target] The target object to use
  11283. @return {Array} The mapped array.
  11284. */
  11285. map: function(callback, target) {
  11286. var ret = Ember.A();
  11287. this.forEach(function(x, idx, i) {
  11288. ret[idx] = callback.call(target, x, idx,i);
  11289. });
  11290. return ret ;
  11291. },
  11292. /**
  11293. Similar to map, this specialized function returns the value of the named
  11294. property on all items in the enumeration.
  11295. @method mapBy
  11296. @param {String} key name of the property
  11297. @return {Array} The mapped array.
  11298. */
  11299. mapBy: function(key) {
  11300. return this.map(function(next) {
  11301. return get(next, key);
  11302. });
  11303. },
  11304. /**
  11305. Similar to map, this specialized function returns the value of the named
  11306. property on all items in the enumeration.
  11307. @method mapProperty
  11308. @param {String} key name of the property
  11309. @return {Array} The mapped array.
  11310. @deprecated Use `mapBy` instead
  11311. */
  11312. mapProperty: Ember.aliasMethod('mapBy'),
  11313. /**
  11314. Returns an array with all of the items in the enumeration that the passed
  11315. function returns true for. This method corresponds to `filter()` defined in
  11316. JavaScript 1.6.
  11317. The callback method you provide should have the following signature (all
  11318. parameters are optional):
  11319. ```javascript
  11320. function(item, index, enumerable);
  11321. ```
  11322. - `item` is the current item in the iteration.
  11323. - `index` is the current index in the iteration.
  11324. - `enumerable` is the enumerable object itself.
  11325. It should return the `true` to include the item in the results, `false`
  11326. otherwise.
  11327. Note that in addition to a callback, you can also pass an optional target
  11328. object that will be set as `this` on the context. This is a good way
  11329. to give your iterator function access to the current object.
  11330. @method filter
  11331. @param {Function} callback The callback to execute
  11332. @param {Object} [target] The target object to use
  11333. @return {Array} A filtered array.
  11334. */
  11335. filter: function(callback, target) {
  11336. var ret = Ember.A();
  11337. this.forEach(function(x, idx, i) {
  11338. if (callback.call(target, x, idx, i)) ret.push(x);
  11339. });
  11340. return ret ;
  11341. },
  11342. /**
  11343. Returns an array with all of the items in the enumeration where the passed
  11344. function returns false for. This method is the inverse of filter().
  11345. The callback method you provide should have the following signature (all
  11346. parameters are optional):
  11347. ```javascript
  11348. function(item, index, enumerable);
  11349. ```
  11350. - *item* is the current item in the iteration.
  11351. - *index* is the current index in the iteration
  11352. - *enumerable* is the enumerable object itself.
  11353. It should return the a falsey value to include the item in the results.
  11354. Note that in addition to a callback, you can also pass an optional target
  11355. object that will be set as "this" on the context. This is a good way
  11356. to give your iterator function access to the current object.
  11357. @method reject
  11358. @param {Function} callback The callback to execute
  11359. @param {Object} [target] The target object to use
  11360. @return {Array} A rejected array.
  11361. */
  11362. reject: function(callback, target) {
  11363. return this.filter(function() {
  11364. return !(callback.apply(target, arguments));
  11365. });
  11366. },
  11367. /**
  11368. Returns an array with just the items with the matched property. You
  11369. can pass an optional second argument with the target value. Otherwise
  11370. this will match any property that evaluates to `true`.
  11371. @method filterBy
  11372. @param {String} key the property to test
  11373. @param {String} [value] optional value to test against.
  11374. @return {Array} filtered array
  11375. */
  11376. filterBy: function(key, value) {
  11377. return this.filter(iter.apply(this, arguments));
  11378. },
  11379. /**
  11380. Returns an array with just the items with the matched property. You
  11381. can pass an optional second argument with the target value. Otherwise
  11382. this will match any property that evaluates to `true`.
  11383. @method filterProperty
  11384. @param {String} key the property to test
  11385. @param {String} [value] optional value to test against.
  11386. @return {Array} filtered array
  11387. @deprecated Use `filterBy` instead
  11388. */
  11389. filterProperty: Ember.aliasMethod('filterBy'),
  11390. /**
  11391. Returns an array with the items that do not have truthy values for
  11392. key. You can pass an optional second argument with the target value. Otherwise
  11393. this will match any property that evaluates to false.
  11394. @method rejectBy
  11395. @param {String} key the property to test
  11396. @param {String} [value] optional value to test against.
  11397. @return {Array} rejected array
  11398. */
  11399. rejectBy: function(key, value) {
  11400. var exactValue = function(item) { return get(item, key) === value; },
  11401. hasValue = function(item) { return !!get(item, key); },
  11402. use = (arguments.length === 2 ? exactValue : hasValue);
  11403. return this.reject(use);
  11404. },
  11405. /**
  11406. Returns an array with the items that do not have truthy values for
  11407. key. You can pass an optional second argument with the target value. Otherwise
  11408. this will match any property that evaluates to false.
  11409. @method rejectProperty
  11410. @param {String} key the property to test
  11411. @param {String} [value] optional value to test against.
  11412. @return {Array} rejected array
  11413. @deprecated Use `rejectBy` instead
  11414. */
  11415. rejectProperty: Ember.aliasMethod('rejectBy'),
  11416. /**
  11417. Returns the first item in the array for which the callback returns true.
  11418. This method works similar to the `filter()` method defined in JavaScript 1.6
  11419. except that it will stop working on the array once a match is found.
  11420. The callback method you provide should have the following signature (all
  11421. parameters are optional):
  11422. ```javascript
  11423. function(item, index, enumerable);
  11424. ```
  11425. - `item` is the current item in the iteration.
  11426. - `index` is the current index in the iteration.
  11427. - `enumerable` is the enumerable object itself.
  11428. It should return the `true` to include the item in the results, `false`
  11429. otherwise.
  11430. Note that in addition to a callback, you can also pass an optional target
  11431. object that will be set as `this` on the context. This is a good way
  11432. to give your iterator function access to the current object.
  11433. @method find
  11434. @param {Function} callback The callback to execute
  11435. @param {Object} [target] The target object to use
  11436. @return {Object} Found item or `undefined`.
  11437. */
  11438. find: function(callback, target) {
  11439. var len = get(this, 'length') ;
  11440. if (target === undefined) target = null;
  11441. var last = null, next, found = false, ret ;
  11442. var context = popCtx();
  11443. for(var idx=0;idx<len && !found;idx++) {
  11444. next = this.nextObject(idx, last, context) ;
  11445. if (found = callback.call(target, next, idx, this)) ret = next ;
  11446. last = next ;
  11447. }
  11448. next = last = null ;
  11449. context = pushCtx(context);
  11450. return ret ;
  11451. },
  11452. /**
  11453. Returns the first item with a property matching the passed value. You
  11454. can pass an optional second argument with the target value. Otherwise
  11455. this will match any property that evaluates to `true`.
  11456. This method works much like the more generic `find()` method.
  11457. @method findBy
  11458. @param {String} key the property to test
  11459. @param {String} [value] optional value to test against.
  11460. @return {Object} found item or `undefined`
  11461. */
  11462. findBy: function(key, value) {
  11463. return this.find(iter.apply(this, arguments));
  11464. },
  11465. /**
  11466. Returns the first item with a property matching the passed value. You
  11467. can pass an optional second argument with the target value. Otherwise
  11468. this will match any property that evaluates to `true`.
  11469. This method works much like the more generic `find()` method.
  11470. @method findProperty
  11471. @param {String} key the property to test
  11472. @param {String} [value] optional value to test against.
  11473. @return {Object} found item or `undefined`
  11474. @deprecated Use `findBy` instead
  11475. */
  11476. findProperty: Ember.aliasMethod('findBy'),
  11477. /**
  11478. Returns `true` if the passed function returns true for every item in the
  11479. enumeration. This corresponds with the `every()` method in JavaScript 1.6.
  11480. The callback method you provide should have the following signature (all
  11481. parameters are optional):
  11482. ```javascript
  11483. function(item, index, enumerable);
  11484. ```
  11485. - `item` is the current item in the iteration.
  11486. - `index` is the current index in the iteration.
  11487. - `enumerable` is the enumerable object itself.
  11488. It should return the `true` or `false`.
  11489. Note that in addition to a callback, you can also pass an optional target
  11490. object that will be set as `this` on the context. This is a good way
  11491. to give your iterator function access to the current object.
  11492. Example Usage:
  11493. ```javascript
  11494. if (people.every(isEngineer)) { Paychecks.addBigBonus(); }
  11495. ```
  11496. @method every
  11497. @param {Function} callback The callback to execute
  11498. @param {Object} [target] The target object to use
  11499. @return {Boolean}
  11500. */
  11501. every: function(callback, target) {
  11502. return !this.find(function(x, idx, i) {
  11503. return !callback.call(target, x, idx, i);
  11504. });
  11505. },
  11506. /**
  11507. @method everyBy
  11508. @param {String} key the property to test
  11509. @param {String} [value] optional value to test against.
  11510. @deprecated Use `isEvery` instead
  11511. @return {Boolean}
  11512. */
  11513. everyBy: Ember.aliasMethod('isEvery'),
  11514. /**
  11515. @method everyProperty
  11516. @param {String} key the property to test
  11517. @param {String} [value] optional value to test against.
  11518. @deprecated Use `isEvery` instead
  11519. @return {Boolean}
  11520. */
  11521. everyProperty: Ember.aliasMethod('isEvery'),
  11522. /**
  11523. Returns `true` if the passed property resolves to `true` for all items in
  11524. the enumerable. This method is often simpler/faster than using a callback.
  11525. @method isEvery
  11526. @param {String} key the property to test
  11527. @param {String} [value] optional value to test against.
  11528. @return {Boolean}
  11529. */
  11530. isEvery: function(key, value) {
  11531. return this.every(iter.apply(this, arguments));
  11532. },
  11533. /**
  11534. Returns `true` if the passed function returns true for any item in the
  11535. enumeration. This corresponds with the `some()` method in JavaScript 1.6.
  11536. The callback method you provide should have the following signature (all
  11537. parameters are optional):
  11538. ```javascript
  11539. function(item, index, enumerable);
  11540. ```
  11541. - `item` is the current item in the iteration.
  11542. - `index` is the current index in the iteration.
  11543. - `enumerable` is the enumerable object itself.
  11544. It should return the `true` to include the item in the results, `false`
  11545. otherwise.
  11546. Note that in addition to a callback, you can also pass an optional target
  11547. object that will be set as `this` on the context. This is a good way
  11548. to give your iterator function access to the current object.
  11549. Usage Example:
  11550. ```javascript
  11551. if (people.any(isManager)) { Paychecks.addBiggerBonus(); }
  11552. ```
  11553. @method any
  11554. @param {Function} callback The callback to execute
  11555. @param {Object} [target] The target object to use
  11556. @return {Boolean} `true` if the passed function returns `true` for any item
  11557. */
  11558. any: function(callback, target) {
  11559. var len = get(this, 'length'),
  11560. context = popCtx(),
  11561. found = false,
  11562. last = null,
  11563. next, idx;
  11564. if (target === undefined) { target = null; }
  11565. for (idx = 0; idx < len && !found; idx++) {
  11566. next = this.nextObject(idx, last, context);
  11567. found = callback.call(target, next, idx, this);
  11568. last = next;
  11569. }
  11570. next = last = null;
  11571. context = pushCtx(context);
  11572. return found;
  11573. },
  11574. /**
  11575. Returns `true` if the passed function returns true for any item in the
  11576. enumeration. This corresponds with the `some()` method in JavaScript 1.6.
  11577. The callback method you provide should have the following signature (all
  11578. parameters are optional):
  11579. ```javascript
  11580. function(item, index, enumerable);
  11581. ```
  11582. - `item` is the current item in the iteration.
  11583. - `index` is the current index in the iteration.
  11584. - `enumerable` is the enumerable object itself.
  11585. It should return the `true` to include the item in the results, `false`
  11586. otherwise.
  11587. Note that in addition to a callback, you can also pass an optional target
  11588. object that will be set as `this` on the context. This is a good way
  11589. to give your iterator function access to the current object.
  11590. Usage Example:
  11591. ```javascript
  11592. if (people.some(isManager)) { Paychecks.addBiggerBonus(); }
  11593. ```
  11594. @method some
  11595. @param {Function} callback The callback to execute
  11596. @param {Object} [target] The target object to use
  11597. @return {Boolean} `true` if the passed function returns `true` for any item
  11598. @deprecated Use `any` instead
  11599. */
  11600. some: Ember.aliasMethod('any'),
  11601. /**
  11602. Returns `true` if the passed property resolves to `true` for any item in
  11603. the enumerable. This method is often simpler/faster than using a callback.
  11604. @method isAny
  11605. @param {String} key the property to test
  11606. @param {String} [value] optional value to test against.
  11607. @return {Boolean} `true` if the passed function returns `true` for any item
  11608. */
  11609. isAny: function(key, value) {
  11610. return this.any(iter.apply(this, arguments));
  11611. },
  11612. /**
  11613. @method anyBy
  11614. @param {String} key the property to test
  11615. @param {String} [value] optional value to test against.
  11616. @return {Boolean} `true` if the passed function returns `true` for any item
  11617. @deprecated Use `isAny` instead
  11618. */
  11619. anyBy: Ember.aliasMethod('isAny'),
  11620. /**
  11621. @method someProperty
  11622. @param {String} key the property to test
  11623. @param {String} [value] optional value to test against.
  11624. @return {Boolean} `true` if the passed function returns `true` for any item
  11625. @deprecated Use `isAny` instead
  11626. */
  11627. someProperty: Ember.aliasMethod('isAny'),
  11628. /**
  11629. This will combine the values of the enumerator into a single value. It
  11630. is a useful way to collect a summary value from an enumeration. This
  11631. corresponds to the `reduce()` method defined in JavaScript 1.8.
  11632. The callback method you provide should have the following signature (all
  11633. parameters are optional):
  11634. ```javascript
  11635. function(previousValue, item, index, enumerable);
  11636. ```
  11637. - `previousValue` is the value returned by the last call to the iterator.
  11638. - `item` is the current item in the iteration.
  11639. - `index` is the current index in the iteration.
  11640. - `enumerable` is the enumerable object itself.
  11641. Return the new cumulative value.
  11642. In addition to the callback you can also pass an `initialValue`. An error
  11643. will be raised if you do not pass an initial value and the enumerator is
  11644. empty.
  11645. Note that unlike the other methods, this method does not allow you to
  11646. pass a target object to set as this for the callback. It's part of the
  11647. spec. Sorry.
  11648. @method reduce
  11649. @param {Function} callback The callback to execute
  11650. @param {Object} initialValue Initial value for the reduce
  11651. @param {String} reducerProperty internal use only.
  11652. @return {Object} The reduced value.
  11653. */
  11654. reduce: function(callback, initialValue, reducerProperty) {
  11655. if (typeof callback !== "function") { throw new TypeError(); }
  11656. var ret = initialValue;
  11657. this.forEach(function(item, i) {
  11658. ret = callback(ret, item, i, this, reducerProperty);
  11659. }, this);
  11660. return ret;
  11661. },
  11662. /**
  11663. Invokes the named method on every object in the receiver that
  11664. implements it. This method corresponds to the implementation in
  11665. Prototype 1.6.
  11666. @method invoke
  11667. @param {String} methodName the name of the method
  11668. @param {Object...} args optional arguments to pass as well.
  11669. @return {Array} return values from calling invoke.
  11670. */
  11671. invoke: function(methodName) {
  11672. var args, ret = Ember.A();
  11673. if (arguments.length>1) args = a_slice.call(arguments, 1);
  11674. this.forEach(function(x, idx) {
  11675. var method = x && x[methodName];
  11676. if ('function' === typeof method) {
  11677. ret[idx] = args ? method.apply(x, args) : x[methodName]();
  11678. }
  11679. }, this);
  11680. return ret;
  11681. },
  11682. /**
  11683. Simply converts the enumerable into a genuine array. The order is not
  11684. guaranteed. Corresponds to the method implemented by Prototype.
  11685. @method toArray
  11686. @return {Array} the enumerable as an array.
  11687. */
  11688. toArray: function() {
  11689. var ret = Ember.A();
  11690. this.forEach(function(o, idx) { ret[idx] = o; });
  11691. return ret ;
  11692. },
  11693. /**
  11694. Returns a copy of the array with all null and undefined elements removed.
  11695. ```javascript
  11696. var arr = ["a", null, "c", undefined];
  11697. arr.compact(); // ["a", "c"]
  11698. ```
  11699. @method compact
  11700. @return {Array} the array without null and undefined elements.
  11701. */
  11702. compact: function() {
  11703. return this.filter(function(value) { return value != null; });
  11704. },
  11705. /**
  11706. Returns a new enumerable that excludes the passed value. The default
  11707. implementation returns an array regardless of the receiver type unless
  11708. the receiver does not contain the value.
  11709. ```javascript
  11710. var arr = ["a", "b", "a", "c"];
  11711. arr.without("a"); // ["b", "c"]
  11712. ```
  11713. @method without
  11714. @param {Object} value
  11715. @return {Ember.Enumerable}
  11716. */
  11717. without: function(value) {
  11718. if (!this.contains(value)) return this; // nothing to do
  11719. var ret = Ember.A();
  11720. this.forEach(function(k) {
  11721. if (k !== value) ret[ret.length] = k;
  11722. }) ;
  11723. return ret ;
  11724. },
  11725. /**
  11726. Returns a new enumerable that contains only unique values. The default
  11727. implementation returns an array regardless of the receiver type.
  11728. ```javascript
  11729. var arr = ["a", "a", "b", "b"];
  11730. arr.uniq(); // ["a", "b"]
  11731. ```
  11732. @method uniq
  11733. @return {Ember.Enumerable}
  11734. */
  11735. uniq: function() {
  11736. var ret = Ember.A();
  11737. this.forEach(function(k) {
  11738. if (a_indexOf(ret, k)<0) ret.push(k);
  11739. });
  11740. return ret;
  11741. },
  11742. /**
  11743. This property will trigger anytime the enumerable's content changes.
  11744. You can observe this property to be notified of changes to the enumerables
  11745. content.
  11746. For plain enumerables, this property is read only. `Ember.Array` overrides
  11747. this method.
  11748. @property []
  11749. @type Ember.Array
  11750. @return this
  11751. */
  11752. '[]': Ember.computed(function(key, value) {
  11753. return this;
  11754. }),
  11755. // ..........................................................
  11756. // ENUMERABLE OBSERVERS
  11757. //
  11758. /**
  11759. Registers an enumerable observer. Must implement `Ember.EnumerableObserver`
  11760. mixin.
  11761. @method addEnumerableObserver
  11762. @param {Object} target
  11763. @param {Hash} [opts]
  11764. @return this
  11765. */
  11766. addEnumerableObserver: function(target, opts) {
  11767. var willChange = (opts && opts.willChange) || 'enumerableWillChange',
  11768. didChange = (opts && opts.didChange) || 'enumerableDidChange';
  11769. var hasObservers = get(this, 'hasEnumerableObservers');
  11770. if (!hasObservers) Ember.propertyWillChange(this, 'hasEnumerableObservers');
  11771. Ember.addListener(this, '@enumerable:before', target, willChange);
  11772. Ember.addListener(this, '@enumerable:change', target, didChange);
  11773. if (!hasObservers) Ember.propertyDidChange(this, 'hasEnumerableObservers');
  11774. return this;
  11775. },
  11776. /**
  11777. Removes a registered enumerable observer.
  11778. @method removeEnumerableObserver
  11779. @param {Object} target
  11780. @param {Hash} [opts]
  11781. @return this
  11782. */
  11783. removeEnumerableObserver: function(target, opts) {
  11784. var willChange = (opts && opts.willChange) || 'enumerableWillChange',
  11785. didChange = (opts && opts.didChange) || 'enumerableDidChange';
  11786. var hasObservers = get(this, 'hasEnumerableObservers');
  11787. if (hasObservers) Ember.propertyWillChange(this, 'hasEnumerableObservers');
  11788. Ember.removeListener(this, '@enumerable:before', target, willChange);
  11789. Ember.removeListener(this, '@enumerable:change', target, didChange);
  11790. if (hasObservers) Ember.propertyDidChange(this, 'hasEnumerableObservers');
  11791. return this;
  11792. },
  11793. /**
  11794. Becomes true whenever the array currently has observers watching changes
  11795. on the array.
  11796. @property hasEnumerableObservers
  11797. @type Boolean
  11798. */
  11799. hasEnumerableObservers: Ember.computed(function() {
  11800. return Ember.hasListeners(this, '@enumerable:change') || Ember.hasListeners(this, '@enumerable:before');
  11801. }),
  11802. /**
  11803. Invoke this method just before the contents of your enumerable will
  11804. change. You can either omit the parameters completely or pass the objects
  11805. to be removed or added if available or just a count.
  11806. @method enumerableContentWillChange
  11807. @param {Ember.Enumerable|Number} removing An enumerable of the objects to
  11808. be removed or the number of items to be removed.
  11809. @param {Ember.Enumerable|Number} adding An enumerable of the objects to be
  11810. added or the number of items to be added.
  11811. @chainable
  11812. */
  11813. enumerableContentWillChange: function(removing, adding) {
  11814. var removeCnt, addCnt, hasDelta;
  11815. if ('number' === typeof removing) removeCnt = removing;
  11816. else if (removing) removeCnt = get(removing, 'length');
  11817. else removeCnt = removing = -1;
  11818. if ('number' === typeof adding) addCnt = adding;
  11819. else if (adding) addCnt = get(adding,'length');
  11820. else addCnt = adding = -1;
  11821. hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0;
  11822. if (removing === -1) removing = null;
  11823. if (adding === -1) adding = null;
  11824. Ember.propertyWillChange(this, '[]');
  11825. if (hasDelta) Ember.propertyWillChange(this, 'length');
  11826. Ember.sendEvent(this, '@enumerable:before', [this, removing, adding]);
  11827. return this;
  11828. },
  11829. /**
  11830. Invoke this method when the contents of your enumerable has changed.
  11831. This will notify any observers watching for content changes. If your are
  11832. implementing an ordered enumerable (such as an array), also pass the
  11833. start and end values where the content changed so that it can be used to
  11834. notify range observers.
  11835. @method enumerableContentDidChange
  11836. @param {Ember.Enumerable|Number} removing An enumerable of the objects to
  11837. be removed or the number of items to be removed.
  11838. @param {Ember.Enumerable|Number} adding An enumerable of the objects to
  11839. be added or the number of items to be added.
  11840. @chainable
  11841. */
  11842. enumerableContentDidChange: function(removing, adding) {
  11843. var removeCnt, addCnt, hasDelta;
  11844. if ('number' === typeof removing) removeCnt = removing;
  11845. else if (removing) removeCnt = get(removing, 'length');
  11846. else removeCnt = removing = -1;
  11847. if ('number' === typeof adding) addCnt = adding;
  11848. else if (adding) addCnt = get(adding, 'length');
  11849. else addCnt = adding = -1;
  11850. hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0;
  11851. if (removing === -1) removing = null;
  11852. if (adding === -1) adding = null;
  11853. Ember.sendEvent(this, '@enumerable:change', [this, removing, adding]);
  11854. if (hasDelta) Ember.propertyDidChange(this, 'length');
  11855. Ember.propertyDidChange(this, '[]');
  11856. return this ;
  11857. },
  11858. /**
  11859. Converts the enumerable into an array and sorts by the keys
  11860. specified in the argument.
  11861. You may provide multiple arguments to sort by multiple properties.
  11862. @method sortBy
  11863. @param {String} property name(s) to sort on
  11864. @return {Array} The sorted array.
  11865. */
  11866. sortBy: function() {
  11867. var sortKeys = arguments;
  11868. return this.toArray().sort(function(a, b){
  11869. for(var i = 0; i < sortKeys.length; i++) {
  11870. var key = sortKeys[i],
  11871. propA = get(a, key),
  11872. propB = get(b, key);
  11873. // return 1 or -1 else continue to the next sortKey
  11874. var compareValue = Ember.compare(propA, propB);
  11875. if (compareValue) { return compareValue; }
  11876. }
  11877. return 0;
  11878. });
  11879. }
  11880. });
  11881. })();
  11882. (function() {
  11883. /**
  11884. @module ember
  11885. @submodule ember-runtime
  11886. */
  11887. // ..........................................................
  11888. // HELPERS
  11889. //
  11890. var get = Ember.get, set = Ember.set, isNone = Ember.isNone, map = Ember.EnumerableUtils.map, cacheFor = Ember.cacheFor;
  11891. // ..........................................................
  11892. // ARRAY
  11893. //
  11894. /**
  11895. This module implements Observer-friendly Array-like behavior. This mixin is
  11896. picked up by the Array class as well as other controllers, etc. that want to
  11897. appear to be arrays.
  11898. Unlike `Ember.Enumerable,` this mixin defines methods specifically for
  11899. collections that provide index-ordered access to their contents. When you
  11900. are designing code that needs to accept any kind of Array-like object, you
  11901. should use these methods instead of Array primitives because these will
  11902. properly notify observers of changes to the array.
  11903. Although these methods are efficient, they do add a layer of indirection to
  11904. your application so it is a good idea to use them only when you need the
  11905. flexibility of using both true JavaScript arrays and "virtual" arrays such
  11906. as controllers and collections.
  11907. You can use the methods defined in this module to access and modify array
  11908. contents in a KVO-friendly way. You can also be notified whenever the
  11909. membership of an array changes by changing the syntax of the property to
  11910. `.observes('*myProperty.[]')`.
  11911. To support `Ember.Array` in your own class, you must override two
  11912. primitives to use it: `replace()` and `objectAt()`.
  11913. Note that the Ember.Array mixin also incorporates the `Ember.Enumerable`
  11914. mixin. All `Ember.Array`-like objects are also enumerable.
  11915. @class Array
  11916. @namespace Ember
  11917. @uses Ember.Enumerable
  11918. @since Ember 0.9.0
  11919. */
  11920. Ember.Array = Ember.Mixin.create(Ember.Enumerable, {
  11921. /**
  11922. Your array must support the `length` property. Your replace methods should
  11923. set this property whenever it changes.
  11924. @property {Number} length
  11925. */
  11926. length: Ember.required(),
  11927. /**
  11928. Returns the object at the given `index`. If the given `index` is negative
  11929. or is greater or equal than the array length, returns `undefined`.
  11930. This is one of the primitives you must implement to support `Ember.Array`.
  11931. If your object supports retrieving the value of an array item using `get()`
  11932. (i.e. `myArray.get(0)`), then you do not need to implement this method
  11933. yourself.
  11934. ```javascript
  11935. var arr = ['a', 'b', 'c', 'd'];
  11936. arr.objectAt(0); // "a"
  11937. arr.objectAt(3); // "d"
  11938. arr.objectAt(-1); // undefined
  11939. arr.objectAt(4); // undefined
  11940. arr.objectAt(5); // undefined
  11941. ```
  11942. @method objectAt
  11943. @param {Number} idx The index of the item to return.
  11944. @return {*} item at index or undefined
  11945. */
  11946. objectAt: function(idx) {
  11947. if ((idx < 0) || (idx>=get(this, 'length'))) return undefined ;
  11948. return get(this, idx);
  11949. },
  11950. /**
  11951. This returns the objects at the specified indexes, using `objectAt`.
  11952. ```javascript
  11953. var arr = ['a', 'b', 'c', 'd'];
  11954. arr.objectsAt([0, 1, 2]); // ["a", "b", "c"]
  11955. arr.objectsAt([2, 3, 4]); // ["c", "d", undefined]
  11956. ```
  11957. @method objectsAt
  11958. @param {Array} indexes An array of indexes of items to return.
  11959. @return {Array}
  11960. */
  11961. objectsAt: function(indexes) {
  11962. var self = this;
  11963. return map(indexes, function(idx) { return self.objectAt(idx); });
  11964. },
  11965. // overrides Ember.Enumerable version
  11966. nextObject: function(idx) {
  11967. return this.objectAt(idx);
  11968. },
  11969. /**
  11970. This is the handler for the special array content property. If you get
  11971. this property, it will return this. If you set this property it a new
  11972. array, it will replace the current content.
  11973. This property overrides the default property defined in `Ember.Enumerable`.
  11974. @property []
  11975. @return this
  11976. */
  11977. '[]': Ember.computed(function(key, value) {
  11978. if (value !== undefined) this.replace(0, get(this, 'length'), value) ;
  11979. return this ;
  11980. }),
  11981. firstObject: Ember.computed(function() {
  11982. return this.objectAt(0);
  11983. }),
  11984. lastObject: Ember.computed(function() {
  11985. return this.objectAt(get(this, 'length')-1);
  11986. }),
  11987. // optimized version from Enumerable
  11988. contains: function(obj) {
  11989. return this.indexOf(obj) >= 0;
  11990. },
  11991. // Add any extra methods to Ember.Array that are native to the built-in Array.
  11992. /**
  11993. Returns a new array that is a slice of the receiver. This implementation
  11994. uses the observable array methods to retrieve the objects for the new
  11995. slice.
  11996. ```javascript
  11997. var arr = ['red', 'green', 'blue'];
  11998. arr.slice(0); // ['red', 'green', 'blue']
  11999. arr.slice(0, 2); // ['red', 'green']
  12000. arr.slice(1, 100); // ['green', 'blue']
  12001. ```
  12002. @method slice
  12003. @param {Integer} beginIndex (Optional) index to begin slicing from.
  12004. @param {Integer} endIndex (Optional) index to end the slice at (but not included).
  12005. @return {Array} New array with specified slice
  12006. */
  12007. slice: function(beginIndex, endIndex) {
  12008. var ret = Ember.A();
  12009. var length = get(this, 'length') ;
  12010. if (isNone(beginIndex)) beginIndex = 0 ;
  12011. if (isNone(endIndex) || (endIndex > length)) endIndex = length ;
  12012. if (beginIndex < 0) beginIndex = length + beginIndex;
  12013. if (endIndex < 0) endIndex = length + endIndex;
  12014. while(beginIndex < endIndex) {
  12015. ret[ret.length] = this.objectAt(beginIndex++) ;
  12016. }
  12017. return ret ;
  12018. },
  12019. /**
  12020. Returns the index of the given object's first occurrence.
  12021. If no `startAt` argument is given, the starting location to
  12022. search is 0. If it's negative, will count backward from
  12023. the end of the array. Returns -1 if no match is found.
  12024. ```javascript
  12025. var arr = ["a", "b", "c", "d", "a"];
  12026. arr.indexOf("a"); // 0
  12027. arr.indexOf("z"); // -1
  12028. arr.indexOf("a", 2); // 4
  12029. arr.indexOf("a", -1); // 4
  12030. arr.indexOf("b", 3); // -1
  12031. arr.indexOf("a", 100); // -1
  12032. ```
  12033. @method indexOf
  12034. @param {Object} object the item to search for
  12035. @param {Number} startAt optional starting location to search, default 0
  12036. @return {Number} index or -1 if not found
  12037. */
  12038. indexOf: function(object, startAt) {
  12039. var idx, len = get(this, 'length');
  12040. if (startAt === undefined) startAt = 0;
  12041. if (startAt < 0) startAt += len;
  12042. for(idx=startAt;idx<len;idx++) {
  12043. if (this.objectAt(idx) === object) return idx ;
  12044. }
  12045. return -1;
  12046. },
  12047. /**
  12048. Returns the index of the given object's last occurrence.
  12049. If no `startAt` argument is given, the search starts from
  12050. the last position. If it's negative, will count backward
  12051. from the end of the array. Returns -1 if no match is found.
  12052. ```javascript
  12053. var arr = ["a", "b", "c", "d", "a"];
  12054. arr.lastIndexOf("a"); // 4
  12055. arr.lastIndexOf("z"); // -1
  12056. arr.lastIndexOf("a", 2); // 0
  12057. arr.lastIndexOf("a", -1); // 4
  12058. arr.lastIndexOf("b", 3); // 1
  12059. arr.lastIndexOf("a", 100); // 4
  12060. ```
  12061. @method lastIndexOf
  12062. @param {Object} object the item to search for
  12063. @param {Number} startAt optional starting location to search, default 0
  12064. @return {Number} index or -1 if not found
  12065. */
  12066. lastIndexOf: function(object, startAt) {
  12067. var idx, len = get(this, 'length');
  12068. if (startAt === undefined || startAt >= len) startAt = len-1;
  12069. if (startAt < 0) startAt += len;
  12070. for(idx=startAt;idx>=0;idx--) {
  12071. if (this.objectAt(idx) === object) return idx ;
  12072. }
  12073. return -1;
  12074. },
  12075. // ..........................................................
  12076. // ARRAY OBSERVERS
  12077. //
  12078. /**
  12079. Adds an array observer to the receiving array. The array observer object
  12080. normally must implement two methods:
  12081. * `arrayWillChange(observedObj, start, removeCount, addCount)` - This method will be
  12082. called just before the array is modified.
  12083. * `arrayDidChange(observedObj, start, removeCount, addCount)` - This method will be
  12084. called just after the array is modified.
  12085. Both callbacks will be passed the observed object, starting index of the
  12086. change as well a a count of the items to be removed and added. You can use
  12087. these callbacks to optionally inspect the array during the change, clear
  12088. caches, or do any other bookkeeping necessary.
  12089. In addition to passing a target, you can also include an options hash
  12090. which you can use to override the method names that will be invoked on the
  12091. target.
  12092. @method addArrayObserver
  12093. @param {Object} target The observer object.
  12094. @param {Hash} opts Optional hash of configuration options including
  12095. `willChange` and `didChange` option.
  12096. @return {Ember.Array} receiver
  12097. */
  12098. addArrayObserver: function(target, opts) {
  12099. var willChange = (opts && opts.willChange) || 'arrayWillChange',
  12100. didChange = (opts && opts.didChange) || 'arrayDidChange';
  12101. var hasObservers = get(this, 'hasArrayObservers');
  12102. if (!hasObservers) Ember.propertyWillChange(this, 'hasArrayObservers');
  12103. Ember.addListener(this, '@array:before', target, willChange);
  12104. Ember.addListener(this, '@array:change', target, didChange);
  12105. if (!hasObservers) Ember.propertyDidChange(this, 'hasArrayObservers');
  12106. return this;
  12107. },
  12108. /**
  12109. Removes an array observer from the object if the observer is current
  12110. registered. Calling this method multiple times with the same object will
  12111. have no effect.
  12112. @method removeArrayObserver
  12113. @param {Object} target The object observing the array.
  12114. @param {Hash} opts Optional hash of configuration options including
  12115. `willChange` and `didChange` option.
  12116. @return {Ember.Array} receiver
  12117. */
  12118. removeArrayObserver: function(target, opts) {
  12119. var willChange = (opts && opts.willChange) || 'arrayWillChange',
  12120. didChange = (opts && opts.didChange) || 'arrayDidChange';
  12121. var hasObservers = get(this, 'hasArrayObservers');
  12122. if (hasObservers) Ember.propertyWillChange(this, 'hasArrayObservers');
  12123. Ember.removeListener(this, '@array:before', target, willChange);
  12124. Ember.removeListener(this, '@array:change', target, didChange);
  12125. if (hasObservers) Ember.propertyDidChange(this, 'hasArrayObservers');
  12126. return this;
  12127. },
  12128. /**
  12129. Becomes true whenever the array currently has observers watching changes
  12130. on the array.
  12131. @property {Boolean} hasArrayObservers
  12132. */
  12133. hasArrayObservers: Ember.computed(function() {
  12134. return Ember.hasListeners(this, '@array:change') || Ember.hasListeners(this, '@array:before');
  12135. }),
  12136. /**
  12137. If you are implementing an object that supports `Ember.Array`, call this
  12138. method just before the array content changes to notify any observers and
  12139. invalidate any related properties. Pass the starting index of the change
  12140. as well as a delta of the amounts to change.
  12141. @method arrayContentWillChange
  12142. @param {Number} startIdx The starting index in the array that will change.
  12143. @param {Number} removeAmt The number of items that will be removed. If you
  12144. pass `null` assumes 0
  12145. @param {Number} addAmt The number of items that will be added. If you
  12146. pass `null` assumes 0.
  12147. @return {Ember.Array} receiver
  12148. */
  12149. arrayContentWillChange: function(startIdx, removeAmt, addAmt) {
  12150. // if no args are passed assume everything changes
  12151. if (startIdx===undefined) {
  12152. startIdx = 0;
  12153. removeAmt = addAmt = -1;
  12154. } else {
  12155. if (removeAmt === undefined) removeAmt=-1;
  12156. if (addAmt === undefined) addAmt=-1;
  12157. }
  12158. // Make sure the @each proxy is set up if anyone is observing @each
  12159. if (Ember.isWatching(this, '@each')) { get(this, '@each'); }
  12160. Ember.sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]);
  12161. var removing, lim;
  12162. if (startIdx>=0 && removeAmt>=0 && get(this, 'hasEnumerableObservers')) {
  12163. removing = [];
  12164. lim = startIdx+removeAmt;
  12165. for(var idx=startIdx;idx<lim;idx++) removing.push(this.objectAt(idx));
  12166. } else {
  12167. removing = removeAmt;
  12168. }
  12169. this.enumerableContentWillChange(removing, addAmt);
  12170. return this;
  12171. },
  12172. /**
  12173. If you are implementing an object that supports `Ember.Array`, call this
  12174. method just after the array content changes to notify any observers and
  12175. invalidate any related properties. Pass the starting index of the change
  12176. as well as a delta of the amounts to change.
  12177. @method arrayContentDidChange
  12178. @param {Number} startIdx The starting index in the array that did change.
  12179. @param {Number} removeAmt The number of items that were removed. If you
  12180. pass `null` assumes 0
  12181. @param {Number} addAmt The number of items that were added. If you
  12182. pass `null` assumes 0.
  12183. @return {Ember.Array} receiver
  12184. */
  12185. arrayContentDidChange: function(startIdx, removeAmt, addAmt) {
  12186. // if no args are passed assume everything changes
  12187. if (startIdx===undefined) {
  12188. startIdx = 0;
  12189. removeAmt = addAmt = -1;
  12190. } else {
  12191. if (removeAmt === undefined) removeAmt=-1;
  12192. if (addAmt === undefined) addAmt=-1;
  12193. }
  12194. var adding, lim;
  12195. if (startIdx>=0 && addAmt>=0 && get(this, 'hasEnumerableObservers')) {
  12196. adding = [];
  12197. lim = startIdx+addAmt;
  12198. for(var idx=startIdx;idx<lim;idx++) adding.push(this.objectAt(idx));
  12199. } else {
  12200. adding = addAmt;
  12201. }
  12202. this.enumerableContentDidChange(removeAmt, adding);
  12203. Ember.sendEvent(this, '@array:change', [this, startIdx, removeAmt, addAmt]);
  12204. var length = get(this, 'length'),
  12205. cachedFirst = cacheFor(this, 'firstObject'),
  12206. cachedLast = cacheFor(this, 'lastObject');
  12207. if (this.objectAt(0) !== cachedFirst) {
  12208. Ember.propertyWillChange(this, 'firstObject');
  12209. Ember.propertyDidChange(this, 'firstObject');
  12210. }
  12211. if (this.objectAt(length-1) !== cachedLast) {
  12212. Ember.propertyWillChange(this, 'lastObject');
  12213. Ember.propertyDidChange(this, 'lastObject');
  12214. }
  12215. return this;
  12216. },
  12217. // ..........................................................
  12218. // ENUMERATED PROPERTIES
  12219. //
  12220. /**
  12221. Returns a special object that can be used to observe individual properties
  12222. on the array. Just get an equivalent property on this object and it will
  12223. return an enumerable that maps automatically to the named key on the
  12224. member objects.
  12225. If you merely want to watch for any items being added or removed to the array,
  12226. use the `[]` property instead of `@each`.
  12227. @property @each
  12228. */
  12229. '@each': Ember.computed(function() {
  12230. if (!this.__each) this.__each = new Ember.EachProxy(this);
  12231. return this.__each;
  12232. })
  12233. }) ;
  12234. })();
  12235. (function() {
  12236. var e_get = Ember.get,
  12237. set = Ember.set,
  12238. guidFor = Ember.guidFor,
  12239. metaFor = Ember.meta,
  12240. propertyWillChange = Ember.propertyWillChange,
  12241. propertyDidChange = Ember.propertyDidChange,
  12242. addBeforeObserver = Ember.addBeforeObserver,
  12243. removeBeforeObserver = Ember.removeBeforeObserver,
  12244. addObserver = Ember.addObserver,
  12245. removeObserver = Ember.removeObserver,
  12246. ComputedProperty = Ember.ComputedProperty,
  12247. a_slice = [].slice,
  12248. o_create = Ember.create,
  12249. forEach = Ember.EnumerableUtils.forEach,
  12250. // Here we explicitly don't allow `@each.foo`; it would require some special
  12251. // testing, but there's no particular reason why it should be disallowed.
  12252. eachPropertyPattern = /^(.*)\.@each\.(.*)/,
  12253. doubleEachPropertyPattern = /(.*\.@each){2,}/,
  12254. arrayBracketPattern = /\.\[\]$/;
  12255. var expandProperties = Ember.expandProperties;
  12256. function get(obj, key) {
  12257. if (key === '@this') {
  12258. return obj;
  12259. }
  12260. return e_get(obj, key);
  12261. }
  12262. /*
  12263. Tracks changes to dependent arrays, as well as to properties of items in
  12264. dependent arrays.
  12265. @class DependentArraysObserver
  12266. */
  12267. function DependentArraysObserver(callbacks, cp, instanceMeta, context, propertyName, sugarMeta) {
  12268. // user specified callbacks for `addedItem` and `removedItem`
  12269. this.callbacks = callbacks;
  12270. // the computed property: remember these are shared across instances
  12271. this.cp = cp;
  12272. // the ReduceComputedPropertyInstanceMeta this DependentArraysObserver is
  12273. // associated with
  12274. this.instanceMeta = instanceMeta;
  12275. // A map of array guids to dependentKeys, for the given context. We track
  12276. // this because we want to set up the computed property potentially before the
  12277. // dependent array even exists, but when the array observer fires, we lack
  12278. // enough context to know what to update: we can recover that context by
  12279. // getting the dependentKey.
  12280. this.dependentKeysByGuid = {};
  12281. // a map of dependent array guids -> Ember.TrackedArray instances. We use
  12282. // this to lazily recompute indexes for item property observers.
  12283. this.trackedArraysByGuid = {};
  12284. // We suspend observers to ignore replacements from `reset` when totally
  12285. // recomputing. Unfortunately we cannot properly suspend the observers
  12286. // because we only have the key; instead we make the observers no-ops
  12287. this.suspended = false;
  12288. // This is used to coalesce item changes from property observers.
  12289. this.changedItems = {};
  12290. }
  12291. function ItemPropertyObserverContext (dependentArray, index, trackedArray) {
  12292. Ember.assert("Internal error: trackedArray is null or undefined", trackedArray);
  12293. this.dependentArray = dependentArray;
  12294. this.index = index;
  12295. this.item = dependentArray.objectAt(index);
  12296. this.trackedArray = trackedArray;
  12297. this.beforeObserver = null;
  12298. this.observer = null;
  12299. this.destroyed = false;
  12300. }
  12301. DependentArraysObserver.prototype = {
  12302. setValue: function (newValue) {
  12303. this.instanceMeta.setValue(newValue, true);
  12304. },
  12305. getValue: function () {
  12306. return this.instanceMeta.getValue();
  12307. },
  12308. setupObservers: function (dependentArray, dependentKey) {
  12309. Ember.assert("dependent array must be an `Ember.Array`", Ember.Array.detect(dependentArray));
  12310. this.dependentKeysByGuid[guidFor(dependentArray)] = dependentKey;
  12311. dependentArray.addArrayObserver(this, {
  12312. willChange: 'dependentArrayWillChange',
  12313. didChange: 'dependentArrayDidChange'
  12314. });
  12315. if (this.cp._itemPropertyKeys[dependentKey]) {
  12316. this.setupPropertyObservers(dependentKey, this.cp._itemPropertyKeys[dependentKey]);
  12317. }
  12318. },
  12319. teardownObservers: function (dependentArray, dependentKey) {
  12320. var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || [];
  12321. delete this.dependentKeysByGuid[guidFor(dependentArray)];
  12322. this.teardownPropertyObservers(dependentKey, itemPropertyKeys);
  12323. dependentArray.removeArrayObserver(this, {
  12324. willChange: 'dependentArrayWillChange',
  12325. didChange: 'dependentArrayDidChange'
  12326. });
  12327. },
  12328. suspendArrayObservers: function (callback, binding) {
  12329. var oldSuspended = this.suspended;
  12330. this.suspended = true;
  12331. callback.call(binding);
  12332. this.suspended = oldSuspended;
  12333. },
  12334. setupPropertyObservers: function (dependentKey, itemPropertyKeys) {
  12335. var dependentArray = get(this.instanceMeta.context, dependentKey),
  12336. length = get(dependentArray, 'length'),
  12337. observerContexts = new Array(length);
  12338. this.resetTransformations(dependentKey, observerContexts);
  12339. forEach(dependentArray, function (item, index) {
  12340. var observerContext = this.createPropertyObserverContext(dependentArray, index, this.trackedArraysByGuid[dependentKey]);
  12341. observerContexts[index] = observerContext;
  12342. forEach(itemPropertyKeys, function (propertyKey) {
  12343. addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver);
  12344. addObserver(item, propertyKey, this, observerContext.observer);
  12345. }, this);
  12346. }, this);
  12347. },
  12348. teardownPropertyObservers: function (dependentKey, itemPropertyKeys) {
  12349. var dependentArrayObserver = this,
  12350. trackedArray = this.trackedArraysByGuid[dependentKey],
  12351. beforeObserver,
  12352. observer,
  12353. item;
  12354. if (!trackedArray) { return; }
  12355. trackedArray.apply(function (observerContexts, offset, operation) {
  12356. if (operation === Ember.TrackedArray.DELETE) { return; }
  12357. forEach(observerContexts, function (observerContext) {
  12358. observerContext.destroyed = true;
  12359. beforeObserver = observerContext.beforeObserver;
  12360. observer = observerContext.observer;
  12361. item = observerContext.item;
  12362. forEach(itemPropertyKeys, function (propertyKey) {
  12363. removeBeforeObserver(item, propertyKey, dependentArrayObserver, beforeObserver);
  12364. removeObserver(item, propertyKey, dependentArrayObserver, observer);
  12365. });
  12366. });
  12367. });
  12368. },
  12369. createPropertyObserverContext: function (dependentArray, index, trackedArray) {
  12370. var observerContext = new ItemPropertyObserverContext(dependentArray, index, trackedArray);
  12371. this.createPropertyObserver(observerContext);
  12372. return observerContext;
  12373. },
  12374. createPropertyObserver: function (observerContext) {
  12375. var dependentArrayObserver = this;
  12376. observerContext.beforeObserver = function (obj, keyName) {
  12377. return dependentArrayObserver.itemPropertyWillChange(obj, keyName, observerContext.dependentArray, observerContext);
  12378. };
  12379. observerContext.observer = function (obj, keyName) {
  12380. return dependentArrayObserver.itemPropertyDidChange(obj, keyName, observerContext.dependentArray, observerContext);
  12381. };
  12382. },
  12383. resetTransformations: function (dependentKey, observerContexts) {
  12384. this.trackedArraysByGuid[dependentKey] = new Ember.TrackedArray(observerContexts);
  12385. },
  12386. trackAdd: function (dependentKey, index, newItems) {
  12387. var trackedArray = this.trackedArraysByGuid[dependentKey];
  12388. if (trackedArray) {
  12389. trackedArray.addItems(index, newItems);
  12390. }
  12391. },
  12392. trackRemove: function (dependentKey, index, removedCount) {
  12393. var trackedArray = this.trackedArraysByGuid[dependentKey];
  12394. if (trackedArray) {
  12395. return trackedArray.removeItems(index, removedCount);
  12396. }
  12397. return [];
  12398. },
  12399. updateIndexes: function (trackedArray, array) {
  12400. var length = get(array, 'length');
  12401. // OPTIMIZE: we could stop updating once we hit the object whose observer
  12402. // fired; ie partially apply the transformations
  12403. trackedArray.apply(function (observerContexts, offset, operation) {
  12404. // we don't even have observer contexts for removed items, even if we did,
  12405. // they no longer have any index in the array
  12406. if (operation === Ember.TrackedArray.DELETE) { return; }
  12407. if (operation === Ember.TrackedArray.RETAIN && observerContexts.length === length && offset === 0) {
  12408. // If we update many items we don't want to walk the array each time: we
  12409. // only need to update the indexes at most once per run loop.
  12410. return;
  12411. }
  12412. forEach(observerContexts, function (context, index) {
  12413. context.index = index + offset;
  12414. });
  12415. });
  12416. },
  12417. dependentArrayWillChange: function (dependentArray, index, removedCount, addedCount) {
  12418. if (this.suspended) { return; }
  12419. var removedItem = this.callbacks.removedItem,
  12420. changeMeta,
  12421. guid = guidFor(dependentArray),
  12422. dependentKey = this.dependentKeysByGuid[guid],
  12423. itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || [],
  12424. length = get(dependentArray, 'length'),
  12425. normalizedIndex = normalizeIndex(index, length, 0),
  12426. normalizedRemoveCount = normalizeRemoveCount(normalizedIndex, length, removedCount),
  12427. item,
  12428. itemIndex,
  12429. sliceIndex,
  12430. observerContexts;
  12431. observerContexts = this.trackRemove(dependentKey, normalizedIndex, normalizedRemoveCount);
  12432. function removeObservers(propertyKey) {
  12433. observerContexts[sliceIndex].destroyed = true;
  12434. removeBeforeObserver(item, propertyKey, this, observerContexts[sliceIndex].beforeObserver);
  12435. removeObserver(item, propertyKey, this, observerContexts[sliceIndex].observer);
  12436. }
  12437. for (sliceIndex = normalizedRemoveCount - 1; sliceIndex >= 0; --sliceIndex) {
  12438. itemIndex = normalizedIndex + sliceIndex;
  12439. if (itemIndex >= length) { break; }
  12440. item = dependentArray.objectAt(itemIndex);
  12441. forEach(itemPropertyKeys, removeObservers, this);
  12442. changeMeta = createChangeMeta(dependentArray, item, itemIndex, this.instanceMeta.propertyName, this.cp);
  12443. this.setValue( removedItem.call(
  12444. this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta));
  12445. }
  12446. },
  12447. dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) {
  12448. if (this.suspended) { return; }
  12449. var addedItem = this.callbacks.addedItem,
  12450. guid = guidFor(dependentArray),
  12451. dependentKey = this.dependentKeysByGuid[guid],
  12452. observerContexts = new Array(addedCount),
  12453. itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey],
  12454. length = get(dependentArray, 'length'),
  12455. normalizedIndex = normalizeIndex(index, length, addedCount),
  12456. changeMeta,
  12457. observerContext;
  12458. forEach(dependentArray.slice(normalizedIndex, normalizedIndex + addedCount), function (item, sliceIndex) {
  12459. if (itemPropertyKeys) {
  12460. observerContext =
  12461. observerContexts[sliceIndex] =
  12462. this.createPropertyObserverContext(dependentArray, normalizedIndex + sliceIndex, this.trackedArraysByGuid[dependentKey]);
  12463. forEach(itemPropertyKeys, function (propertyKey) {
  12464. addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver);
  12465. addObserver(item, propertyKey, this, observerContext.observer);
  12466. }, this);
  12467. }
  12468. changeMeta = createChangeMeta(dependentArray, item, normalizedIndex + sliceIndex, this.instanceMeta.propertyName, this.cp);
  12469. this.setValue( addedItem.call(
  12470. this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta));
  12471. }, this);
  12472. this.trackAdd(dependentKey, normalizedIndex, observerContexts);
  12473. },
  12474. itemPropertyWillChange: function (obj, keyName, array, observerContext) {
  12475. var guid = guidFor(obj);
  12476. if (!this.changedItems[guid]) {
  12477. this.changedItems[guid] = {
  12478. array: array,
  12479. observerContext: observerContext,
  12480. obj: obj,
  12481. previousValues: {}
  12482. };
  12483. }
  12484. this.changedItems[guid].previousValues[keyName] = get(obj, keyName);
  12485. },
  12486. itemPropertyDidChange: function(obj, keyName, array, observerContext) {
  12487. this.flushChanges();
  12488. },
  12489. flushChanges: function() {
  12490. var changedItems = this.changedItems, key, c, changeMeta;
  12491. for (key in changedItems) {
  12492. c = changedItems[key];
  12493. if (c.observerContext.destroyed) { continue; }
  12494. this.updateIndexes(c.observerContext.trackedArray, c.observerContext.dependentArray);
  12495. changeMeta = createChangeMeta(c.array, c.obj, c.observerContext.index, this.instanceMeta.propertyName, this.cp, c.previousValues);
  12496. this.setValue(
  12497. this.callbacks.removedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta));
  12498. this.setValue(
  12499. this.callbacks.addedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta));
  12500. }
  12501. this.changedItems = {};
  12502. }
  12503. };
  12504. function normalizeIndex(index, length, newItemsOffset) {
  12505. if (index < 0) {
  12506. return Math.max(0, length + index);
  12507. } else if (index < length) {
  12508. return index;
  12509. } else /* index > length */ {
  12510. return Math.min(length - newItemsOffset, index);
  12511. }
  12512. }
  12513. function normalizeRemoveCount(index, length, removedCount) {
  12514. return Math.min(removedCount, length - index);
  12515. }
  12516. function createChangeMeta(dependentArray, item, index, propertyName, property, previousValues) {
  12517. var meta = {
  12518. arrayChanged: dependentArray,
  12519. index: index,
  12520. item: item,
  12521. propertyName: propertyName,
  12522. property: property
  12523. };
  12524. if (previousValues) {
  12525. // previous values only available for item property changes
  12526. meta.previousValues = previousValues;
  12527. }
  12528. return meta;
  12529. }
  12530. function addItems (dependentArray, callbacks, cp, propertyName, meta) {
  12531. forEach(dependentArray, function (item, index) {
  12532. meta.setValue( callbacks.addedItem.call(
  12533. this, meta.getValue(), item, createChangeMeta(dependentArray, item, index, propertyName, cp), meta.sugarMeta));
  12534. }, this);
  12535. }
  12536. function reset(cp, propertyName) {
  12537. var callbacks = cp._callbacks(),
  12538. meta;
  12539. if (cp._hasInstanceMeta(this, propertyName)) {
  12540. meta = cp._instanceMeta(this, propertyName);
  12541. meta.setValue(cp.resetValue(meta.getValue()));
  12542. } else {
  12543. meta = cp._instanceMeta(this, propertyName);
  12544. }
  12545. if (cp.options.initialize) {
  12546. cp.options.initialize.call(this, meta.getValue(), { property: cp, propertyName: propertyName }, meta.sugarMeta);
  12547. }
  12548. }
  12549. function partiallyRecomputeFor(obj, dependentKey) {
  12550. if (arrayBracketPattern.test(dependentKey)) {
  12551. return false;
  12552. }
  12553. var value = get(obj, dependentKey);
  12554. return Ember.Array.detect(value);
  12555. }
  12556. function ReduceComputedPropertyInstanceMeta(context, propertyName, initialValue) {
  12557. this.context = context;
  12558. this.propertyName = propertyName;
  12559. this.cache = metaFor(context).cache;
  12560. this.dependentArrays = {};
  12561. this.sugarMeta = {};
  12562. this.initialValue = initialValue;
  12563. }
  12564. ReduceComputedPropertyInstanceMeta.prototype = {
  12565. getValue: function () {
  12566. if (this.propertyName in this.cache) {
  12567. return this.cache[this.propertyName];
  12568. } else {
  12569. return this.initialValue;
  12570. }
  12571. },
  12572. setValue: function(newValue, triggerObservers) {
  12573. // This lets sugars force a recomputation, handy for very simple
  12574. // implementations of eg max.
  12575. if (newValue === this.cache[this.propertyName]) {
  12576. return;
  12577. }
  12578. if (triggerObservers) {
  12579. propertyWillChange(this.context, this.propertyName);
  12580. }
  12581. if (newValue === undefined) {
  12582. delete this.cache[this.propertyName];
  12583. } else {
  12584. this.cache[this.propertyName] = newValue;
  12585. }
  12586. if (triggerObservers) {
  12587. propertyDidChange(this.context, this.propertyName);
  12588. }
  12589. }
  12590. };
  12591. /**
  12592. A computed property whose dependent keys are arrays and which is updated with
  12593. "one at a time" semantics.
  12594. @class ReduceComputedProperty
  12595. @namespace Ember
  12596. @extends Ember.ComputedProperty
  12597. @constructor
  12598. */
  12599. function ReduceComputedProperty(options) {
  12600. var cp = this;
  12601. this.options = options;
  12602. this._instanceMetas = {};
  12603. this._dependentKeys = null;
  12604. // A map of dependentKey -> [itemProperty, ...] that tracks what properties of
  12605. // items in the array we must track to update this property.
  12606. this._itemPropertyKeys = {};
  12607. this._previousItemPropertyKeys = {};
  12608. this.readOnly();
  12609. this.cacheable();
  12610. this.recomputeOnce = function(propertyName) {
  12611. // What we really want to do is coalesce by <cp, propertyName>.
  12612. // We need a form of `scheduleOnce` that accepts an arbitrary token to
  12613. // coalesce by, in addition to the target and method.
  12614. Ember.run.once(this, recompute, propertyName);
  12615. };
  12616. var recompute = function(propertyName) {
  12617. var dependentKeys = cp._dependentKeys,
  12618. meta = cp._instanceMeta(this, propertyName),
  12619. callbacks = cp._callbacks();
  12620. reset.call(this, cp, propertyName);
  12621. meta.dependentArraysObserver.suspendArrayObservers(function () {
  12622. forEach(cp._dependentKeys, function (dependentKey) {
  12623. if (!partiallyRecomputeFor(this, dependentKey)) { return; }
  12624. var dependentArray = get(this, dependentKey),
  12625. previousDependentArray = meta.dependentArrays[dependentKey];
  12626. if (dependentArray === previousDependentArray) {
  12627. // The array may be the same, but our item property keys may have
  12628. // changed, so we set them up again. We can't easily tell if they've
  12629. // changed: the array may be the same object, but with different
  12630. // contents.
  12631. if (cp._previousItemPropertyKeys[dependentKey]) {
  12632. delete cp._previousItemPropertyKeys[dependentKey];
  12633. meta.dependentArraysObserver.setupPropertyObservers(dependentKey, cp._itemPropertyKeys[dependentKey]);
  12634. }
  12635. } else {
  12636. meta.dependentArrays[dependentKey] = dependentArray;
  12637. if (previousDependentArray) {
  12638. meta.dependentArraysObserver.teardownObservers(previousDependentArray, dependentKey);
  12639. }
  12640. if (dependentArray) {
  12641. meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey);
  12642. }
  12643. }
  12644. }, this);
  12645. }, this);
  12646. forEach(cp._dependentKeys, function(dependentKey) {
  12647. if (!partiallyRecomputeFor(this, dependentKey)) { return; }
  12648. var dependentArray = get(this, dependentKey);
  12649. if (dependentArray) {
  12650. addItems.call(this, dependentArray, callbacks, cp, propertyName, meta);
  12651. }
  12652. }, this);
  12653. };
  12654. this.func = function (propertyName) {
  12655. Ember.assert("Computed reduce values require at least one dependent key", cp._dependentKeys);
  12656. recompute.call(this, propertyName);
  12657. return cp._instanceMeta(this, propertyName).getValue();
  12658. };
  12659. }
  12660. Ember.ReduceComputedProperty = ReduceComputedProperty;
  12661. ReduceComputedProperty.prototype = o_create(ComputedProperty.prototype);
  12662. function defaultCallback(computedValue) {
  12663. return computedValue;
  12664. }
  12665. ReduceComputedProperty.prototype._callbacks = function () {
  12666. if (!this.callbacks) {
  12667. var options = this.options;
  12668. this.callbacks = {
  12669. removedItem: options.removedItem || defaultCallback,
  12670. addedItem: options.addedItem || defaultCallback
  12671. };
  12672. }
  12673. return this.callbacks;
  12674. };
  12675. ReduceComputedProperty.prototype._hasInstanceMeta = function (context, propertyName) {
  12676. var guid = guidFor(context),
  12677. key = guid + ':' + propertyName;
  12678. return !!this._instanceMetas[key];
  12679. };
  12680. ReduceComputedProperty.prototype._instanceMeta = function (context, propertyName) {
  12681. var guid = guidFor(context),
  12682. key = guid + ':' + propertyName,
  12683. meta = this._instanceMetas[key];
  12684. if (!meta) {
  12685. meta = this._instanceMetas[key] = new ReduceComputedPropertyInstanceMeta(context, propertyName, this.initialValue());
  12686. meta.dependentArraysObserver = new DependentArraysObserver(this._callbacks(), this, meta, context, propertyName, meta.sugarMeta);
  12687. }
  12688. return meta;
  12689. };
  12690. ReduceComputedProperty.prototype.initialValue = function () {
  12691. if (typeof this.options.initialValue === 'function') {
  12692. return this.options.initialValue();
  12693. }
  12694. else {
  12695. return this.options.initialValue;
  12696. }
  12697. };
  12698. ReduceComputedProperty.prototype.resetValue = function (value) {
  12699. return this.initialValue();
  12700. };
  12701. ReduceComputedProperty.prototype.itemPropertyKey = function (dependentArrayKey, itemPropertyKey) {
  12702. this._itemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey] || [];
  12703. this._itemPropertyKeys[dependentArrayKey].push(itemPropertyKey);
  12704. };
  12705. ReduceComputedProperty.prototype.clearItemPropertyKeys = function (dependentArrayKey) {
  12706. if (this._itemPropertyKeys[dependentArrayKey]) {
  12707. this._previousItemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey];
  12708. this._itemPropertyKeys[dependentArrayKey] = [];
  12709. }
  12710. };
  12711. ReduceComputedProperty.prototype.property = function () {
  12712. var cp = this,
  12713. args = a_slice.call(arguments),
  12714. propertyArgs = new Ember.Set(),
  12715. match,
  12716. dependentArrayKey,
  12717. itemPropertyKey;
  12718. forEach(a_slice.call(arguments), function (dependentKey) {
  12719. if (doubleEachPropertyPattern.test(dependentKey)) {
  12720. throw new Ember.Error("Nested @each properties not supported: " + dependentKey);
  12721. } else if (match = eachPropertyPattern.exec(dependentKey)) {
  12722. dependentArrayKey = match[1];
  12723. var itemPropertyKeyPattern = match[2],
  12724. addItemPropertyKey = function (itemPropertyKey) {
  12725. cp.itemPropertyKey(dependentArrayKey, itemPropertyKey);
  12726. };
  12727. expandProperties(itemPropertyKeyPattern, addItemPropertyKey);
  12728. propertyArgs.add(dependentArrayKey);
  12729. } else {
  12730. propertyArgs.add(dependentKey);
  12731. }
  12732. });
  12733. return ComputedProperty.prototype.property.apply(this, propertyArgs.toArray());
  12734. };
  12735. /**
  12736. Creates a computed property which operates on dependent arrays and
  12737. is updated with "one at a time" semantics. When items are added or
  12738. removed from the dependent array(s) a reduce computed only operates
  12739. on the change instead of re-evaluating the entire array.
  12740. If there are more than one arguments the first arguments are
  12741. considered to be dependent property keys. The last argument is
  12742. required to be an options object. The options object can have the
  12743. following four properties:
  12744. `initialValue` - A value or function that will be used as the initial
  12745. value for the computed. If this property is a function the result of calling
  12746. the function will be used as the initial value. This property is required.
  12747. `initialize` - An optional initialize function. Typically this will be used
  12748. to set up state on the instanceMeta object.
  12749. `removedItem` - A function that is called each time an element is removed
  12750. from the array.
  12751. `addedItem` - A function that is called each time an element is added to
  12752. the array.
  12753. The `initialize` function has the following signature:
  12754. ```javascript
  12755. function (initialValue, changeMeta, instanceMeta)
  12756. ```
  12757. `initialValue` - The value of the `initialValue` property from the
  12758. options object.
  12759. `changeMeta` - An object which contains meta information about the
  12760. computed. It contains the following properties:
  12761. - `property` the computed property
  12762. - `propertyName` the name of the property on the object
  12763. `instanceMeta` - An object that can be used to store meta
  12764. information needed for calculating your computed. For example a
  12765. unique computed might use this to store the number of times a given
  12766. element is found in the dependent array.
  12767. The `removedItem` and `addedItem` functions both have the following signature:
  12768. ```javascript
  12769. function (accumulatedValue, item, changeMeta, instanceMeta)
  12770. ```
  12771. `accumulatedValue` - The value returned from the last time
  12772. `removedItem` or `addedItem` was called or `initialValue`.
  12773. `item` - the element added or removed from the array
  12774. `changeMeta` - An object which contains meta information about the
  12775. change. It contains the following properties:
  12776. - `property` the computed property
  12777. - `propertyName` the name of the property on the object
  12778. - `index` the index of the added or removed item
  12779. - `item` the added or removed item: this is exactly the same as
  12780. the second arg
  12781. - `arrayChanged` the array that triggered the change. Can be
  12782. useful when depending on multiple arrays.
  12783. For property changes triggered on an item property change (when
  12784. depKey is something like `someArray.@each.someProperty`),
  12785. `changeMeta` will also contain the following property:
  12786. - `previousValues` an object whose keys are the properties that changed on
  12787. the item, and whose values are the item's previous values.
  12788. `previousValues` is important Ember coalesces item property changes via
  12789. Ember.run.once. This means that by the time removedItem gets called, item has
  12790. the new values, but you may need the previous value (eg for sorting &
  12791. filtering).
  12792. `instanceMeta` - An object that can be used to store meta
  12793. information needed for calculating your computed. For example a
  12794. unique computed might use this to store the number of times a given
  12795. element is found in the dependent array.
  12796. The `removedItem` and `addedItem` functions should return the accumulated
  12797. value. It is acceptable to not return anything (ie return undefined)
  12798. to invalidate the computation. This is generally not a good idea for
  12799. arrayComputed but it's used in eg max and min.
  12800. Note that observers will be fired if either of these functions return a value
  12801. that differs from the accumulated value. When returning an object that
  12802. mutates in response to array changes, for example an array that maps
  12803. everything from some other array (see `Ember.computed.map`), it is usually
  12804. important that the *same* array be returned to avoid accidentally triggering observers.
  12805. Example
  12806. ```javascript
  12807. Ember.computed.max = function (dependentKey) {
  12808. return Ember.reduceComputed(dependentKey, {
  12809. initialValue: -Infinity,
  12810. addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
  12811. return Math.max(accumulatedValue, item);
  12812. },
  12813. removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
  12814. if (item < accumulatedValue) {
  12815. return accumulatedValue;
  12816. }
  12817. }
  12818. });
  12819. };
  12820. ```
  12821. Dependent keys may refer to `@this` to observe changes to the object itself,
  12822. which must be array-like, rather than a property of the object. This is
  12823. mostly useful for array proxies, to ensure objects are retrieved via
  12824. `objectAtContent`. This is how you could sort items by properties defined on an item controller.
  12825. Example
  12826. ```javascript
  12827. App.PeopleController = Ember.ArrayController.extend({
  12828. itemController: 'person',
  12829. sortedPeople: Ember.computed.sort('@this.@each.reversedName', function(personA, personB) {
  12830. // `reversedName` isn't defined on Person, but we have access to it via
  12831. // the item controller App.PersonController. If we'd used
  12832. // `content.@each.reversedName` above, we would be getting the objects
  12833. // directly and not have access to `reversedName`.
  12834. //
  12835. var reversedNameA = get(personA, 'reversedName'),
  12836. reversedNameB = get(personB, 'reversedName');
  12837. return Ember.compare(reversedNameA, reversedNameB);
  12838. })
  12839. });
  12840. App.PersonController = Ember.ObjectController.extend({
  12841. reversedName: function () {
  12842. return reverse(get(this, 'name'));
  12843. }.property('name')
  12844. })
  12845. ```
  12846. Dependent keys whose values are not arrays are treated as regular
  12847. dependencies: when they change, the computed property is completely
  12848. recalculated. It is sometimes useful to have dependent arrays with similar
  12849. semantics. Dependent keys which end in `.[]` do not use "one at a time"
  12850. semantics. When an item is added or removed from such a dependency, the
  12851. computed property is completely recomputed.
  12852. Example
  12853. ```javascript
  12854. Ember.Object.extend({
  12855. // When `string` is changed, `computed` is completely recomputed.
  12856. string: 'a string',
  12857. // When an item is added to `array`, `addedItem` is called.
  12858. array: [],
  12859. // When an item is added to `anotherArray`, `computed` is completely
  12860. // recomputed.
  12861. anotherArray: [],
  12862. computed: Ember.reduceComputed('string', 'array', 'anotherArray.[]', {
  12863. addedItem: addedItemCallback,
  12864. removedItem: removedItemCallback
  12865. })
  12866. });
  12867. ```
  12868. @method reduceComputed
  12869. @for Ember
  12870. @param {String} [dependentKeys*]
  12871. @param {Object} options
  12872. @return {Ember.ComputedProperty}
  12873. */
  12874. Ember.reduceComputed = function (options) {
  12875. var args;
  12876. if (arguments.length > 1) {
  12877. args = a_slice.call(arguments, 0, -1);
  12878. options = a_slice.call(arguments, -1)[0];
  12879. }
  12880. if (typeof options !== "object") {
  12881. throw new Ember.Error("Reduce Computed Property declared without an options hash");
  12882. }
  12883. if (!('initialValue' in options)) {
  12884. throw new Ember.Error("Reduce Computed Property declared without an initial value");
  12885. }
  12886. var cp = new ReduceComputedProperty(options);
  12887. if (args) {
  12888. cp.property.apply(cp, args);
  12889. }
  12890. return cp;
  12891. };
  12892. })();
  12893. (function() {
  12894. var ReduceComputedProperty = Ember.ReduceComputedProperty,
  12895. a_slice = [].slice,
  12896. o_create = Ember.create,
  12897. forEach = Ember.EnumerableUtils.forEach;
  12898. function ArrayComputedProperty() {
  12899. var cp = this;
  12900. ReduceComputedProperty.apply(this, arguments);
  12901. this.func = (function(reduceFunc) {
  12902. return function (propertyName) {
  12903. if (!cp._hasInstanceMeta(this, propertyName)) {
  12904. // When we recompute an array computed property, we need already
  12905. // retrieved arrays to be updated; we can't simply empty the cache and
  12906. // hope the array is re-retrieved.
  12907. forEach(cp._dependentKeys, function(dependentKey) {
  12908. Ember.addObserver(this, dependentKey, function() {
  12909. cp.recomputeOnce.call(this, propertyName);
  12910. });
  12911. }, this);
  12912. }
  12913. return reduceFunc.apply(this, arguments);
  12914. };
  12915. })(this.func);
  12916. return this;
  12917. }
  12918. Ember.ArrayComputedProperty = ArrayComputedProperty;
  12919. ArrayComputedProperty.prototype = o_create(ReduceComputedProperty.prototype);
  12920. ArrayComputedProperty.prototype.initialValue = function () {
  12921. return Ember.A();
  12922. };
  12923. ArrayComputedProperty.prototype.resetValue = function (array) {
  12924. array.clear();
  12925. return array;
  12926. };
  12927. // This is a stopgap to keep the reference counts correct with lazy CPs.
  12928. ArrayComputedProperty.prototype.didChange = function (obj, keyName) {
  12929. return;
  12930. };
  12931. /**
  12932. Creates a computed property which operates on dependent arrays and
  12933. is updated with "one at a time" semantics. When items are added or
  12934. removed from the dependent array(s) an array computed only operates
  12935. on the change instead of re-evaluating the entire array. This should
  12936. return an array, if you'd like to use "one at a time" semantics and
  12937. compute some value other then an array look at
  12938. `Ember.reduceComputed`.
  12939. If there are more than one arguments the first arguments are
  12940. considered to be dependent property keys. The last argument is
  12941. required to be an options object. The options object can have the
  12942. following three properties.
  12943. `initialize` - An optional initialize function. Typically this will be used
  12944. to set up state on the instanceMeta object.
  12945. `removedItem` - A function that is called each time an element is
  12946. removed from the array.
  12947. `addedItem` - A function that is called each time an element is
  12948. added to the array.
  12949. The `initialize` function has the following signature:
  12950. ```javascript
  12951. function (array, changeMeta, instanceMeta)
  12952. ```
  12953. `array` - The initial value of the arrayComputed, an empty array.
  12954. `changeMeta` - An object which contains meta information about the
  12955. computed. It contains the following properties:
  12956. - `property` the computed property
  12957. - `propertyName` the name of the property on the object
  12958. `instanceMeta` - An object that can be used to store meta
  12959. information needed for calculating your computed. For example a
  12960. unique computed might use this to store the number of times a given
  12961. element is found in the dependent array.
  12962. The `removedItem` and `addedItem` functions both have the following signature:
  12963. ```javascript
  12964. function (accumulatedValue, item, changeMeta, instanceMeta)
  12965. ```
  12966. `accumulatedValue` - The value returned from the last time
  12967. `removedItem` or `addedItem` was called or an empty array.
  12968. `item` - the element added or removed from the array
  12969. `changeMeta` - An object which contains meta information about the
  12970. change. It contains the following properties:
  12971. - `property` the computed property
  12972. - `propertyName` the name of the property on the object
  12973. - `index` the index of the added or removed item
  12974. - `item` the added or removed item: this is exactly the same as
  12975. the second arg
  12976. - `arrayChanged` the array that triggered the change. Can be
  12977. useful when depending on multiple arrays.
  12978. For property changes triggered on an item property change (when
  12979. depKey is something like `someArray.@each.someProperty`),
  12980. `changeMeta` will also contain the following property:
  12981. - `previousValues` an object whose keys are the properties that changed on
  12982. the item, and whose values are the item's previous values.
  12983. `previousValues` is important Ember coalesces item property changes via
  12984. Ember.run.once. This means that by the time removedItem gets called, item has
  12985. the new values, but you may need the previous value (eg for sorting &
  12986. filtering).
  12987. `instanceMeta` - An object that can be used to store meta
  12988. information needed for calculating your computed. For example a
  12989. unique computed might use this to store the number of times a given
  12990. element is found in the dependent array.
  12991. The `removedItem` and `addedItem` functions should return the accumulated
  12992. value. It is acceptable to not return anything (ie return undefined)
  12993. to invalidate the computation. This is generally not a good idea for
  12994. arrayComputed but it's used in eg max and min.
  12995. Example
  12996. ```javascript
  12997. Ember.computed.map = function(dependentKey, callback) {
  12998. var options = {
  12999. addedItem: function(array, item, changeMeta, instanceMeta) {
  13000. var mapped = callback(item);
  13001. array.insertAt(changeMeta.index, mapped);
  13002. return array;
  13003. },
  13004. removedItem: function(array, item, changeMeta, instanceMeta) {
  13005. array.removeAt(changeMeta.index, 1);
  13006. return array;
  13007. }
  13008. };
  13009. return Ember.arrayComputed(dependentKey, options);
  13010. };
  13011. ```
  13012. @method arrayComputed
  13013. @for Ember
  13014. @param {String} [dependentKeys*]
  13015. @param {Object} options
  13016. @return {Ember.ComputedProperty}
  13017. */
  13018. Ember.arrayComputed = function (options) {
  13019. var args;
  13020. if (arguments.length > 1) {
  13021. args = a_slice.call(arguments, 0, -1);
  13022. options = a_slice.call(arguments, -1)[0];
  13023. }
  13024. if (typeof options !== "object") {
  13025. throw new Ember.Error("Array Computed Property declared without an options hash");
  13026. }
  13027. var cp = new ArrayComputedProperty(options);
  13028. if (args) {
  13029. cp.property.apply(cp, args);
  13030. }
  13031. return cp;
  13032. };
  13033. })();
  13034. (function() {
  13035. /**
  13036. @module ember
  13037. @submodule ember-runtime
  13038. */
  13039. var get = Ember.get,
  13040. set = Ember.set,
  13041. guidFor = Ember.guidFor,
  13042. merge = Ember.merge,
  13043. a_slice = [].slice,
  13044. forEach = Ember.EnumerableUtils.forEach,
  13045. map = Ember.EnumerableUtils.map,
  13046. SearchProxy;
  13047. /**
  13048. A computed property that returns the sum of the value
  13049. in the dependent array.
  13050. @method computed.sum
  13051. @for Ember
  13052. @param {String} dependentKey
  13053. @return {Ember.ComputedProperty} computes the sum of all values in the dependentKey's array
  13054. */
  13055. Ember.computed.sum = function(dependentKey){
  13056. return Ember.reduceComputed(dependentKey, {
  13057. initialValue: 0,
  13058. addedItem: function(accumulatedValue, item, changeMeta, instanceMeta){
  13059. return accumulatedValue + item;
  13060. },
  13061. removedItem: function(accumulatedValue, item, changeMeta, instanceMeta){
  13062. return accumulatedValue - item;
  13063. }
  13064. });
  13065. };
  13066. /**
  13067. A computed property that calculates the maximum value in the
  13068. dependent array. This will return `-Infinity` when the dependent
  13069. array is empty.
  13070. ```javascript
  13071. App.Person = Ember.Object.extend({
  13072. childAges: Ember.computed.mapBy('children', 'age'),
  13073. maxChildAge: Ember.computed.max('childAges')
  13074. });
  13075. var lordByron = App.Person.create({children: []});
  13076. lordByron.get('maxChildAge'); // -Infinity
  13077. lordByron.get('children').pushObject({
  13078. name: 'Augusta Ada Byron', age: 7
  13079. });
  13080. lordByron.get('maxChildAge'); // 7
  13081. lordByron.get('children').pushObjects([{
  13082. name: 'Allegra Byron',
  13083. age: 5
  13084. }, {
  13085. name: 'Elizabeth Medora Leigh',
  13086. age: 8
  13087. }]);
  13088. lordByron.get('maxChildAge'); // 8
  13089. ```
  13090. @method computed.max
  13091. @for Ember
  13092. @param {String} dependentKey
  13093. @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array
  13094. */
  13095. Ember.computed.max = function (dependentKey) {
  13096. return Ember.reduceComputed(dependentKey, {
  13097. initialValue: -Infinity,
  13098. addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
  13099. return Math.max(accumulatedValue, item);
  13100. },
  13101. removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
  13102. if (item < accumulatedValue) {
  13103. return accumulatedValue;
  13104. }
  13105. }
  13106. });
  13107. };
  13108. /**
  13109. A computed property that calculates the minimum value in the
  13110. dependent array. This will return `Infinity` when the dependent
  13111. array is empty.
  13112. ```javascript
  13113. App.Person = Ember.Object.extend({
  13114. childAges: Ember.computed.mapBy('children', 'age'),
  13115. minChildAge: Ember.computed.min('childAges')
  13116. });
  13117. var lordByron = App.Person.create({children: []});
  13118. lordByron.get('minChildAge'); // Infinity
  13119. lordByron.get('children').pushObject({
  13120. name: 'Augusta Ada Byron', age: 7
  13121. });
  13122. lordByron.get('minChildAge'); // 7
  13123. lordByron.get('children').pushObjects([{
  13124. name: 'Allegra Byron',
  13125. age: 5
  13126. }, {
  13127. name: 'Elizabeth Medora Leigh',
  13128. age: 8
  13129. }]);
  13130. lordByron.get('minChildAge'); // 5
  13131. ```
  13132. @method computed.min
  13133. @for Ember
  13134. @param {String} dependentKey
  13135. @return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array
  13136. */
  13137. Ember.computed.min = function (dependentKey) {
  13138. return Ember.reduceComputed(dependentKey, {
  13139. initialValue: Infinity,
  13140. addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
  13141. return Math.min(accumulatedValue, item);
  13142. },
  13143. removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
  13144. if (item > accumulatedValue) {
  13145. return accumulatedValue;
  13146. }
  13147. }
  13148. });
  13149. };
  13150. /**
  13151. Returns an array mapped via the callback
  13152. The callback method you provide should have the following signature.
  13153. `item` is the current item in the iteration.
  13154. ```javascript
  13155. function(item);
  13156. ```
  13157. Example
  13158. ```javascript
  13159. App.Hamster = Ember.Object.extend({
  13160. excitingChores: Ember.computed.map('chores', function(chore) {
  13161. return chore.toUpperCase() + '!';
  13162. })
  13163. });
  13164. var hamster = App.Hamster.create({
  13165. chores: ['clean', 'write more unit tests']
  13166. });
  13167. hamster.get('excitingChores'); // ['CLEAN!', 'WRITE MORE UNIT TESTS!']
  13168. ```
  13169. @method computed.map
  13170. @for Ember
  13171. @param {String} dependentKey
  13172. @param {Function} callback
  13173. @return {Ember.ComputedProperty} an array mapped via the callback
  13174. */
  13175. Ember.computed.map = function(dependentKey, callback) {
  13176. var options = {
  13177. addedItem: function(array, item, changeMeta, instanceMeta) {
  13178. var mapped = callback.call(this, item);
  13179. array.insertAt(changeMeta.index, mapped);
  13180. return array;
  13181. },
  13182. removedItem: function(array, item, changeMeta, instanceMeta) {
  13183. array.removeAt(changeMeta.index, 1);
  13184. return array;
  13185. }
  13186. };
  13187. return Ember.arrayComputed(dependentKey, options);
  13188. };
  13189. /**
  13190. Returns an array mapped to the specified key.
  13191. ```javascript
  13192. App.Person = Ember.Object.extend({
  13193. childAges: Ember.computed.mapBy('children', 'age')
  13194. });
  13195. var lordByron = App.Person.create({children: []});
  13196. lordByron.get('childAges'); // []
  13197. lordByron.get('children').pushObject({name: 'Augusta Ada Byron', age: 7});
  13198. lordByron.get('childAges'); // [7]
  13199. lordByron.get('children').pushObjects([{
  13200. name: 'Allegra Byron',
  13201. age: 5
  13202. }, {
  13203. name: 'Elizabeth Medora Leigh',
  13204. age: 8
  13205. }]);
  13206. lordByron.get('childAges'); // [7, 5, 8]
  13207. ```
  13208. @method computed.mapBy
  13209. @for Ember
  13210. @param {String} dependentKey
  13211. @param {String} propertyKey
  13212. @return {Ember.ComputedProperty} an array mapped to the specified key
  13213. */
  13214. Ember.computed.mapBy = function(dependentKey, propertyKey) {
  13215. var callback = function(item) { return get(item, propertyKey); };
  13216. return Ember.computed.map(dependentKey + '.@each.' + propertyKey, callback);
  13217. };
  13218. /**
  13219. @method computed.mapProperty
  13220. @for Ember
  13221. @deprecated Use `Ember.computed.mapBy` instead
  13222. @param dependentKey
  13223. @param propertyKey
  13224. */
  13225. Ember.computed.mapProperty = Ember.computed.mapBy;
  13226. /**
  13227. Filters the array by the callback.
  13228. The callback method you provide should have the following signature.
  13229. `item` is the current item in the iteration.
  13230. ```javascript
  13231. function(item);
  13232. ```
  13233. ```javascript
  13234. App.Hamster = Ember.Object.extend({
  13235. remainingChores: Ember.computed.filter('chores', function(chore) {
  13236. return !chore.done;
  13237. })
  13238. });
  13239. var hamster = App.Hamster.create({chores: [
  13240. {name: 'cook', done: true},
  13241. {name: 'clean', done: true},
  13242. {name: 'write more unit tests', done: false}
  13243. ]});
  13244. hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}]
  13245. ```
  13246. @method computed.filter
  13247. @for Ember
  13248. @param {String} dependentKey
  13249. @param {Function} callback
  13250. @return {Ember.ComputedProperty} the filtered array
  13251. */
  13252. Ember.computed.filter = function(dependentKey, callback) {
  13253. var options = {
  13254. initialize: function (array, changeMeta, instanceMeta) {
  13255. instanceMeta.filteredArrayIndexes = new Ember.SubArray();
  13256. },
  13257. addedItem: function(array, item, changeMeta, instanceMeta) {
  13258. var match = !!callback.call(this, item),
  13259. filterIndex = instanceMeta.filteredArrayIndexes.addItem(changeMeta.index, match);
  13260. if (match) {
  13261. array.insertAt(filterIndex, item);
  13262. }
  13263. return array;
  13264. },
  13265. removedItem: function(array, item, changeMeta, instanceMeta) {
  13266. var filterIndex = instanceMeta.filteredArrayIndexes.removeItem(changeMeta.index);
  13267. if (filterIndex > -1) {
  13268. array.removeAt(filterIndex);
  13269. }
  13270. return array;
  13271. }
  13272. };
  13273. return Ember.arrayComputed(dependentKey, options);
  13274. };
  13275. /**
  13276. Filters the array by the property and value
  13277. ```javascript
  13278. App.Hamster = Ember.Object.extend({
  13279. remainingChores: Ember.computed.filterBy('chores', 'done', false)
  13280. });
  13281. var hamster = App.Hamster.create({chores: [
  13282. {name: 'cook', done: true},
  13283. {name: 'clean', done: true},
  13284. {name: 'write more unit tests', done: false}
  13285. ]});
  13286. hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}]
  13287. ```
  13288. @method computed.filterBy
  13289. @for Ember
  13290. @param {String} dependentKey
  13291. @param {String} propertyKey
  13292. @param {String} value
  13293. @return {Ember.ComputedProperty} the filtered array
  13294. */
  13295. Ember.computed.filterBy = function(dependentKey, propertyKey, value) {
  13296. var callback;
  13297. if (arguments.length === 2) {
  13298. callback = function(item) {
  13299. return get(item, propertyKey);
  13300. };
  13301. } else {
  13302. callback = function(item) {
  13303. return get(item, propertyKey) === value;
  13304. };
  13305. }
  13306. return Ember.computed.filter(dependentKey + '.@each.' + propertyKey, callback);
  13307. };
  13308. /**
  13309. @method computed.filterProperty
  13310. @for Ember
  13311. @param dependentKey
  13312. @param propertyKey
  13313. @param value
  13314. @deprecated Use `Ember.computed.filterBy` instead
  13315. */
  13316. Ember.computed.filterProperty = Ember.computed.filterBy;
  13317. /**
  13318. A computed property which returns a new array with all the unique
  13319. elements from one or more dependent arrays.
  13320. Example
  13321. ```javascript
  13322. App.Hamster = Ember.Object.extend({
  13323. uniqueFruits: Ember.computed.uniq('fruits')
  13324. });
  13325. var hamster = App.Hamster.create({fruits: [
  13326. 'banana',
  13327. 'grape',
  13328. 'kale',
  13329. 'banana'
  13330. ]});
  13331. hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale']
  13332. ```
  13333. @method computed.uniq
  13334. @for Ember
  13335. @param {String} propertyKey*
  13336. @return {Ember.ComputedProperty} computes a new array with all the
  13337. unique elements from the dependent array
  13338. */
  13339. Ember.computed.uniq = function() {
  13340. var args = a_slice.call(arguments);
  13341. args.push({
  13342. initialize: function(array, changeMeta, instanceMeta) {
  13343. instanceMeta.itemCounts = {};
  13344. },
  13345. addedItem: function(array, item, changeMeta, instanceMeta) {
  13346. var guid = guidFor(item);
  13347. if (!instanceMeta.itemCounts[guid]) {
  13348. instanceMeta.itemCounts[guid] = 1;
  13349. } else {
  13350. ++instanceMeta.itemCounts[guid];
  13351. }
  13352. array.addObject(item);
  13353. return array;
  13354. },
  13355. removedItem: function(array, item, _, instanceMeta) {
  13356. var guid = guidFor(item),
  13357. itemCounts = instanceMeta.itemCounts;
  13358. if (--itemCounts[guid] === 0) {
  13359. array.removeObject(item);
  13360. }
  13361. return array;
  13362. }
  13363. });
  13364. return Ember.arrayComputed.apply(null, args);
  13365. };
  13366. /**
  13367. Alias for [Ember.computed.uniq](/api/#method_computed_uniq).
  13368. @method computed.union
  13369. @for Ember
  13370. @param {String} propertyKey*
  13371. @return {Ember.ComputedProperty} computes a new array with all the
  13372. unique elements from the dependent array
  13373. */
  13374. Ember.computed.union = Ember.computed.uniq;
  13375. /**
  13376. A computed property which returns a new array with all the duplicated
  13377. elements from two or more dependent arrays.
  13378. Example
  13379. ```javascript
  13380. var obj = Ember.Object.createWithMixins({
  13381. adaFriends: ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'],
  13382. charlesFriends: ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'],
  13383. friendsInCommon: Ember.computed.intersect('adaFriends', 'charlesFriends')
  13384. });
  13385. obj.get('friendsInCommon'); // ['William King', 'Mary Somerville']
  13386. ```
  13387. @method computed.intersect
  13388. @for Ember
  13389. @param {String} propertyKey*
  13390. @return {Ember.ComputedProperty} computes a new array with all the
  13391. duplicated elements from the dependent arrays
  13392. */
  13393. Ember.computed.intersect = function () {
  13394. var getDependentKeyGuids = function (changeMeta) {
  13395. return map(changeMeta.property._dependentKeys, function (dependentKey) {
  13396. return guidFor(dependentKey);
  13397. });
  13398. };
  13399. var args = a_slice.call(arguments);
  13400. args.push({
  13401. initialize: function (array, changeMeta, instanceMeta) {
  13402. instanceMeta.itemCounts = {};
  13403. },
  13404. addedItem: function(array, item, changeMeta, instanceMeta) {
  13405. var itemGuid = guidFor(item),
  13406. dependentGuids = getDependentKeyGuids(changeMeta),
  13407. dependentGuid = guidFor(changeMeta.arrayChanged),
  13408. numberOfDependentArrays = changeMeta.property._dependentKeys.length,
  13409. itemCounts = instanceMeta.itemCounts;
  13410. if (!itemCounts[itemGuid]) { itemCounts[itemGuid] = {}; }
  13411. if (itemCounts[itemGuid][dependentGuid] === undefined) { itemCounts[itemGuid][dependentGuid] = 0; }
  13412. if (++itemCounts[itemGuid][dependentGuid] === 1 &&
  13413. numberOfDependentArrays === Ember.keys(itemCounts[itemGuid]).length) {
  13414. array.addObject(item);
  13415. }
  13416. return array;
  13417. },
  13418. removedItem: function(array, item, changeMeta, instanceMeta) {
  13419. var itemGuid = guidFor(item),
  13420. dependentGuids = getDependentKeyGuids(changeMeta),
  13421. dependentGuid = guidFor(changeMeta.arrayChanged),
  13422. numberOfDependentArrays = changeMeta.property._dependentKeys.length,
  13423. numberOfArraysItemAppearsIn,
  13424. itemCounts = instanceMeta.itemCounts;
  13425. if (itemCounts[itemGuid][dependentGuid] === undefined) { itemCounts[itemGuid][dependentGuid] = 0; }
  13426. if (--itemCounts[itemGuid][dependentGuid] === 0) {
  13427. delete itemCounts[itemGuid][dependentGuid];
  13428. numberOfArraysItemAppearsIn = Ember.keys(itemCounts[itemGuid]).length;
  13429. if (numberOfArraysItemAppearsIn === 0) {
  13430. delete itemCounts[itemGuid];
  13431. }
  13432. array.removeObject(item);
  13433. }
  13434. return array;
  13435. }
  13436. });
  13437. return Ember.arrayComputed.apply(null, args);
  13438. };
  13439. /**
  13440. A computed property which returns a new array with all the
  13441. properties from the first dependent array that are not in the second
  13442. dependent array.
  13443. Example
  13444. ```javascript
  13445. App.Hamster = Ember.Object.extend({
  13446. likes: ['banana', 'grape', 'kale'],
  13447. wants: Ember.computed.setDiff('likes', 'fruits')
  13448. });
  13449. var hamster = App.Hamster.create({fruits: [
  13450. 'grape',
  13451. 'kale',
  13452. ]});
  13453. hamster.get('wants'); // ['banana']
  13454. ```
  13455. @method computed.setDiff
  13456. @for Ember
  13457. @param {String} setAProperty
  13458. @param {String} setBProperty
  13459. @return {Ember.ComputedProperty} computes a new array with all the
  13460. items from the first dependent array that are not in the second
  13461. dependent array
  13462. */
  13463. Ember.computed.setDiff = function (setAProperty, setBProperty) {
  13464. if (arguments.length !== 2) {
  13465. throw new Ember.Error("setDiff requires exactly two dependent arrays.");
  13466. }
  13467. return Ember.arrayComputed(setAProperty, setBProperty, {
  13468. addedItem: function (array, item, changeMeta, instanceMeta) {
  13469. var setA = get(this, setAProperty),
  13470. setB = get(this, setBProperty);
  13471. if (changeMeta.arrayChanged === setA) {
  13472. if (!setB.contains(item)) {
  13473. array.addObject(item);
  13474. }
  13475. } else {
  13476. array.removeObject(item);
  13477. }
  13478. return array;
  13479. },
  13480. removedItem: function (array, item, changeMeta, instanceMeta) {
  13481. var setA = get(this, setAProperty),
  13482. setB = get(this, setBProperty);
  13483. if (changeMeta.arrayChanged === setB) {
  13484. if (setA.contains(item)) {
  13485. array.addObject(item);
  13486. }
  13487. } else {
  13488. array.removeObject(item);
  13489. }
  13490. return array;
  13491. }
  13492. });
  13493. };
  13494. function binarySearch(array, item, low, high) {
  13495. var mid, midItem, res, guidMid, guidItem;
  13496. if (arguments.length < 4) { high = get(array, 'length'); }
  13497. if (arguments.length < 3) { low = 0; }
  13498. if (low === high) {
  13499. return low;
  13500. }
  13501. mid = low + Math.floor((high - low) / 2);
  13502. midItem = array.objectAt(mid);
  13503. guidMid = _guidFor(midItem);
  13504. guidItem = _guidFor(item);
  13505. if (guidMid === guidItem) {
  13506. return mid;
  13507. }
  13508. res = this.order(midItem, item);
  13509. if (res === 0) {
  13510. res = guidMid < guidItem ? -1 : 1;
  13511. }
  13512. if (res < 0) {
  13513. return this.binarySearch(array, item, mid+1, high);
  13514. } else if (res > 0) {
  13515. return this.binarySearch(array, item, low, mid);
  13516. }
  13517. return mid;
  13518. function _guidFor(item) {
  13519. if (SearchProxy.detectInstance(item)) {
  13520. return guidFor(get(item, 'content'));
  13521. }
  13522. return guidFor(item);
  13523. }
  13524. }
  13525. SearchProxy = Ember.ObjectProxy.extend();
  13526. /**
  13527. A computed property which returns a new array with all the
  13528. properties from the first dependent array sorted based on a property
  13529. or sort function.
  13530. The callback method you provide should have the following signature:
  13531. ```javascript
  13532. function(itemA, itemB);
  13533. ```
  13534. - `itemA` the first item to compare.
  13535. - `itemB` the second item to compare.
  13536. This function should return `-1` when `itemA` should come before
  13537. `itemB`. It should return `1` when `itemA` should come after
  13538. `itemB`. If the `itemA` and `itemB` are equal this function should return `0`.
  13539. Example
  13540. ```javascript
  13541. var ToDoList = Ember.Object.extend({
  13542. todosSorting: ['name'],
  13543. sortedTodos: Ember.computed.sort('todos', 'todosSorting'),
  13544. priorityTodos: Ember.computed.sort('todos', function(a, b){
  13545. if (a.priority > b.priority) {
  13546. return 1;
  13547. } else if (a.priority < b.priority) {
  13548. return -1;
  13549. }
  13550. return 0;
  13551. }),
  13552. });
  13553. var todoList = ToDoList.create({todos: [
  13554. {name: 'Unit Test', priority: 2},
  13555. {name: 'Documentation', priority: 3},
  13556. {name: 'Release', priority: 1}
  13557. ]});
  13558. todoList.get('sortedTodos'); // [{name:'Documentation', priority:3}, {name:'Release', priority:1}, {name:'Unit Test', priority:2}]
  13559. todoList.get('priorityTodos'); // [{name:'Release', priority:1}, {name:'Unit Test', priority:2}, {name:'Documentation', priority:3}]
  13560. ```
  13561. @method computed.sort
  13562. @for Ember
  13563. @param {String} dependentKey
  13564. @param {String or Function} sortDefinition a dependent key to an
  13565. array of sort properties or a function to use when sorting
  13566. @return {Ember.ComputedProperty} computes a new sorted array based
  13567. on the sort property array or callback function
  13568. */
  13569. Ember.computed.sort = function (itemsKey, sortDefinition) {
  13570. Ember.assert("Ember.computed.sort requires two arguments: an array key to sort and either a sort properties key or sort function", arguments.length === 2);
  13571. var initFn, sortPropertiesKey;
  13572. if (typeof sortDefinition === 'function') {
  13573. initFn = function (array, changeMeta, instanceMeta) {
  13574. instanceMeta.order = sortDefinition;
  13575. instanceMeta.binarySearch = binarySearch;
  13576. };
  13577. } else {
  13578. sortPropertiesKey = sortDefinition;
  13579. initFn = function (array, changeMeta, instanceMeta) {
  13580. function setupSortProperties() {
  13581. var sortPropertyDefinitions = get(this, sortPropertiesKey),
  13582. sortProperty,
  13583. sortProperties = instanceMeta.sortProperties = [],
  13584. sortPropertyAscending = instanceMeta.sortPropertyAscending = {},
  13585. idx,
  13586. asc;
  13587. Ember.assert("Cannot sort: '" + sortPropertiesKey + "' is not an array.", Ember.isArray(sortPropertyDefinitions));
  13588. changeMeta.property.clearItemPropertyKeys(itemsKey);
  13589. forEach(sortPropertyDefinitions, function (sortPropertyDefinition) {
  13590. if ((idx = sortPropertyDefinition.indexOf(':')) !== -1) {
  13591. sortProperty = sortPropertyDefinition.substring(0, idx);
  13592. asc = sortPropertyDefinition.substring(idx+1).toLowerCase() !== 'desc';
  13593. } else {
  13594. sortProperty = sortPropertyDefinition;
  13595. asc = true;
  13596. }
  13597. sortProperties.push(sortProperty);
  13598. sortPropertyAscending[sortProperty] = asc;
  13599. changeMeta.property.itemPropertyKey(itemsKey, sortProperty);
  13600. });
  13601. sortPropertyDefinitions.addObserver('@each', this, updateSortPropertiesOnce);
  13602. }
  13603. function updateSortPropertiesOnce() {
  13604. Ember.run.once(this, updateSortProperties, changeMeta.propertyName);
  13605. }
  13606. function updateSortProperties(propertyName) {
  13607. setupSortProperties.call(this);
  13608. changeMeta.property.recomputeOnce.call(this, propertyName);
  13609. }
  13610. Ember.addObserver(this, sortPropertiesKey, updateSortPropertiesOnce);
  13611. setupSortProperties.call(this);
  13612. instanceMeta.order = function (itemA, itemB) {
  13613. var sortProperty, result, asc;
  13614. for (var i = 0; i < this.sortProperties.length; ++i) {
  13615. sortProperty = this.sortProperties[i];
  13616. result = Ember.compare(get(itemA, sortProperty), get(itemB, sortProperty));
  13617. if (result !== 0) {
  13618. asc = this.sortPropertyAscending[sortProperty];
  13619. return asc ? result : (-1 * result);
  13620. }
  13621. }
  13622. return 0;
  13623. };
  13624. instanceMeta.binarySearch = binarySearch;
  13625. };
  13626. }
  13627. return Ember.arrayComputed(itemsKey, {
  13628. initialize: initFn,
  13629. addedItem: function (array, item, changeMeta, instanceMeta) {
  13630. var index = instanceMeta.binarySearch(array, item);
  13631. array.insertAt(index, item);
  13632. return array;
  13633. },
  13634. removedItem: function (array, item, changeMeta, instanceMeta) {
  13635. var proxyProperties, index, searchItem;
  13636. if (changeMeta.previousValues) {
  13637. proxyProperties = merge({ content: item }, changeMeta.previousValues);
  13638. searchItem = SearchProxy.create(proxyProperties);
  13639. } else {
  13640. searchItem = item;
  13641. }
  13642. index = instanceMeta.binarySearch(array, searchItem);
  13643. array.removeAt(index);
  13644. return array;
  13645. }
  13646. });
  13647. };
  13648. })();
  13649. (function() {
  13650. Ember.RSVP = requireModule('rsvp');
  13651. Ember.RSVP.onerrorDefault = function(error) {
  13652. if (error instanceof Error) {
  13653. if (Ember.testing) {
  13654. if (Ember.Test && Ember.Test.adapter) {
  13655. Ember.Test.adapter.exception(error);
  13656. } else {
  13657. throw error;
  13658. }
  13659. } else {
  13660. Ember.Logger.error(error.stack);
  13661. Ember.assert(error, false);
  13662. }
  13663. }
  13664. };
  13665. Ember.RSVP.on('error', Ember.RSVP.onerrorDefault);
  13666. })();
  13667. (function() {
  13668. /**
  13669. @module ember
  13670. @submodule ember-runtime
  13671. */
  13672. var a_slice = Array.prototype.slice;
  13673. var expandProperties = Ember.expandProperties;
  13674. if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
  13675. /**
  13676. The `property` extension of Javascript's Function prototype is available
  13677. when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is
  13678. `true`, which is the default.
  13679. Computed properties allow you to treat a function like a property:
  13680. ```javascript
  13681. MyApp.President = Ember.Object.extend({
  13682. firstName: '',
  13683. lastName: '',
  13684. fullName: function() {
  13685. return this.get('firstName') + ' ' + this.get('lastName');
  13686. // Call this flag to mark the function as a property
  13687. }.property()
  13688. });
  13689. var president = MyApp.President.create({
  13690. firstName: "Barack",
  13691. lastName: "Obama"
  13692. });
  13693. president.get('fullName'); // "Barack Obama"
  13694. ```
  13695. Treating a function like a property is useful because they can work with
  13696. bindings, just like any other property.
  13697. Many computed properties have dependencies on other properties. For
  13698. example, in the above example, the `fullName` property depends on
  13699. `firstName` and `lastName` to determine its value. You can tell Ember
  13700. about these dependencies like this:
  13701. ```javascript
  13702. MyApp.President = Ember.Object.extend({
  13703. firstName: '',
  13704. lastName: '',
  13705. fullName: function() {
  13706. return this.get('firstName') + ' ' + this.get('lastName');
  13707. // Tell Ember.js that this computed property depends on firstName
  13708. // and lastName
  13709. }.property('firstName', 'lastName')
  13710. });
  13711. ```
  13712. Make sure you list these dependencies so Ember knows when to update
  13713. bindings that connect to a computed property. Changing a dependency
  13714. will not immediately trigger an update of the computed property, but
  13715. will instead clear the cache so that it is updated when the next `get`
  13716. is called on the property.
  13717. See [Ember.ComputedProperty](/api/classes/Ember.ComputedProperty.html), [Ember.computed](/api/#method_computed).
  13718. @method property
  13719. @for Function
  13720. */
  13721. Function.prototype.property = function() {
  13722. var ret = Ember.computed(this);
  13723. // ComputedProperty.prototype.property expands properties; no need for us to
  13724. // do so here.
  13725. return ret.property.apply(ret, arguments);
  13726. };
  13727. /**
  13728. The `observes` extension of Javascript's Function prototype is available
  13729. when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is
  13730. true, which is the default.
  13731. You can observe property changes simply by adding the `observes`
  13732. call to the end of your method declarations in classes that you write.
  13733. For example:
  13734. ```javascript
  13735. Ember.Object.extend({
  13736. valueObserver: function() {
  13737. // Executes whenever the "value" property changes
  13738. }.observes('value')
  13739. });
  13740. ```
  13741. In the future this method may become asynchronous. If you want to ensure
  13742. synchronous behavior, use `observesImmediately`.
  13743. See `Ember.observer`.
  13744. @method observes
  13745. @for Function
  13746. */
  13747. Function.prototype.observes = function() {
  13748. var addWatchedProperty = function (obs) { watched.push(obs); };
  13749. var watched = [];
  13750. for (var i=0; i<arguments.length; ++i) {
  13751. expandProperties(arguments[i], addWatchedProperty);
  13752. }
  13753. this.__ember_observes__ = watched;
  13754. return this;
  13755. };
  13756. /**
  13757. The `observesImmediately` extension of Javascript's Function prototype is
  13758. available when `Ember.EXTEND_PROTOTYPES` or
  13759. `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default.
  13760. You can observe property changes simply by adding the `observesImmediately`
  13761. call to the end of your method declarations in classes that you write.
  13762. For example:
  13763. ```javascript
  13764. Ember.Object.extend({
  13765. valueObserver: function() {
  13766. // Executes immediately after the "value" property changes
  13767. }.observesImmediately('value')
  13768. });
  13769. ```
  13770. In the future, `observes` may become asynchronous. In this event,
  13771. `observesImmediately` will maintain the synchronous behavior.
  13772. See `Ember.immediateObserver`.
  13773. @method observesImmediately
  13774. @for Function
  13775. */
  13776. Function.prototype.observesImmediately = function() {
  13777. for (var i=0, l=arguments.length; i<l; i++) {
  13778. var arg = arguments[i];
  13779. Ember.assert("Immediate observers must observe internal properties only, not properties on other objects.", arg.indexOf('.') === -1);
  13780. }
  13781. // observes handles property expansion
  13782. return this.observes.apply(this, arguments);
  13783. };
  13784. /**
  13785. The `observesBefore` extension of Javascript's Function prototype is
  13786. available when `Ember.EXTEND_PROTOTYPES` or
  13787. `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default.
  13788. You can get notified when a property change is about to happen by
  13789. by adding the `observesBefore` call to the end of your method
  13790. declarations in classes that you write. For example:
  13791. ```javascript
  13792. Ember.Object.extend({
  13793. valueObserver: function() {
  13794. // Executes whenever the "value" property is about to change
  13795. }.observesBefore('value')
  13796. });
  13797. ```
  13798. See `Ember.beforeObserver`.
  13799. @method observesBefore
  13800. @for Function
  13801. */
  13802. Function.prototype.observesBefore = function() {
  13803. var addWatchedProperty = function (obs) { watched.push(obs); };
  13804. var watched = [];
  13805. for (var i=0; i<arguments.length; ++i) {
  13806. expandProperties(arguments[i], addWatchedProperty);
  13807. }
  13808. this.__ember_observesBefore__ = watched;
  13809. return this;
  13810. };
  13811. /**
  13812. The `on` extension of Javascript's Function prototype is available
  13813. when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is
  13814. true, which is the default.
  13815. You can listen for events simply by adding the `on` call to the end of
  13816. your method declarations in classes or mixins that you write. For example:
  13817. ```javascript
  13818. Ember.Mixin.create({
  13819. doSomethingWithElement: function() {
  13820. // Executes whenever the "didInsertElement" event fires
  13821. }.on('didInsertElement')
  13822. });
  13823. ```
  13824. See `Ember.on`.
  13825. @method on
  13826. @for Function
  13827. */
  13828. Function.prototype.on = function() {
  13829. var events = a_slice.call(arguments);
  13830. this.__ember_listens__ = events;
  13831. return this;
  13832. };
  13833. }
  13834. })();
  13835. (function() {
  13836. })();
  13837. (function() {
  13838. /**
  13839. @module ember
  13840. @submodule ember-runtime
  13841. */
  13842. /**
  13843. Implements some standard methods for comparing objects. Add this mixin to
  13844. any class you create that can compare its instances.
  13845. You should implement the `compare()` method.
  13846. @class Comparable
  13847. @namespace Ember
  13848. @since Ember 0.9
  13849. */
  13850. Ember.Comparable = Ember.Mixin.create({
  13851. /**
  13852. Override to return the result of the comparison of the two parameters. The
  13853. compare method should return:
  13854. - `-1` if `a < b`
  13855. - `0` if `a == b`
  13856. - `1` if `a > b`
  13857. Default implementation raises an exception.
  13858. @method compare
  13859. @param a {Object} the first object to compare
  13860. @param b {Object} the second object to compare
  13861. @return {Integer} the result of the comparison
  13862. */
  13863. compare: Ember.required(Function)
  13864. });
  13865. })();
  13866. (function() {
  13867. /**
  13868. @module ember
  13869. @submodule ember-runtime
  13870. */
  13871. var get = Ember.get, set = Ember.set;
  13872. /**
  13873. Implements some standard methods for copying an object. Add this mixin to
  13874. any object you create that can create a copy of itself. This mixin is
  13875. added automatically to the built-in array.
  13876. You should generally implement the `copy()` method to return a copy of the
  13877. receiver.
  13878. Note that `frozenCopy()` will only work if you also implement
  13879. `Ember.Freezable`.
  13880. @class Copyable
  13881. @namespace Ember
  13882. @since Ember 0.9
  13883. */
  13884. Ember.Copyable = Ember.Mixin.create({
  13885. /**
  13886. Override to return a copy of the receiver. Default implementation raises
  13887. an exception.
  13888. @method copy
  13889. @param {Boolean} deep if `true`, a deep copy of the object should be made
  13890. @return {Object} copy of receiver
  13891. */
  13892. copy: Ember.required(Function),
  13893. /**
  13894. If the object implements `Ember.Freezable`, then this will return a new
  13895. copy if the object is not frozen and the receiver if the object is frozen.
  13896. Raises an exception if you try to call this method on a object that does
  13897. not support freezing.
  13898. You should use this method whenever you want a copy of a freezable object
  13899. since a freezable object can simply return itself without actually
  13900. consuming more memory.
  13901. @method frozenCopy
  13902. @return {Object} copy of receiver or receiver
  13903. */
  13904. frozenCopy: function() {
  13905. if (Ember.Freezable && Ember.Freezable.detect(this)) {
  13906. return get(this, 'isFrozen') ? this : this.copy().freeze();
  13907. } else {
  13908. throw new Ember.Error(Ember.String.fmt("%@ does not support freezing", [this]));
  13909. }
  13910. }
  13911. });
  13912. })();
  13913. (function() {
  13914. /**
  13915. @module ember
  13916. @submodule ember-runtime
  13917. */
  13918. var get = Ember.get, set = Ember.set;
  13919. /**
  13920. The `Ember.Freezable` mixin implements some basic methods for marking an
  13921. object as frozen. Once an object is frozen it should be read only. No changes
  13922. may be made the internal state of the object.
  13923. ## Enforcement
  13924. To fully support freezing in your subclass, you must include this mixin and
  13925. override any method that might alter any property on the object to instead
  13926. raise an exception. You can check the state of an object by checking the
  13927. `isFrozen` property.
  13928. Although future versions of JavaScript may support language-level freezing
  13929. object objects, that is not the case today. Even if an object is freezable,
  13930. it is still technically possible to modify the object, even though it could
  13931. break other parts of your application that do not expect a frozen object to
  13932. change. It is, therefore, very important that you always respect the
  13933. `isFrozen` property on all freezable objects.
  13934. ## Example Usage
  13935. The example below shows a simple object that implement the `Ember.Freezable`
  13936. protocol.
  13937. ```javascript
  13938. Contact = Ember.Object.extend(Ember.Freezable, {
  13939. firstName: null,
  13940. lastName: null,
  13941. // swaps the names
  13942. swapNames: function() {
  13943. if (this.get('isFrozen')) throw Ember.FROZEN_ERROR;
  13944. var tmp = this.get('firstName');
  13945. this.set('firstName', this.get('lastName'));
  13946. this.set('lastName', tmp);
  13947. return this;
  13948. }
  13949. });
  13950. c = Contact.create({ firstName: "John", lastName: "Doe" });
  13951. c.swapNames(); // returns c
  13952. c.freeze();
  13953. c.swapNames(); // EXCEPTION
  13954. ```
  13955. ## Copying
  13956. Usually the `Ember.Freezable` protocol is implemented in cooperation with the
  13957. `Ember.Copyable` protocol, which defines a `frozenCopy()` method that will
  13958. return a frozen object, if the object implements this method as well.
  13959. @class Freezable
  13960. @namespace Ember
  13961. @since Ember 0.9
  13962. */
  13963. Ember.Freezable = Ember.Mixin.create({
  13964. /**
  13965. Set to `true` when the object is frozen. Use this property to detect
  13966. whether your object is frozen or not.
  13967. @property isFrozen
  13968. @type Boolean
  13969. */
  13970. isFrozen: false,
  13971. /**
  13972. Freezes the object. Once this method has been called the object should
  13973. no longer allow any properties to be edited.
  13974. @method freeze
  13975. @return {Object} receiver
  13976. */
  13977. freeze: function() {
  13978. if (get(this, 'isFrozen')) return this;
  13979. set(this, 'isFrozen', true);
  13980. return this;
  13981. }
  13982. });
  13983. Ember.FROZEN_ERROR = "Frozen object cannot be modified.";
  13984. })();
  13985. (function() {
  13986. /**
  13987. @module ember
  13988. @submodule ember-runtime
  13989. */
  13990. var forEach = Ember.EnumerableUtils.forEach;
  13991. /**
  13992. This mixin defines the API for modifying generic enumerables. These methods
  13993. can be applied to an object regardless of whether it is ordered or
  13994. unordered.
  13995. Note that an Enumerable can change even if it does not implement this mixin.
  13996. For example, a MappedEnumerable cannot be directly modified but if its
  13997. underlying enumerable changes, it will change also.
  13998. ## Adding Objects
  13999. To add an object to an enumerable, use the `addObject()` method. This
  14000. method will only add the object to the enumerable if the object is not
  14001. already present and is of a type supported by the enumerable.
  14002. ```javascript
  14003. set.addObject(contact);
  14004. ```
  14005. ## Removing Objects
  14006. To remove an object from an enumerable, use the `removeObject()` method. This
  14007. will only remove the object if it is present in the enumerable, otherwise
  14008. this method has no effect.
  14009. ```javascript
  14010. set.removeObject(contact);
  14011. ```
  14012. ## Implementing In Your Own Code
  14013. If you are implementing an object and want to support this API, just include
  14014. this mixin in your class and implement the required methods. In your unit
  14015. tests, be sure to apply the Ember.MutableEnumerableTests to your object.
  14016. @class MutableEnumerable
  14017. @namespace Ember
  14018. @uses Ember.Enumerable
  14019. */
  14020. Ember.MutableEnumerable = Ember.Mixin.create(Ember.Enumerable, {
  14021. /**
  14022. __Required.__ You must implement this method to apply this mixin.
  14023. Attempts to add the passed object to the receiver if the object is not
  14024. already present in the collection. If the object is present, this method
  14025. has no effect.
  14026. If the passed object is of a type not supported by the receiver,
  14027. then this method should raise an exception.
  14028. @method addObject
  14029. @param {Object} object The object to add to the enumerable.
  14030. @return {Object} the passed object
  14031. */
  14032. addObject: Ember.required(Function),
  14033. /**
  14034. Adds each object in the passed enumerable to the receiver.
  14035. @method addObjects
  14036. @param {Ember.Enumerable} objects the objects to add.
  14037. @return {Object} receiver
  14038. */
  14039. addObjects: function(objects) {
  14040. Ember.beginPropertyChanges(this);
  14041. forEach(objects, function(obj) { this.addObject(obj); }, this);
  14042. Ember.endPropertyChanges(this);
  14043. return this;
  14044. },
  14045. /**
  14046. __Required.__ You must implement this method to apply this mixin.
  14047. Attempts to remove the passed object from the receiver collection if the
  14048. object is present in the collection. If the object is not present,
  14049. this method has no effect.
  14050. If the passed object is of a type not supported by the receiver,
  14051. then this method should raise an exception.
  14052. @method removeObject
  14053. @param {Object} object The object to remove from the enumerable.
  14054. @return {Object} the passed object
  14055. */
  14056. removeObject: Ember.required(Function),
  14057. /**
  14058. Removes each object in the passed enumerable from the receiver.
  14059. @method removeObjects
  14060. @param {Ember.Enumerable} objects the objects to remove
  14061. @return {Object} receiver
  14062. */
  14063. removeObjects: function(objects) {
  14064. Ember.beginPropertyChanges(this);
  14065. forEach(objects, function(obj) { this.removeObject(obj); }, this);
  14066. Ember.endPropertyChanges(this);
  14067. return this;
  14068. }
  14069. });
  14070. })();
  14071. (function() {
  14072. /**
  14073. @module ember
  14074. @submodule ember-runtime
  14075. */
  14076. // ..........................................................
  14077. // CONSTANTS
  14078. //
  14079. var OUT_OF_RANGE_EXCEPTION = "Index out of range" ;
  14080. var EMPTY = [];
  14081. // ..........................................................
  14082. // HELPERS
  14083. //
  14084. var get = Ember.get, set = Ember.set;
  14085. /**
  14086. This mixin defines the API for modifying array-like objects. These methods
  14087. can be applied only to a collection that keeps its items in an ordered set.
  14088. Note that an Array can change even if it does not implement this mixin.
  14089. For example, one might implement a SparseArray that cannot be directly
  14090. modified, but if its underlying enumerable changes, it will change also.
  14091. @class MutableArray
  14092. @namespace Ember
  14093. @uses Ember.Array
  14094. @uses Ember.MutableEnumerable
  14095. */
  14096. Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable, {
  14097. /**
  14098. __Required.__ You must implement this method to apply this mixin.
  14099. This is one of the primitives you must implement to support `Ember.Array`.
  14100. You should replace amt objects started at idx with the objects in the
  14101. passed array. You should also call `this.enumerableContentDidChange()`
  14102. @method replace
  14103. @param {Number} idx Starting index in the array to replace. If
  14104. idx >= length, then append to the end of the array.
  14105. @param {Number} amt Number of elements that should be removed from
  14106. the array, starting at *idx*.
  14107. @param {Array} objects An array of zero or more objects that should be
  14108. inserted into the array at *idx*
  14109. */
  14110. replace: Ember.required(),
  14111. /**
  14112. Remove all elements from self. This is useful if you
  14113. want to reuse an existing array without having to recreate it.
  14114. ```javascript
  14115. var colors = ["red", "green", "blue"];
  14116. color.length(); // 3
  14117. colors.clear(); // []
  14118. colors.length(); // 0
  14119. ```
  14120. @method clear
  14121. @return {Ember.Array} An empty Array.
  14122. */
  14123. clear: function () {
  14124. var len = get(this, 'length');
  14125. if (len === 0) return this;
  14126. this.replace(0, len, EMPTY);
  14127. return this;
  14128. },
  14129. /**
  14130. This will use the primitive `replace()` method to insert an object at the
  14131. specified index.
  14132. ```javascript
  14133. var colors = ["red", "green", "blue"];
  14134. colors.insertAt(2, "yellow"); // ["red", "green", "yellow", "blue"]
  14135. colors.insertAt(5, "orange"); // Error: Index out of range
  14136. ```
  14137. @method insertAt
  14138. @param {Number} idx index of insert the object at.
  14139. @param {Object} object object to insert
  14140. @return this
  14141. */
  14142. insertAt: function(idx, object) {
  14143. if (idx > get(this, 'length')) throw new Ember.Error(OUT_OF_RANGE_EXCEPTION) ;
  14144. this.replace(idx, 0, [object]) ;
  14145. return this ;
  14146. },
  14147. /**
  14148. Remove an object at the specified index using the `replace()` primitive
  14149. method. You can pass either a single index, or a start and a length.
  14150. If you pass a start and length that is beyond the
  14151. length this method will throw an `OUT_OF_RANGE_EXCEPTION`.
  14152. ```javascript
  14153. var colors = ["red", "green", "blue", "yellow", "orange"];
  14154. colors.removeAt(0); // ["green", "blue", "yellow", "orange"]
  14155. colors.removeAt(2, 2); // ["green", "blue"]
  14156. colors.removeAt(4, 2); // Error: Index out of range
  14157. ```
  14158. @method removeAt
  14159. @param {Number} start index, start of range
  14160. @param {Number} len length of passing range
  14161. @return {Object} receiver
  14162. */
  14163. removeAt: function(start, len) {
  14164. if ('number' === typeof start) {
  14165. if ((start < 0) || (start >= get(this, 'length'))) {
  14166. throw new Ember.Error(OUT_OF_RANGE_EXCEPTION);
  14167. }
  14168. // fast case
  14169. if (len === undefined) len = 1;
  14170. this.replace(start, len, EMPTY);
  14171. }
  14172. return this ;
  14173. },
  14174. /**
  14175. Push the object onto the end of the array. Works just like `push()` but it
  14176. is KVO-compliant.
  14177. ```javascript
  14178. var colors = ["red", "green"];
  14179. colors.pushObject("black"); // ["red", "green", "black"]
  14180. colors.pushObject(["yellow"]); // ["red", "green", ["yellow"]]
  14181. ```
  14182. @method pushObject
  14183. @param {*} obj object to push
  14184. @return The same obj passed as param
  14185. */
  14186. pushObject: function(obj) {
  14187. this.insertAt(get(this, 'length'), obj) ;
  14188. return obj;
  14189. },
  14190. /**
  14191. Add the objects in the passed numerable to the end of the array. Defers
  14192. notifying observers of the change until all objects are added.
  14193. ```javascript
  14194. var colors = ["red"];
  14195. colors.pushObjects(["yellow", "orange"]); // ["red", "yellow", "orange"]
  14196. ```
  14197. @method pushObjects
  14198. @param {Ember.Enumerable} objects the objects to add
  14199. @return {Ember.Array} receiver
  14200. */
  14201. pushObjects: function(objects) {
  14202. if (!(Ember.Enumerable.detect(objects) || Ember.isArray(objects))) {
  14203. throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects");
  14204. }
  14205. this.replace(get(this, 'length'), 0, objects);
  14206. return this;
  14207. },
  14208. /**
  14209. Pop object from array or nil if none are left. Works just like `pop()` but
  14210. it is KVO-compliant.
  14211. ```javascript
  14212. var colors = ["red", "green", "blue"];
  14213. colors.popObject(); // "blue"
  14214. console.log(colors); // ["red", "green"]
  14215. ```
  14216. @method popObject
  14217. @return object
  14218. */
  14219. popObject: function() {
  14220. var len = get(this, 'length') ;
  14221. if (len === 0) return null ;
  14222. var ret = this.objectAt(len-1) ;
  14223. this.removeAt(len-1, 1) ;
  14224. return ret ;
  14225. },
  14226. /**
  14227. Shift an object from start of array or nil if none are left. Works just
  14228. like `shift()` but it is KVO-compliant.
  14229. ```javascript
  14230. var colors = ["red", "green", "blue"];
  14231. colors.shiftObject(); // "red"
  14232. console.log(colors); // ["green", "blue"]
  14233. ```
  14234. @method shiftObject
  14235. @return object
  14236. */
  14237. shiftObject: function() {
  14238. if (get(this, 'length') === 0) return null ;
  14239. var ret = this.objectAt(0) ;
  14240. this.removeAt(0) ;
  14241. return ret ;
  14242. },
  14243. /**
  14244. Unshift an object to start of array. Works just like `unshift()` but it is
  14245. KVO-compliant.
  14246. ```javascript
  14247. var colors = ["red"];
  14248. colors.unshiftObject("yellow"); // ["yellow", "red"]
  14249. colors.unshiftObject(["black"]); // [["black"], "yellow", "red"]
  14250. ```
  14251. @method unshiftObject
  14252. @param {*} obj object to unshift
  14253. @return The same obj passed as param
  14254. */
  14255. unshiftObject: function(obj) {
  14256. this.insertAt(0, obj) ;
  14257. return obj ;
  14258. },
  14259. /**
  14260. Adds the named objects to the beginning of the array. Defers notifying
  14261. observers until all objects have been added.
  14262. ```javascript
  14263. var colors = ["red"];
  14264. colors.unshiftObjects(["black", "white"]); // ["black", "white", "red"]
  14265. colors.unshiftObjects("yellow"); // Type Error: 'undefined' is not a function
  14266. ```
  14267. @method unshiftObjects
  14268. @param {Ember.Enumerable} objects the objects to add
  14269. @return {Ember.Array} receiver
  14270. */
  14271. unshiftObjects: function(objects) {
  14272. this.replace(0, 0, objects);
  14273. return this;
  14274. },
  14275. /**
  14276. Reverse objects in the array. Works just like `reverse()` but it is
  14277. KVO-compliant.
  14278. @method reverseObjects
  14279. @return {Ember.Array} receiver
  14280. */
  14281. reverseObjects: function() {
  14282. var len = get(this, 'length');
  14283. if (len === 0) return this;
  14284. var objects = this.toArray().reverse();
  14285. this.replace(0, len, objects);
  14286. return this;
  14287. },
  14288. /**
  14289. Replace all the the receiver's content with content of the argument.
  14290. If argument is an empty array receiver will be cleared.
  14291. ```javascript
  14292. var colors = ["red", "green", "blue"];
  14293. colors.setObjects(["black", "white"]); // ["black", "white"]
  14294. colors.setObjects([]); // []
  14295. ```
  14296. @method setObjects
  14297. @param {Ember.Array} objects array whose content will be used for replacing
  14298. the content of the receiver
  14299. @return {Ember.Array} receiver with the new content
  14300. */
  14301. setObjects: function(objects) {
  14302. if (objects.length === 0) return this.clear();
  14303. var len = get(this, 'length');
  14304. this.replace(0, len, objects);
  14305. return this;
  14306. },
  14307. // ..........................................................
  14308. // IMPLEMENT Ember.MutableEnumerable
  14309. //
  14310. removeObject: function(obj) {
  14311. var loc = get(this, 'length') || 0;
  14312. while(--loc >= 0) {
  14313. var curObject = this.objectAt(loc) ;
  14314. if (curObject === obj) this.removeAt(loc) ;
  14315. }
  14316. return this ;
  14317. },
  14318. addObject: function(obj) {
  14319. if (!this.contains(obj)) this.pushObject(obj);
  14320. return this ;
  14321. }
  14322. });
  14323. })();
  14324. (function() {
  14325. /**
  14326. @module ember
  14327. @submodule ember-runtime
  14328. */
  14329. var get = Ember.get, set = Ember.set;
  14330. /**
  14331. `Ember.TargetActionSupport` is a mixin that can be included in a class
  14332. to add a `triggerAction` method with semantics similar to the Handlebars
  14333. `{{action}}` helper. In normal Ember usage, the `{{action}}` helper is
  14334. usually the best choice. This mixin is most often useful when you are
  14335. doing more complex event handling in View objects.
  14336. See also `Ember.ViewTargetActionSupport`, which has
  14337. view-aware defaults for target and actionContext.
  14338. @class TargetActionSupport
  14339. @namespace Ember
  14340. @extends Ember.Mixin
  14341. */
  14342. Ember.TargetActionSupport = Ember.Mixin.create({
  14343. target: null,
  14344. action: null,
  14345. actionContext: null,
  14346. targetObject: Ember.computed(function() {
  14347. var target = get(this, 'target');
  14348. if (Ember.typeOf(target) === "string") {
  14349. var value = get(this, target);
  14350. if (value === undefined) { value = get(Ember.lookup, target); }
  14351. return value;
  14352. } else {
  14353. return target;
  14354. }
  14355. }).property('target'),
  14356. actionContextObject: Ember.computed(function() {
  14357. var actionContext = get(this, 'actionContext');
  14358. if (Ember.typeOf(actionContext) === "string") {
  14359. var value = get(this, actionContext);
  14360. if (value === undefined) { value = get(Ember.lookup, actionContext); }
  14361. return value;
  14362. } else {
  14363. return actionContext;
  14364. }
  14365. }).property('actionContext'),
  14366. /**
  14367. Send an `action` with an `actionContext` to a `target`. The action, actionContext
  14368. and target will be retrieved from properties of the object. For example:
  14369. ```javascript
  14370. App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, {
  14371. target: Ember.computed.alias('controller'),
  14372. action: 'save',
  14373. actionContext: Ember.computed.alias('context'),
  14374. click: function() {
  14375. this.triggerAction(); // Sends the `save` action, along with the current context
  14376. // to the current controller
  14377. }
  14378. });
  14379. ```
  14380. The `target`, `action`, and `actionContext` can be provided as properties of
  14381. an optional object argument to `triggerAction` as well.
  14382. ```javascript
  14383. App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, {
  14384. click: function() {
  14385. this.triggerAction({
  14386. action: 'save',
  14387. target: this.get('controller'),
  14388. actionContext: this.get('context'),
  14389. }); // Sends the `save` action, along with the current context
  14390. // to the current controller
  14391. }
  14392. });
  14393. ```
  14394. The `actionContext` defaults to the object you mixing `TargetActionSupport` into.
  14395. But `target` and `action` must be specified either as properties or with the argument
  14396. to `triggerAction`, or a combination:
  14397. ```javascript
  14398. App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, {
  14399. target: Ember.computed.alias('controller'),
  14400. click: function() {
  14401. this.triggerAction({
  14402. action: 'save'
  14403. }); // Sends the `save` action, along with a reference to `this`,
  14404. // to the current controller
  14405. }
  14406. });
  14407. ```
  14408. @method triggerAction
  14409. @param opts {Hash} (optional, with the optional keys action, target and/or actionContext)
  14410. @return {Boolean} true if the action was sent successfully and did not return false
  14411. */
  14412. triggerAction: function(opts) {
  14413. opts = opts || {};
  14414. var action = opts.action || get(this, 'action'),
  14415. target = opts.target || get(this, 'targetObject'),
  14416. actionContext = opts.actionContext;
  14417. function args(options, actionName) {
  14418. var ret = [];
  14419. if (actionName) { ret.push(actionName); }
  14420. return ret.concat(options);
  14421. }
  14422. if (typeof actionContext === 'undefined') {
  14423. actionContext = get(this, 'actionContextObject') || this;
  14424. }
  14425. if (target && action) {
  14426. var ret;
  14427. if (target.send) {
  14428. ret = target.send.apply(target, args(actionContext, action));
  14429. } else {
  14430. Ember.assert("The action '" + action + "' did not exist on " + target, typeof target[action] === 'function');
  14431. ret = target[action].apply(target, args(actionContext));
  14432. }
  14433. if (ret !== false) ret = true;
  14434. return ret;
  14435. } else {
  14436. return false;
  14437. }
  14438. }
  14439. });
  14440. })();
  14441. (function() {
  14442. /**
  14443. @module ember
  14444. @submodule ember-runtime
  14445. */
  14446. /**
  14447. This mixin allows for Ember objects to subscribe to and emit events.
  14448. ```javascript
  14449. App.Person = Ember.Object.extend(Ember.Evented, {
  14450. greet: function() {
  14451. // ...
  14452. this.trigger('greet');
  14453. }
  14454. });
  14455. var person = App.Person.create();
  14456. person.on('greet', function() {
  14457. console.log('Our person has greeted');
  14458. });
  14459. person.greet();
  14460. // outputs: 'Our person has greeted'
  14461. ```
  14462. You can also chain multiple event subscriptions:
  14463. ```javascript
  14464. person.on('greet', function() {
  14465. console.log('Our person has greeted');
  14466. }).one('greet', function() {
  14467. console.log('Offer one-time special');
  14468. }).off('event', this, forgetThis);
  14469. ```
  14470. @class Evented
  14471. @namespace Ember
  14472. */
  14473. Ember.Evented = Ember.Mixin.create({
  14474. /**
  14475. Subscribes to a named event with given function.
  14476. ```javascript
  14477. person.on('didLoad', function() {
  14478. // fired once the person has loaded
  14479. });
  14480. ```
  14481. An optional target can be passed in as the 2nd argument that will
  14482. be set as the "this" for the callback. This is a good way to give your
  14483. function access to the object triggering the event. When the target
  14484. parameter is used the callback becomes the third argument.
  14485. @method on
  14486. @param {String} name The name of the event
  14487. @param {Object} [target] The "this" binding for the callback
  14488. @param {Function} method The callback to execute
  14489. @return this
  14490. */
  14491. on: function(name, target, method) {
  14492. Ember.addListener(this, name, target, method);
  14493. return this;
  14494. },
  14495. /**
  14496. Subscribes a function to a named event and then cancels the subscription
  14497. after the first time the event is triggered. It is good to use ``one`` when
  14498. you only care about the first time an event has taken place.
  14499. This function takes an optional 2nd argument that will become the "this"
  14500. value for the callback. If this argument is passed then the 3rd argument
  14501. becomes the function.
  14502. @method one
  14503. @param {String} name The name of the event
  14504. @param {Object} [target] The "this" binding for the callback
  14505. @param {Function} method The callback to execute
  14506. @return this
  14507. */
  14508. one: function(name, target, method) {
  14509. if (!method) {
  14510. method = target;
  14511. target = null;
  14512. }
  14513. Ember.addListener(this, name, target, method, true);
  14514. return this;
  14515. },
  14516. /**
  14517. Triggers a named event for the object. Any additional arguments
  14518. will be passed as parameters to the functions that are subscribed to the
  14519. event.
  14520. ```javascript
  14521. person.on('didEat', function(food) {
  14522. console.log('person ate some ' + food);
  14523. });
  14524. person.trigger('didEat', 'broccoli');
  14525. // outputs: person ate some broccoli
  14526. ```
  14527. @method trigger
  14528. @param {String} name The name of the event
  14529. @param {Object...} args Optional arguments to pass on
  14530. */
  14531. trigger: function(name) {
  14532. var args = [], i, l;
  14533. for (i = 1, l = arguments.length; i < l; i++) {
  14534. args.push(arguments[i]);
  14535. }
  14536. Ember.sendEvent(this, name, args);
  14537. },
  14538. /**
  14539. Cancels subscription for given name, target, and method.
  14540. @method off
  14541. @param {String} name The name of the event
  14542. @param {Object} target The target of the subscription
  14543. @param {Function} method The function of the subscription
  14544. @return this
  14545. */
  14546. off: function(name, target, method) {
  14547. Ember.removeListener(this, name, target, method);
  14548. return this;
  14549. },
  14550. /**
  14551. Checks to see if object has any subscriptions for named event.
  14552. @method has
  14553. @param {String} name The name of the event
  14554. @return {Boolean} does the object have a subscription for event
  14555. */
  14556. has: function(name) {
  14557. return Ember.hasListeners(this, name);
  14558. }
  14559. });
  14560. })();
  14561. (function() {
  14562. var RSVP = requireModule("rsvp");
  14563. RSVP.configure('async', function(callback, promise) {
  14564. Ember.run.schedule('actions', promise, callback, promise);
  14565. });
  14566. RSVP.Promise.prototype.fail = function(callback, label){
  14567. Ember.deprecate('RSVP.Promise.fail has been renamed as RSVP.Promise.catch');
  14568. return this['catch'](callback, label);
  14569. };
  14570. /**
  14571. @module ember
  14572. @submodule ember-runtime
  14573. */
  14574. var get = Ember.get;
  14575. /**
  14576. @class Deferred
  14577. @namespace Ember
  14578. */
  14579. Ember.DeferredMixin = Ember.Mixin.create({
  14580. /**
  14581. Add handlers to be called when the Deferred object is resolved or rejected.
  14582. @method then
  14583. @param {Function} resolve a callback function to be called when done
  14584. @param {Function} reject a callback function to be called when failed
  14585. */
  14586. then: function(resolve, reject, label) {
  14587. var deferred, promise, entity;
  14588. entity = this;
  14589. deferred = get(this, '_deferred');
  14590. promise = deferred.promise;
  14591. function fulfillmentHandler(fulfillment) {
  14592. if (fulfillment === promise) {
  14593. return resolve(entity);
  14594. } else {
  14595. return resolve(fulfillment);
  14596. }
  14597. }
  14598. return promise.then(resolve && fulfillmentHandler, reject, label);
  14599. },
  14600. /**
  14601. Resolve a Deferred object and call any `doneCallbacks` with the given args.
  14602. @method resolve
  14603. */
  14604. resolve: function(value) {
  14605. var deferred, promise;
  14606. deferred = get(this, '_deferred');
  14607. promise = deferred.promise;
  14608. if (value === this) {
  14609. deferred.resolve(promise);
  14610. } else {
  14611. deferred.resolve(value);
  14612. }
  14613. },
  14614. /**
  14615. Reject a Deferred object and call any `failCallbacks` with the given args.
  14616. @method reject
  14617. */
  14618. reject: function(value) {
  14619. get(this, '_deferred').reject(value);
  14620. },
  14621. _deferred: Ember.computed(function() {
  14622. return RSVP.defer('Ember: DeferredMixin - ' + this);
  14623. })
  14624. });
  14625. })();
  14626. (function() {
  14627. /**
  14628. @module ember
  14629. @submodule ember-runtime
  14630. */
  14631. var get = Ember.get, typeOf = Ember.typeOf;
  14632. /**
  14633. The `Ember.ActionHandler` mixin implements support for moving an `actions`
  14634. property to an `_actions` property at extend time, and adding `_actions`
  14635. to the object's mergedProperties list.
  14636. `Ember.ActionHandler` is used internally by Ember in `Ember.View`,
  14637. `Ember.Controller`, and `Ember.Route`.
  14638. @class ActionHandler
  14639. @namespace Ember
  14640. */
  14641. Ember.ActionHandler = Ember.Mixin.create({
  14642. mergedProperties: ['_actions'],
  14643. /**
  14644. The collection of functions, keyed by name, available on this
  14645. `ActionHandler` as action targets.
  14646. These functions will be invoked when a matching `{{action}}` is triggered
  14647. from within a template and the application's current route is this route.
  14648. Actions can also be invoked from other parts of your application
  14649. via `ActionHandler#send`.
  14650. The `actions` hash will inherit action handlers from
  14651. the `actions` hash defined on extended parent classes
  14652. or mixins rather than just replace the entire hash, e.g.:
  14653. ```js
  14654. App.CanDisplayBanner = Ember.Mixin.create({
  14655. actions: {
  14656. displayBanner: function(msg) {
  14657. // ...
  14658. }
  14659. }
  14660. });
  14661. App.WelcomeRoute = Ember.Route.extend(App.CanDisplayBanner, {
  14662. actions: {
  14663. playMusic: function() {
  14664. // ...
  14665. }
  14666. }
  14667. });
  14668. // `WelcomeRoute`, when active, will be able to respond
  14669. // to both actions, since the actions hash is merged rather
  14670. // then replaced when extending mixins / parent classes.
  14671. this.send('displayBanner');
  14672. this.send('playMusic');
  14673. ```
  14674. Within a Controller, Route, View or Component's action handler,
  14675. the value of the `this` context is the Controller, Route, View or
  14676. Component object:
  14677. ```js
  14678. App.SongRoute = Ember.Route.extend({
  14679. actions: {
  14680. myAction: function() {
  14681. this.controllerFor("song");
  14682. this.transitionTo("other.route");
  14683. ...
  14684. }
  14685. }
  14686. });
  14687. ```
  14688. It is also possible to call `this._super()` from within an
  14689. action handler if it overrides a handler defined on a parent
  14690. class or mixin:
  14691. Take for example the following routes:
  14692. ```js
  14693. App.DebugRoute = Ember.Mixin.create({
  14694. actions: {
  14695. debugRouteInformation: function() {
  14696. console.debug("trololo");
  14697. }
  14698. }
  14699. });
  14700. App.AnnoyingDebugRoute = Ember.Route.extend(App.DebugRoute, {
  14701. actions: {
  14702. debugRouteInformation: function() {
  14703. // also call the debugRouteInformation of mixed in App.DebugRoute
  14704. this._super();
  14705. // show additional annoyance
  14706. window.alert(...);
  14707. }
  14708. }
  14709. });
  14710. ```
  14711. ## Bubbling
  14712. By default, an action will stop bubbling once a handler defined
  14713. on the `actions` hash handles it. To continue bubbling the action,
  14714. you must return `true` from the handler:
  14715. ```js
  14716. App.Router.map(function() {
  14717. this.resource("album", function() {
  14718. this.route("song");
  14719. });
  14720. });
  14721. App.AlbumRoute = Ember.Route.extend({
  14722. actions: {
  14723. startPlaying: function() {
  14724. }
  14725. }
  14726. });
  14727. App.AlbumSongRoute = Ember.Route.extend({
  14728. actions: {
  14729. startPlaying: function() {
  14730. // ...
  14731. if (actionShouldAlsoBeTriggeredOnParentRoute) {
  14732. return true;
  14733. }
  14734. }
  14735. }
  14736. });
  14737. ```
  14738. @property actions
  14739. @type Hash
  14740. @default null
  14741. */
  14742. /**
  14743. Moves `actions` to `_actions` at extend time. Note that this currently
  14744. modifies the mixin themselves, which is technically dubious but
  14745. is practically of little consequence. This may change in the future.
  14746. @private
  14747. @method willMergeMixin
  14748. */
  14749. willMergeMixin: function(props) {
  14750. var hashName;
  14751. if (!props._actions) {
  14752. Ember.assert("'actions' should not be a function", typeof(props.actions) !== 'function');
  14753. if (typeOf(props.actions) === 'object') {
  14754. hashName = 'actions';
  14755. } else if (typeOf(props.events) === 'object') {
  14756. Ember.deprecate('Action handlers contained in an `events` object are deprecated in favor of putting them in an `actions` object', false);
  14757. hashName = 'events';
  14758. }
  14759. if (hashName) {
  14760. props._actions = Ember.merge(props._actions || {}, props[hashName]);
  14761. }
  14762. delete props[hashName];
  14763. }
  14764. },
  14765. /**
  14766. Triggers a named action on the `ActionHandler`. Any parameters
  14767. supplied after the `actionName` string will be passed as arguments
  14768. to the action target function.
  14769. If the `ActionHandler` has its `target` property set, actions may
  14770. bubble to the `target`. Bubbling happens when an `actionName` can
  14771. not be found in the `ActionHandler`'s `actions` hash or if the
  14772. action target function returns `true`.
  14773. Example
  14774. ```js
  14775. App.WelcomeRoute = Ember.Route.extend({
  14776. actions: {
  14777. playTheme: function() {
  14778. this.send('playMusic', 'theme.mp3');
  14779. },
  14780. playMusic: function(track) {
  14781. // ...
  14782. }
  14783. }
  14784. });
  14785. ```
  14786. @method send
  14787. @param {String} actionName The action to trigger
  14788. @param {*} context a context to send with the action
  14789. */
  14790. send: function(actionName) {
  14791. var args = [].slice.call(arguments, 1), target;
  14792. if (this._actions && this._actions[actionName]) {
  14793. if (this._actions[actionName].apply(this, args) === true) {
  14794. // handler returned true, so this action will bubble
  14795. } else {
  14796. return;
  14797. }
  14798. } else if (this.deprecatedSend && this.deprecatedSendHandles && this.deprecatedSendHandles(actionName)) {
  14799. if (this.deprecatedSend.apply(this, [].slice.call(arguments)) === true) {
  14800. // handler return true, so this action will bubble
  14801. } else {
  14802. return;
  14803. }
  14804. }
  14805. if (target = get(this, 'target')) {
  14806. Ember.assert("The `target` for " + this + " (" + target + ") does not have a `send` method", typeof target.send === 'function');
  14807. target.send.apply(target, arguments);
  14808. }
  14809. }
  14810. });
  14811. })();
  14812. (function() {
  14813. var set = Ember.set, get = Ember.get,
  14814. not = Ember.computed.not,
  14815. or = Ember.computed.or;
  14816. /**
  14817. @module ember
  14818. @submodule ember-runtime
  14819. */
  14820. function tap(proxy, promise) {
  14821. return promise.then(function(value) {
  14822. set(proxy, 'isFulfilled', true);
  14823. set(proxy, 'content', value);
  14824. return value;
  14825. }, function(reason) {
  14826. set(proxy, 'isRejected', true);
  14827. set(proxy, 'reason', reason);
  14828. throw reason;
  14829. }, "Ember: PromiseProxy");
  14830. }
  14831. /**
  14832. A low level mixin making ObjectProxy, ObjectController or ArrayController's promise aware.
  14833. ```javascript
  14834. var ObjectPromiseController = Ember.ObjectController.extend(Ember.PromiseProxyMixin);
  14835. var controller = ObjectPromiseController.create({
  14836. promise: $.getJSON('/some/remote/data.json')
  14837. });
  14838. controller.then(function(json){
  14839. // the json
  14840. }, function(reason) {
  14841. // the reason why you have no json
  14842. });
  14843. ```
  14844. the controller has bindable attributes which
  14845. track the promises life cycle
  14846. ```javascript
  14847. controller.get('isPending') //=> true
  14848. controller.get('isSettled') //=> false
  14849. controller.get('isRejected') //=> false
  14850. controller.get('isFulfilled') //=> false
  14851. ```
  14852. When the the $.getJSON completes, and the promise is fulfilled
  14853. with json, the life cycle attributes will update accordingly.
  14854. ```javascript
  14855. controller.get('isPending') //=> false
  14856. controller.get('isSettled') //=> true
  14857. controller.get('isRejected') //=> false
  14858. controller.get('isFulfilled') //=> true
  14859. ```
  14860. As the controller is an ObjectController, and the json now its content,
  14861. all the json properties will be available directly from the controller.
  14862. ```javascript
  14863. // Assuming the following json:
  14864. {
  14865. firstName: 'Stefan',
  14866. lastName: 'Penner'
  14867. }
  14868. // both properties will accessible on the controller
  14869. controller.get('firstName') //=> 'Stefan'
  14870. controller.get('lastName') //=> 'Penner'
  14871. ```
  14872. If the controller is backing a template, the attributes are
  14873. bindable from within that template
  14874. ```handlebars
  14875. {{#if isPending}}
  14876. loading...
  14877. {{else}}
  14878. firstName: {{firstName}}
  14879. lastName: {{lastName}}
  14880. {{/if}}
  14881. ```
  14882. @class Ember.PromiseProxyMixin
  14883. */
  14884. Ember.PromiseProxyMixin = Ember.Mixin.create({
  14885. /**
  14886. If the proxied promise is rejected this will contain the reason
  14887. provided.
  14888. @property reason
  14889. @default null
  14890. */
  14891. reason: null,
  14892. /**
  14893. Once the proxied promise has settled this will become `false`.
  14894. @property isPending
  14895. @default true
  14896. */
  14897. isPending: not('isSettled').readOnly(),
  14898. /**
  14899. Once the proxied promise has settled this will become `true`.
  14900. @property isSettled
  14901. @default false
  14902. */
  14903. isSettled: or('isRejected', 'isFulfilled').readOnly(),
  14904. /**
  14905. Will become `true` if the proxied promise is rejected.
  14906. @property isRejected
  14907. @default false
  14908. */
  14909. isRejected: false,
  14910. /**
  14911. Will become `true` if the proxied promise is fulfilled.
  14912. @property isFullfilled
  14913. @default false
  14914. */
  14915. isFulfilled: false,
  14916. /**
  14917. The promise whose fulfillment value is being proxied by this object.
  14918. This property must be specified upon creation, and should not be
  14919. changed once created.
  14920. Example:
  14921. ```javascript
  14922. Ember.ObjectController.extend(Ember.PromiseProxyMixin).create({
  14923. promise: <thenable>
  14924. });
  14925. ```
  14926. @property promise
  14927. */
  14928. promise: Ember.computed(function(key, promise) {
  14929. if (arguments.length === 2) {
  14930. return tap(this, promise);
  14931. } else {
  14932. throw new Ember.Error("PromiseProxy's promise must be set");
  14933. }
  14934. }),
  14935. /**
  14936. An alias to the proxied promise's `then`.
  14937. See RSVP.Promise.then.
  14938. @method then
  14939. @param {Function} callback
  14940. @return {RSVP.Promise}
  14941. */
  14942. then: promiseAlias('then'),
  14943. /**
  14944. An alias to the proxied promise's `catch`.
  14945. See RSVP.Promise.catch.
  14946. @method catch
  14947. @param {Function} callback
  14948. @return {RSVP.Promise}
  14949. */
  14950. 'catch': promiseAlias('catch'),
  14951. /**
  14952. An alias to the proxied promise's `finally`.
  14953. See RSVP.Promise.finally.
  14954. @method finally
  14955. @param {Function} callback
  14956. @return {RSVP.Promise}
  14957. */
  14958. 'finally': promiseAlias('finally')
  14959. });
  14960. function promiseAlias(name) {
  14961. return function () {
  14962. var promise = get(this, 'promise');
  14963. return promise[name].apply(promise, arguments);
  14964. };
  14965. }
  14966. })();
  14967. (function() {
  14968. })();
  14969. (function() {
  14970. var get = Ember.get,
  14971. forEach = Ember.EnumerableUtils.forEach,
  14972. RETAIN = 'r',
  14973. INSERT = 'i',
  14974. DELETE = 'd';
  14975. /**
  14976. An `Ember.TrackedArray` tracks array operations. It's useful when you want to
  14977. lazily compute the indexes of items in an array after they've been shifted by
  14978. subsequent operations.
  14979. @class TrackedArray
  14980. @namespace Ember
  14981. @param {array} [items=[]] The array to be tracked. This is used just to get
  14982. the initial items for the starting state of retain:n.
  14983. */
  14984. Ember.TrackedArray = function (items) {
  14985. if (arguments.length < 1) { items = []; }
  14986. var length = get(items, 'length');
  14987. if (length) {
  14988. this._operations = [new ArrayOperation(RETAIN, length, items)];
  14989. } else {
  14990. this._operations = [];
  14991. }
  14992. };
  14993. Ember.TrackedArray.RETAIN = RETAIN;
  14994. Ember.TrackedArray.INSERT = INSERT;
  14995. Ember.TrackedArray.DELETE = DELETE;
  14996. Ember.TrackedArray.prototype = {
  14997. /**
  14998. Track that `newItems` were added to the tracked array at `index`.
  14999. @method addItems
  15000. @param index
  15001. @param newItems
  15002. */
  15003. addItems: function (index, newItems) {
  15004. var count = get(newItems, 'length');
  15005. if (count < 1) { return; }
  15006. var match = this._findArrayOperation(index),
  15007. arrayOperation = match.operation,
  15008. arrayOperationIndex = match.index,
  15009. arrayOperationRangeStart = match.rangeStart,
  15010. composeIndex,
  15011. splitIndex,
  15012. splitItems,
  15013. splitArrayOperation,
  15014. newArrayOperation;
  15015. newArrayOperation = new ArrayOperation(INSERT, count, newItems);
  15016. if (arrayOperation) {
  15017. if (!match.split) {
  15018. // insert left of arrayOperation
  15019. this._operations.splice(arrayOperationIndex, 0, newArrayOperation);
  15020. composeIndex = arrayOperationIndex;
  15021. } else {
  15022. this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation);
  15023. composeIndex = arrayOperationIndex + 1;
  15024. }
  15025. } else {
  15026. // insert at end
  15027. this._operations.push(newArrayOperation);
  15028. composeIndex = arrayOperationIndex;
  15029. }
  15030. this._composeInsert(composeIndex);
  15031. },
  15032. /**
  15033. Track that `count` items were removed at `index`.
  15034. @method removeItems
  15035. @param index
  15036. @param count
  15037. */
  15038. removeItems: function (index, count) {
  15039. if (count < 1) { return; }
  15040. var match = this._findArrayOperation(index),
  15041. arrayOperation = match.operation,
  15042. arrayOperationIndex = match.index,
  15043. arrayOperationRangeStart = match.rangeStart,
  15044. newArrayOperation,
  15045. composeIndex;
  15046. newArrayOperation = new ArrayOperation(DELETE, count);
  15047. if (!match.split) {
  15048. // insert left of arrayOperation
  15049. this._operations.splice(arrayOperationIndex, 0, newArrayOperation);
  15050. composeIndex = arrayOperationIndex;
  15051. } else {
  15052. this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation);
  15053. composeIndex = arrayOperationIndex + 1;
  15054. }
  15055. return this._composeDelete(composeIndex);
  15056. },
  15057. /**
  15058. Apply all operations, reducing them to retain:n, for `n`, the number of
  15059. items in the array.
  15060. `callback` will be called for each operation and will be passed the following arguments:
  15061. * {array} items The items for the given operation
  15062. * {number} offset The computed offset of the items, ie the index in the
  15063. array of the first item for this operation.
  15064. * {string} operation The type of the operation. One of
  15065. `Ember.TrackedArray.{RETAIN, DELETE, INSERT}`
  15066. @method apply
  15067. @param {function} callback
  15068. */
  15069. apply: function (callback) {
  15070. var items = [],
  15071. offset = 0;
  15072. forEach(this._operations, function (arrayOperation) {
  15073. callback(arrayOperation.items, offset, arrayOperation.type);
  15074. if (arrayOperation.type !== DELETE) {
  15075. offset += arrayOperation.count;
  15076. items = items.concat(arrayOperation.items);
  15077. }
  15078. });
  15079. this._operations = [new ArrayOperation(RETAIN, items.length, items)];
  15080. },
  15081. /**
  15082. Return an `ArrayOperationMatch` for the operation that contains the item at `index`.
  15083. @method _findArrayOperation
  15084. @param {number} index the index of the item whose operation information
  15085. should be returned.
  15086. @private
  15087. */
  15088. _findArrayOperation: function (index) {
  15089. var arrayOperationIndex,
  15090. len,
  15091. split = false,
  15092. arrayOperation,
  15093. arrayOperationRangeStart,
  15094. arrayOperationRangeEnd;
  15095. // OPTIMIZE: we could search these faster if we kept a balanced tree.
  15096. // find leftmost arrayOperation to the right of `index`
  15097. for (arrayOperationIndex = arrayOperationRangeStart = 0, len = this._operations.length; arrayOperationIndex < len; ++arrayOperationIndex) {
  15098. arrayOperation = this._operations[arrayOperationIndex];
  15099. if (arrayOperation.type === DELETE) { continue; }
  15100. arrayOperationRangeEnd = arrayOperationRangeStart + arrayOperation.count - 1;
  15101. if (index === arrayOperationRangeStart) {
  15102. break;
  15103. } else if (index > arrayOperationRangeStart && index <= arrayOperationRangeEnd) {
  15104. split = true;
  15105. break;
  15106. } else {
  15107. arrayOperationRangeStart = arrayOperationRangeEnd + 1;
  15108. }
  15109. }
  15110. return new ArrayOperationMatch(arrayOperation, arrayOperationIndex, split, arrayOperationRangeStart);
  15111. },
  15112. _split: function (arrayOperationIndex, splitIndex, newArrayOperation) {
  15113. var arrayOperation = this._operations[arrayOperationIndex],
  15114. splitItems = arrayOperation.items.slice(splitIndex),
  15115. splitArrayOperation = new ArrayOperation(arrayOperation.type, splitItems.length, splitItems);
  15116. // truncate LHS
  15117. arrayOperation.count = splitIndex;
  15118. arrayOperation.items = arrayOperation.items.slice(0, splitIndex);
  15119. this._operations.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation);
  15120. },
  15121. // see SubArray for a better implementation.
  15122. _composeInsert: function (index) {
  15123. var newArrayOperation = this._operations[index],
  15124. leftArrayOperation = this._operations[index-1], // may be undefined
  15125. rightArrayOperation = this._operations[index+1], // may be undefined
  15126. leftOp = leftArrayOperation && leftArrayOperation.type,
  15127. rightOp = rightArrayOperation && rightArrayOperation.type;
  15128. if (leftOp === INSERT) {
  15129. // merge left
  15130. leftArrayOperation.count += newArrayOperation.count;
  15131. leftArrayOperation.items = leftArrayOperation.items.concat(newArrayOperation.items);
  15132. if (rightOp === INSERT) {
  15133. // also merge right (we have split an insert with an insert)
  15134. leftArrayOperation.count += rightArrayOperation.count;
  15135. leftArrayOperation.items = leftArrayOperation.items.concat(rightArrayOperation.items);
  15136. this._operations.splice(index, 2);
  15137. } else {
  15138. // only merge left
  15139. this._operations.splice(index, 1);
  15140. }
  15141. } else if (rightOp === INSERT) {
  15142. // merge right
  15143. newArrayOperation.count += rightArrayOperation.count;
  15144. newArrayOperation.items = newArrayOperation.items.concat(rightArrayOperation.items);
  15145. this._operations.splice(index + 1, 1);
  15146. }
  15147. },
  15148. _composeDelete: function (index) {
  15149. var arrayOperation = this._operations[index],
  15150. deletesToGo = arrayOperation.count,
  15151. leftArrayOperation = this._operations[index-1], // may be undefined
  15152. leftOp = leftArrayOperation && leftArrayOperation.type,
  15153. nextArrayOperation,
  15154. nextOp,
  15155. nextCount,
  15156. removeNewAndNextOp = false,
  15157. removedItems = [];
  15158. if (leftOp === DELETE) {
  15159. arrayOperation = leftArrayOperation;
  15160. index -= 1;
  15161. }
  15162. for (var i = index + 1; deletesToGo > 0; ++i) {
  15163. nextArrayOperation = this._operations[i];
  15164. nextOp = nextArrayOperation.type;
  15165. nextCount = nextArrayOperation.count;
  15166. if (nextOp === DELETE) {
  15167. arrayOperation.count += nextCount;
  15168. continue;
  15169. }
  15170. if (nextCount > deletesToGo) {
  15171. // d:2 {r,i}:5 we reduce the retain or insert, but it stays
  15172. removedItems = removedItems.concat(nextArrayOperation.items.splice(0, deletesToGo));
  15173. nextArrayOperation.count -= deletesToGo;
  15174. // In the case where we truncate the last arrayOperation, we don't need to
  15175. // remove it; also the deletesToGo reduction is not the entirety of
  15176. // nextCount
  15177. i -= 1;
  15178. nextCount = deletesToGo;
  15179. deletesToGo = 0;
  15180. } else {
  15181. if (nextCount === deletesToGo) {
  15182. // Handle edge case of d:2 i:2 in which case both operations go away
  15183. // during composition.
  15184. removeNewAndNextOp = true;
  15185. }
  15186. removedItems = removedItems.concat(nextArrayOperation.items);
  15187. deletesToGo -= nextCount;
  15188. }
  15189. if (nextOp === INSERT) {
  15190. // d:2 i:3 will result in delete going away
  15191. arrayOperation.count -= nextCount;
  15192. }
  15193. }
  15194. if (arrayOperation.count > 0) {
  15195. // compose our new delete with possibly several operations to the right of
  15196. // disparate types
  15197. this._operations.splice(index+1, i-1-index);
  15198. } else {
  15199. // The delete operation can go away; it has merely reduced some other
  15200. // operation, as in d:3 i:4; it may also have eliminated that operation,
  15201. // as in d:3 i:3.
  15202. this._operations.splice(index, removeNewAndNextOp ? 2 : 1);
  15203. }
  15204. return removedItems;
  15205. },
  15206. toString: function () {
  15207. var str = "";
  15208. forEach(this._operations, function (operation) {
  15209. str += " " + operation.type + ":" + operation.count;
  15210. });
  15211. return str.substring(1);
  15212. }
  15213. };
  15214. /**
  15215. Internal data structure to represent an array operation.
  15216. @method ArrayOperation
  15217. @private
  15218. @param {string} type The type of the operation. One of
  15219. `Ember.TrackedArray.{RETAIN, INSERT, DELETE}`
  15220. @param {number} count The number of items in this operation.
  15221. @param {array} items The items of the operation, if included. RETAIN and
  15222. INSERT include their items, DELETE does not.
  15223. */
  15224. function ArrayOperation (operation, count, items) {
  15225. this.type = operation; // RETAIN | INSERT | DELETE
  15226. this.count = count;
  15227. this.items = items;
  15228. }
  15229. /**
  15230. Internal data structure used to include information when looking up operations
  15231. by item index.
  15232. @method ArrayOperationMatch
  15233. @private
  15234. @param {ArrayOperation} operation
  15235. @param {number} index The index of `operation` in the array of operations.
  15236. @param {boolean} split Whether or not the item index searched for would
  15237. require a split for a new operation type.
  15238. @param {number} rangeStart The index of the first item in the operation,
  15239. with respect to the tracked array. The index of the last item can be computed
  15240. from `rangeStart` and `operation.count`.
  15241. */
  15242. function ArrayOperationMatch(operation, index, split, rangeStart) {
  15243. this.operation = operation;
  15244. this.index = index;
  15245. this.split = split;
  15246. this.rangeStart = rangeStart;
  15247. }
  15248. })();
  15249. (function() {
  15250. var get = Ember.get,
  15251. forEach = Ember.EnumerableUtils.forEach,
  15252. RETAIN = 'r',
  15253. FILTER = 'f';
  15254. function Operation (type, count) {
  15255. this.type = type;
  15256. this.count = count;
  15257. }
  15258. /**
  15259. An `Ember.SubArray` tracks an array in a way similar to, but more specialized
  15260. than, `Ember.TrackedArray`. It is useful for keeping track of the indexes of
  15261. items within a filtered array.
  15262. @class SubArray
  15263. @namespace Ember
  15264. */
  15265. Ember.SubArray = function (length) {
  15266. if (arguments.length < 1) { length = 0; }
  15267. if (length > 0) {
  15268. this._operations = [new Operation(RETAIN, length)];
  15269. } else {
  15270. this._operations = [];
  15271. }
  15272. };
  15273. Ember.SubArray.prototype = {
  15274. /**
  15275. Track that an item was added to the tracked array.
  15276. @method addItem
  15277. @param {number} index The index of the item in the tracked array.
  15278. @param {boolean} match `true` iff the item is included in the subarray.
  15279. @return {number} The index of the item in the subarray.
  15280. */
  15281. addItem: function(index, match) {
  15282. var returnValue = -1,
  15283. itemType = match ? RETAIN : FILTER,
  15284. self = this;
  15285. this._findOperation(index, function(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) {
  15286. var newOperation, splitOperation;
  15287. if (itemType === operation.type) {
  15288. ++operation.count;
  15289. } else if (index === rangeStart) {
  15290. // insert to the left of `operation`
  15291. self._operations.splice(operationIndex, 0, new Operation(itemType, 1));
  15292. } else {
  15293. newOperation = new Operation(itemType, 1);
  15294. splitOperation = new Operation(operation.type, rangeEnd - index + 1);
  15295. operation.count = index - rangeStart;
  15296. self._operations.splice(operationIndex + 1, 0, newOperation, splitOperation);
  15297. }
  15298. if (match) {
  15299. if (operation.type === RETAIN) {
  15300. returnValue = seenInSubArray + (index - rangeStart);
  15301. } else {
  15302. returnValue = seenInSubArray;
  15303. }
  15304. }
  15305. self._composeAt(operationIndex);
  15306. }, function(seenInSubArray) {
  15307. self._operations.push(new Operation(itemType, 1));
  15308. if (match) {
  15309. returnValue = seenInSubArray;
  15310. }
  15311. self._composeAt(self._operations.length-1);
  15312. });
  15313. return returnValue;
  15314. },
  15315. /**
  15316. Track that an item was removed from the tracked array.
  15317. @method removeItem
  15318. @param {number} index The index of the item in the tracked array.
  15319. @return {number} The index of the item in the subarray, or `-1` if the item
  15320. was not in the subarray.
  15321. */
  15322. removeItem: function(index) {
  15323. var returnValue = -1,
  15324. self = this;
  15325. this._findOperation(index, function (operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) {
  15326. if (operation.type === RETAIN) {
  15327. returnValue = seenInSubArray + (index - rangeStart);
  15328. }
  15329. if (operation.count > 1) {
  15330. --operation.count;
  15331. } else {
  15332. self._operations.splice(operationIndex, 1);
  15333. self._composeAt(operationIndex);
  15334. }
  15335. }, function() {
  15336. throw new Ember.Error("Can't remove an item that has never been added.");
  15337. });
  15338. return returnValue;
  15339. },
  15340. _findOperation: function (index, foundCallback, notFoundCallback) {
  15341. var operationIndex,
  15342. len,
  15343. operation,
  15344. rangeStart,
  15345. rangeEnd,
  15346. seenInSubArray = 0;
  15347. // OPTIMIZE: change to balanced tree
  15348. // find leftmost operation to the right of `index`
  15349. for (operationIndex = rangeStart = 0, len = this._operations.length; operationIndex < len; rangeStart = rangeEnd + 1, ++operationIndex) {
  15350. operation = this._operations[operationIndex];
  15351. rangeEnd = rangeStart + operation.count - 1;
  15352. if (index >= rangeStart && index <= rangeEnd) {
  15353. foundCallback(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray);
  15354. return;
  15355. } else if (operation.type === RETAIN) {
  15356. seenInSubArray += operation.count;
  15357. }
  15358. }
  15359. notFoundCallback(seenInSubArray);
  15360. },
  15361. _composeAt: function(index) {
  15362. var op = this._operations[index],
  15363. otherOp;
  15364. if (!op) {
  15365. // Composing out of bounds is a no-op, as when removing the last operation
  15366. // in the list.
  15367. return;
  15368. }
  15369. if (index > 0) {
  15370. otherOp = this._operations[index-1];
  15371. if (otherOp.type === op.type) {
  15372. op.count += otherOp.count;
  15373. this._operations.splice(index-1, 1);
  15374. --index;
  15375. }
  15376. }
  15377. if (index < this._operations.length-1) {
  15378. otherOp = this._operations[index+1];
  15379. if (otherOp.type === op.type) {
  15380. op.count += otherOp.count;
  15381. this._operations.splice(index+1, 1);
  15382. }
  15383. }
  15384. },
  15385. toString: function () {
  15386. var str = "";
  15387. forEach(this._operations, function (operation) {
  15388. str += " " + operation.type + ":" + operation.count;
  15389. });
  15390. return str.substring(1);
  15391. }
  15392. };
  15393. })();
  15394. (function() {
  15395. Ember.Container = requireModule('container');
  15396. Ember.Container.set = Ember.set;
  15397. })();
  15398. (function() {
  15399. Ember.Application = Ember.Namespace.extend();
  15400. })();
  15401. (function() {
  15402. /**
  15403. @module ember
  15404. @submodule ember-runtime
  15405. */
  15406. var OUT_OF_RANGE_EXCEPTION = "Index out of range";
  15407. var EMPTY = [];
  15408. var get = Ember.get, set = Ember.set;
  15409. /**
  15410. An ArrayProxy wraps any other object that implements `Ember.Array` and/or
  15411. `Ember.MutableArray,` forwarding all requests. This makes it very useful for
  15412. a number of binding use cases or other cases where being able to swap
  15413. out the underlying array is useful.
  15414. A simple example of usage:
  15415. ```javascript
  15416. var pets = ['dog', 'cat', 'fish'];
  15417. var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) });
  15418. ap.get('firstObject'); // 'dog'
  15419. ap.set('content', ['amoeba', 'paramecium']);
  15420. ap.get('firstObject'); // 'amoeba'
  15421. ```
  15422. This class can also be useful as a layer to transform the contents of
  15423. an array, as they are accessed. This can be done by overriding
  15424. `objectAtContent`:
  15425. ```javascript
  15426. var pets = ['dog', 'cat', 'fish'];
  15427. var ap = Ember.ArrayProxy.create({
  15428. content: Ember.A(pets),
  15429. objectAtContent: function(idx) {
  15430. return this.get('content').objectAt(idx).toUpperCase();
  15431. }
  15432. });
  15433. ap.get('firstObject'); // . 'DOG'
  15434. ```
  15435. @class ArrayProxy
  15436. @namespace Ember
  15437. @extends Ember.Object
  15438. @uses Ember.MutableArray
  15439. */
  15440. Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray, {
  15441. /**
  15442. The content array. Must be an object that implements `Ember.Array` and/or
  15443. `Ember.MutableArray.`
  15444. @property content
  15445. @type Ember.Array
  15446. */
  15447. content: null,
  15448. /**
  15449. The array that the proxy pretends to be. In the default `ArrayProxy`
  15450. implementation, this and `content` are the same. Subclasses of `ArrayProxy`
  15451. can override this property to provide things like sorting and filtering.
  15452. @property arrangedContent
  15453. */
  15454. arrangedContent: Ember.computed.alias('content'),
  15455. /**
  15456. Should actually retrieve the object at the specified index from the
  15457. content. You can override this method in subclasses to transform the
  15458. content item to something new.
  15459. This method will only be called if content is non-`null`.
  15460. @method objectAtContent
  15461. @param {Number} idx The index to retrieve.
  15462. @return {Object} the value or undefined if none found
  15463. */
  15464. objectAtContent: function(idx) {
  15465. return get(this, 'arrangedContent').objectAt(idx);
  15466. },
  15467. /**
  15468. Should actually replace the specified objects on the content array.
  15469. You can override this method in subclasses to transform the content item
  15470. into something new.
  15471. This method will only be called if content is non-`null`.
  15472. @method replaceContent
  15473. @param {Number} idx The starting index
  15474. @param {Number} amt The number of items to remove from the content.
  15475. @param {Array} objects Optional array of objects to insert or null if no
  15476. objects.
  15477. @return {void}
  15478. */
  15479. replaceContent: function(idx, amt, objects) {
  15480. get(this, 'content').replace(idx, amt, objects);
  15481. },
  15482. /**
  15483. Invoked when the content property is about to change. Notifies observers that the
  15484. entire array content will change.
  15485. @private
  15486. @method _contentWillChange
  15487. */
  15488. _contentWillChange: Ember.beforeObserver('content', function() {
  15489. this._teardownContent();
  15490. }),
  15491. _teardownContent: function() {
  15492. var content = get(this, 'content');
  15493. if (content) {
  15494. content.removeArrayObserver(this, {
  15495. willChange: 'contentArrayWillChange',
  15496. didChange: 'contentArrayDidChange'
  15497. });
  15498. }
  15499. },
  15500. contentArrayWillChange: Ember.K,
  15501. contentArrayDidChange: Ember.K,
  15502. /**
  15503. Invoked when the content property changes. Notifies observers that the
  15504. entire array content has changed.
  15505. @private
  15506. @method _contentDidChange
  15507. */
  15508. _contentDidChange: Ember.observer('content', function() {
  15509. var content = get(this, 'content');
  15510. Ember.assert("Can't set ArrayProxy's content to itself", content !== this);
  15511. this._setupContent();
  15512. }),
  15513. _setupContent: function() {
  15514. var content = get(this, 'content');
  15515. if (content) {
  15516. content.addArrayObserver(this, {
  15517. willChange: 'contentArrayWillChange',
  15518. didChange: 'contentArrayDidChange'
  15519. });
  15520. }
  15521. },
  15522. _arrangedContentWillChange: Ember.beforeObserver('arrangedContent', function() {
  15523. var arrangedContent = get(this, 'arrangedContent'),
  15524. len = arrangedContent ? get(arrangedContent, 'length') : 0;
  15525. this.arrangedContentArrayWillChange(this, 0, len, undefined);
  15526. this.arrangedContentWillChange(this);
  15527. this._teardownArrangedContent(arrangedContent);
  15528. }),
  15529. _arrangedContentDidChange: Ember.observer('arrangedContent', function() {
  15530. var arrangedContent = get(this, 'arrangedContent'),
  15531. len = arrangedContent ? get(arrangedContent, 'length') : 0;
  15532. Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this);
  15533. this._setupArrangedContent();
  15534. this.arrangedContentDidChange(this);
  15535. this.arrangedContentArrayDidChange(this, 0, undefined, len);
  15536. }),
  15537. _setupArrangedContent: function() {
  15538. var arrangedContent = get(this, 'arrangedContent');
  15539. if (arrangedContent) {
  15540. arrangedContent.addArrayObserver(this, {
  15541. willChange: 'arrangedContentArrayWillChange',
  15542. didChange: 'arrangedContentArrayDidChange'
  15543. });
  15544. }
  15545. },
  15546. _teardownArrangedContent: function() {
  15547. var arrangedContent = get(this, 'arrangedContent');
  15548. if (arrangedContent) {
  15549. arrangedContent.removeArrayObserver(this, {
  15550. willChange: 'arrangedContentArrayWillChange',
  15551. didChange: 'arrangedContentArrayDidChange'
  15552. });
  15553. }
  15554. },
  15555. arrangedContentWillChange: Ember.K,
  15556. arrangedContentDidChange: Ember.K,
  15557. objectAt: function(idx) {
  15558. return get(this, 'content') && this.objectAtContent(idx);
  15559. },
  15560. length: Ember.computed(function() {
  15561. var arrangedContent = get(this, 'arrangedContent');
  15562. return arrangedContent ? get(arrangedContent, 'length') : 0;
  15563. // No dependencies since Enumerable notifies length of change
  15564. }),
  15565. _replace: function(idx, amt, objects) {
  15566. var content = get(this, 'content');
  15567. Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', content);
  15568. if (content) this.replaceContent(idx, amt, objects);
  15569. return this;
  15570. },
  15571. replace: function() {
  15572. if (get(this, 'arrangedContent') === get(this, 'content')) {
  15573. this._replace.apply(this, arguments);
  15574. } else {
  15575. throw new Ember.Error("Using replace on an arranged ArrayProxy is not allowed.");
  15576. }
  15577. },
  15578. _insertAt: function(idx, object) {
  15579. if (idx > get(this, 'content.length')) throw new Ember.Error(OUT_OF_RANGE_EXCEPTION);
  15580. this._replace(idx, 0, [object]);
  15581. return this;
  15582. },
  15583. insertAt: function(idx, object) {
  15584. if (get(this, 'arrangedContent') === get(this, 'content')) {
  15585. return this._insertAt(idx, object);
  15586. } else {
  15587. throw new Ember.Error("Using insertAt on an arranged ArrayProxy is not allowed.");
  15588. }
  15589. },
  15590. removeAt: function(start, len) {
  15591. if ('number' === typeof start) {
  15592. var content = get(this, 'content'),
  15593. arrangedContent = get(this, 'arrangedContent'),
  15594. indices = [], i;
  15595. if ((start < 0) || (start >= get(this, 'length'))) {
  15596. throw new Ember.Error(OUT_OF_RANGE_EXCEPTION);
  15597. }
  15598. if (len === undefined) len = 1;
  15599. // Get a list of indices in original content to remove
  15600. for (i=start; i<start+len; i++) {
  15601. // Use arrangedContent here so we avoid confusion with objects transformed by objectAtContent
  15602. indices.push(content.indexOf(arrangedContent.objectAt(i)));
  15603. }
  15604. // Replace in reverse order since indices will change
  15605. indices.sort(function(a,b) { return b - a; });
  15606. Ember.beginPropertyChanges();
  15607. for (i=0; i<indices.length; i++) {
  15608. this._replace(indices[i], 1, EMPTY);
  15609. }
  15610. Ember.endPropertyChanges();
  15611. }
  15612. return this ;
  15613. },
  15614. pushObject: function(obj) {
  15615. this._insertAt(get(this, 'content.length'), obj) ;
  15616. return obj ;
  15617. },
  15618. pushObjects: function(objects) {
  15619. if (!(Ember.Enumerable.detect(objects) || Ember.isArray(objects))) {
  15620. throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects");
  15621. }
  15622. this._replace(get(this, 'length'), 0, objects);
  15623. return this;
  15624. },
  15625. setObjects: function(objects) {
  15626. if (objects.length === 0) return this.clear();
  15627. var len = get(this, 'length');
  15628. this._replace(0, len, objects);
  15629. return this;
  15630. },
  15631. unshiftObject: function(obj) {
  15632. this._insertAt(0, obj) ;
  15633. return obj ;
  15634. },
  15635. unshiftObjects: function(objects) {
  15636. this._replace(0, 0, objects);
  15637. return this;
  15638. },
  15639. slice: function() {
  15640. var arr = this.toArray();
  15641. return arr.slice.apply(arr, arguments);
  15642. },
  15643. arrangedContentArrayWillChange: function(item, idx, removedCnt, addedCnt) {
  15644. this.arrayContentWillChange(idx, removedCnt, addedCnt);
  15645. },
  15646. arrangedContentArrayDidChange: function(item, idx, removedCnt, addedCnt) {
  15647. this.arrayContentDidChange(idx, removedCnt, addedCnt);
  15648. },
  15649. init: function() {
  15650. this._super();
  15651. this._setupContent();
  15652. this._setupArrangedContent();
  15653. },
  15654. willDestroy: function() {
  15655. this._teardownArrangedContent();
  15656. this._teardownContent();
  15657. }
  15658. });
  15659. })();
  15660. (function() {
  15661. /**
  15662. @module ember
  15663. @submodule ember-runtime
  15664. */
  15665. var set = Ember.set, get = Ember.get, guidFor = Ember.guidFor;
  15666. var forEach = Ember.EnumerableUtils.forEach,
  15667. indexOf = Ember.ArrayPolyfills.indexOf;
  15668. var EachArray = Ember.Object.extend(Ember.Array, {
  15669. init: function(content, keyName, owner) {
  15670. this._super();
  15671. this._keyName = keyName;
  15672. this._owner = owner;
  15673. this._content = content;
  15674. },
  15675. objectAt: function(idx) {
  15676. var item = this._content.objectAt(idx);
  15677. return item && get(item, this._keyName);
  15678. },
  15679. length: Ember.computed(function() {
  15680. var content = this._content;
  15681. return content ? get(content, 'length') : 0;
  15682. })
  15683. });
  15684. var IS_OBSERVER = /^.+:(before|change)$/;
  15685. function addObserverForContentKey(content, keyName, proxy, idx, loc) {
  15686. var objects = proxy._objects, guid;
  15687. if (!objects) objects = proxy._objects = {};
  15688. while(--loc>=idx) {
  15689. var item = content.objectAt(loc);
  15690. if (item) {
  15691. Ember.assert('When using @each to observe the array ' + content + ', the array must return an object', Ember.typeOf(item) === 'instance' || Ember.typeOf(item) === 'object');
  15692. Ember.addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange');
  15693. Ember.addObserver(item, keyName, proxy, 'contentKeyDidChange');
  15694. // keep track of the index each item was found at so we can map
  15695. // it back when the obj changes.
  15696. guid = guidFor(item);
  15697. if (!objects[guid]) objects[guid] = [];
  15698. objects[guid].push(loc);
  15699. }
  15700. }
  15701. }
  15702. function removeObserverForContentKey(content, keyName, proxy, idx, loc) {
  15703. var objects = proxy._objects;
  15704. if (!objects) objects = proxy._objects = {};
  15705. var indicies, guid;
  15706. while(--loc>=idx) {
  15707. var item = content.objectAt(loc);
  15708. if (item) {
  15709. Ember.removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange');
  15710. Ember.removeObserver(item, keyName, proxy, 'contentKeyDidChange');
  15711. guid = guidFor(item);
  15712. indicies = objects[guid];
  15713. indicies[indexOf.call(indicies, loc)] = null;
  15714. }
  15715. }
  15716. }
  15717. /**
  15718. This is the object instance returned when you get the `@each` property on an
  15719. array. It uses the unknownProperty handler to automatically create
  15720. EachArray instances for property names.
  15721. @private
  15722. @class EachProxy
  15723. @namespace Ember
  15724. @extends Ember.Object
  15725. */
  15726. Ember.EachProxy = Ember.Object.extend({
  15727. init: function(content) {
  15728. this._super();
  15729. this._content = content;
  15730. content.addArrayObserver(this);
  15731. // in case someone is already observing some keys make sure they are
  15732. // added
  15733. forEach(Ember.watchedEvents(this), function(eventName) {
  15734. this.didAddListener(eventName);
  15735. }, this);
  15736. },
  15737. /**
  15738. You can directly access mapped properties by simply requesting them.
  15739. The `unknownProperty` handler will generate an EachArray of each item.
  15740. @method unknownProperty
  15741. @param keyName {String}
  15742. @param value {*}
  15743. */
  15744. unknownProperty: function(keyName, value) {
  15745. var ret;
  15746. ret = new EachArray(this._content, keyName, this);
  15747. Ember.defineProperty(this, keyName, null, ret);
  15748. this.beginObservingContentKey(keyName);
  15749. return ret;
  15750. },
  15751. // ..........................................................
  15752. // ARRAY CHANGES
  15753. // Invokes whenever the content array itself changes.
  15754. arrayWillChange: function(content, idx, removedCnt, addedCnt) {
  15755. var keys = this._keys, key, lim;
  15756. lim = removedCnt>0 ? idx+removedCnt : -1;
  15757. Ember.beginPropertyChanges(this);
  15758. for(key in keys) {
  15759. if (!keys.hasOwnProperty(key)) { continue; }
  15760. if (lim>0) { removeObserverForContentKey(content, key, this, idx, lim); }
  15761. Ember.propertyWillChange(this, key);
  15762. }
  15763. Ember.propertyWillChange(this._content, '@each');
  15764. Ember.endPropertyChanges(this);
  15765. },
  15766. arrayDidChange: function(content, idx, removedCnt, addedCnt) {
  15767. var keys = this._keys, lim;
  15768. lim = addedCnt>0 ? idx+addedCnt : -1;
  15769. Ember.changeProperties(function() {
  15770. for(var key in keys) {
  15771. if (!keys.hasOwnProperty(key)) { continue; }
  15772. if (lim>0) { addObserverForContentKey(content, key, this, idx, lim); }
  15773. Ember.propertyDidChange(this, key);
  15774. }
  15775. Ember.propertyDidChange(this._content, '@each');
  15776. }, this);
  15777. },
  15778. // ..........................................................
  15779. // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS
  15780. // Start monitoring keys based on who is listening...
  15781. didAddListener: function(eventName) {
  15782. if (IS_OBSERVER.test(eventName)) {
  15783. this.beginObservingContentKey(eventName.slice(0, -7));
  15784. }
  15785. },
  15786. didRemoveListener: function(eventName) {
  15787. if (IS_OBSERVER.test(eventName)) {
  15788. this.stopObservingContentKey(eventName.slice(0, -7));
  15789. }
  15790. },
  15791. // ..........................................................
  15792. // CONTENT KEY OBSERVING
  15793. // Actual watch keys on the source content.
  15794. beginObservingContentKey: function(keyName) {
  15795. var keys = this._keys;
  15796. if (!keys) keys = this._keys = {};
  15797. if (!keys[keyName]) {
  15798. keys[keyName] = 1;
  15799. var content = this._content,
  15800. len = get(content, 'length');
  15801. addObserverForContentKey(content, keyName, this, 0, len);
  15802. } else {
  15803. keys[keyName]++;
  15804. }
  15805. },
  15806. stopObservingContentKey: function(keyName) {
  15807. var keys = this._keys;
  15808. if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) {
  15809. var content = this._content,
  15810. len = get(content, 'length');
  15811. removeObserverForContentKey(content, keyName, this, 0, len);
  15812. }
  15813. },
  15814. contentKeyWillChange: function(obj, keyName) {
  15815. Ember.propertyWillChange(this, keyName);
  15816. },
  15817. contentKeyDidChange: function(obj, keyName) {
  15818. Ember.propertyDidChange(this, keyName);
  15819. }
  15820. });
  15821. })();
  15822. (function() {
  15823. /**
  15824. @module ember
  15825. @submodule ember-runtime
  15826. */
  15827. var get = Ember.get, set = Ember.set, replace = Ember.EnumerableUtils._replace;
  15828. // Add Ember.Array to Array.prototype. Remove methods with native
  15829. // implementations and supply some more optimized versions of generic methods
  15830. // because they are so common.
  15831. var NativeArray = Ember.Mixin.create(Ember.MutableArray, Ember.Observable, Ember.Copyable, {
  15832. // because length is a built-in property we need to know to just get the
  15833. // original property.
  15834. get: function(key) {
  15835. if (key==='length') return this.length;
  15836. else if ('number' === typeof key) return this[key];
  15837. else return this._super(key);
  15838. },
  15839. objectAt: function(idx) {
  15840. return this[idx];
  15841. },
  15842. // primitive for array support.
  15843. replace: function(idx, amt, objects) {
  15844. if (this.isFrozen) throw Ember.FROZEN_ERROR;
  15845. // if we replaced exactly the same number of items, then pass only the
  15846. // replaced range. Otherwise, pass the full remaining array length
  15847. // since everything has shifted
  15848. var len = objects ? get(objects, 'length') : 0;
  15849. this.arrayContentWillChange(idx, amt, len);
  15850. if (len === 0) {
  15851. this.splice(idx, amt);
  15852. } else {
  15853. replace(this, idx, amt, objects);
  15854. }
  15855. this.arrayContentDidChange(idx, amt, len);
  15856. return this;
  15857. },
  15858. // If you ask for an unknown property, then try to collect the value
  15859. // from member items.
  15860. unknownProperty: function(key, value) {
  15861. var ret;// = this.reducedProperty(key, value) ;
  15862. if ((value !== undefined) && ret === undefined) {
  15863. ret = this[key] = value;
  15864. }
  15865. return ret ;
  15866. },
  15867. // If browser did not implement indexOf natively, then override with
  15868. // specialized version
  15869. indexOf: function(object, startAt) {
  15870. var idx, len = this.length;
  15871. if (startAt === undefined) startAt = 0;
  15872. else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
  15873. if (startAt < 0) startAt += len;
  15874. for(idx=startAt;idx<len;idx++) {
  15875. if (this[idx] === object) return idx ;
  15876. }
  15877. return -1;
  15878. },
  15879. lastIndexOf: function(object, startAt) {
  15880. var idx, len = this.length;
  15881. if (startAt === undefined) startAt = len-1;
  15882. else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
  15883. if (startAt < 0) startAt += len;
  15884. for(idx=startAt;idx>=0;idx--) {
  15885. if (this[idx] === object) return idx ;
  15886. }
  15887. return -1;
  15888. },
  15889. copy: function(deep) {
  15890. if (deep) {
  15891. return this.map(function(item) { return Ember.copy(item, true); });
  15892. }
  15893. return this.slice();
  15894. }
  15895. });
  15896. // Remove any methods implemented natively so we don't override them
  15897. var ignore = ['length'];
  15898. Ember.EnumerableUtils.forEach(NativeArray.keys(), function(methodName) {
  15899. if (Array.prototype[methodName]) ignore.push(methodName);
  15900. });
  15901. if (ignore.length>0) {
  15902. NativeArray = NativeArray.without.apply(NativeArray, ignore);
  15903. }
  15904. /**
  15905. The NativeArray mixin contains the properties needed to to make the native
  15906. Array support Ember.MutableArray and all of its dependent APIs. Unless you
  15907. have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` set to
  15908. false, this will be applied automatically. Otherwise you can apply the mixin
  15909. at anytime by calling `Ember.NativeArray.activate`.
  15910. @class NativeArray
  15911. @namespace Ember
  15912. @uses Ember.MutableArray
  15913. @uses Ember.Observable
  15914. @uses Ember.Copyable
  15915. */
  15916. Ember.NativeArray = NativeArray;
  15917. /**
  15918. Creates an `Ember.NativeArray` from an Array like object.
  15919. Does not modify the original object. Ember.A is not needed if
  15920. `Ember.EXTEND_PROTOTYPES` is `true` (the default value). However,
  15921. it is recommended that you use Ember.A when creating addons for
  15922. ember or when you can not guarantee that `Ember.EXTEND_PROTOTYPES`
  15923. will be `true`.
  15924. Example
  15925. ```js
  15926. var Pagination = Ember.CollectionView.extend({
  15927. tagName: 'ul',
  15928. classNames: ['pagination'],
  15929. init: function() {
  15930. this._super();
  15931. if (!this.get('content')) {
  15932. this.set('content', Ember.A([]));
  15933. }
  15934. }
  15935. });
  15936. ```
  15937. @method A
  15938. @for Ember
  15939. @return {Ember.NativeArray}
  15940. */
  15941. Ember.A = function(arr) {
  15942. if (arr === undefined) { arr = []; }
  15943. return Ember.Array.detect(arr) ? arr : Ember.NativeArray.apply(arr);
  15944. };
  15945. /**
  15946. Activates the mixin on the Array.prototype if not already applied. Calling
  15947. this method more than once is safe. This will be called when ember is loaded
  15948. unless you have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array`
  15949. set to `false`.
  15950. Example
  15951. ```js
  15952. if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) {
  15953. Ember.NativeArray.activate();
  15954. }
  15955. ```
  15956. @method activate
  15957. @for Ember.NativeArray
  15958. @static
  15959. @return {void}
  15960. */
  15961. Ember.NativeArray.activate = function() {
  15962. NativeArray.apply(Array.prototype);
  15963. Ember.A = function(arr) { return arr || []; };
  15964. };
  15965. if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) {
  15966. Ember.NativeArray.activate();
  15967. }
  15968. })();
  15969. (function() {
  15970. /**
  15971. @module ember
  15972. @submodule ember-runtime
  15973. */
  15974. var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor, isNone = Ember.isNone, fmt = Ember.String.fmt;
  15975. /**
  15976. An unordered collection of objects.
  15977. A Set works a bit like an array except that its items are not ordered. You
  15978. can create a set to efficiently test for membership for an object. You can
  15979. also iterate through a set just like an array, even accessing objects by
  15980. index, however there is no guarantee as to their order.
  15981. All Sets are observable via the Enumerable Observer API - which works
  15982. on any enumerable object including both Sets and Arrays.
  15983. ## Creating a Set
  15984. You can create a set like you would most objects using
  15985. `new Ember.Set()`. Most new sets you create will be empty, but you can
  15986. also initialize the set with some content by passing an array or other
  15987. enumerable of objects to the constructor.
  15988. Finally, you can pass in an existing set and the set will be copied. You
  15989. can also create a copy of a set by calling `Ember.Set#copy()`.
  15990. ```javascript
  15991. // creates a new empty set
  15992. var foundNames = new Ember.Set();
  15993. // creates a set with four names in it.
  15994. var names = new Ember.Set(["Charles", "Tom", "Juan", "Alex"]); // :P
  15995. // creates a copy of the names set.
  15996. var namesCopy = new Ember.Set(names);
  15997. // same as above.
  15998. var anotherNamesCopy = names.copy();
  15999. ```
  16000. ## Adding/Removing Objects
  16001. You generally add or remove objects from a set using `add()` or
  16002. `remove()`. You can add any type of object including primitives such as
  16003. numbers, strings, and booleans.
  16004. Unlike arrays, objects can only exist one time in a set. If you call `add()`
  16005. on a set with the same object multiple times, the object will only be added
  16006. once. Likewise, calling `remove()` with the same object multiple times will
  16007. remove the object the first time and have no effect on future calls until
  16008. you add the object to the set again.
  16009. NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do
  16010. so will be ignored.
  16011. In addition to add/remove you can also call `push()`/`pop()`. Push behaves
  16012. just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary
  16013. object, remove it and return it. This is a good way to use a set as a job
  16014. queue when you don't care which order the jobs are executed in.
  16015. ## Testing for an Object
  16016. To test for an object's presence in a set you simply call
  16017. `Ember.Set#contains()`.
  16018. ## Observing changes
  16019. When using `Ember.Set`, you can observe the `"[]"` property to be
  16020. alerted whenever the content changes. You can also add an enumerable
  16021. observer to the set to be notified of specific objects that are added and
  16022. removed from the set. See [Ember.Enumerable](/api/classes/Ember.Enumerable.html)
  16023. for more information on enumerables.
  16024. This is often unhelpful. If you are filtering sets of objects, for instance,
  16025. it is very inefficient to re-filter all of the items each time the set
  16026. changes. It would be better if you could just adjust the filtered set based
  16027. on what was changed on the original set. The same issue applies to merging
  16028. sets, as well.
  16029. ## Other Methods
  16030. `Ember.Set` primary implements other mixin APIs. For a complete reference
  16031. on the methods you will use with `Ember.Set`, please consult these mixins.
  16032. The most useful ones will be `Ember.Enumerable` and
  16033. `Ember.MutableEnumerable` which implement most of the common iterator
  16034. methods you are used to on Array.
  16035. Note that you can also use the `Ember.Copyable` and `Ember.Freezable`
  16036. APIs on `Ember.Set` as well. Once a set is frozen it can no longer be
  16037. modified. The benefit of this is that when you call `frozenCopy()` on it,
  16038. Ember will avoid making copies of the set. This allows you to write
  16039. code that can know with certainty when the underlying set data will or
  16040. will not be modified.
  16041. @class Set
  16042. @namespace Ember
  16043. @extends Ember.CoreObject
  16044. @uses Ember.MutableEnumerable
  16045. @uses Ember.Copyable
  16046. @uses Ember.Freezable
  16047. @since Ember 0.9
  16048. */
  16049. Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Ember.Freezable,
  16050. {
  16051. // ..........................................................
  16052. // IMPLEMENT ENUMERABLE APIS
  16053. //
  16054. /**
  16055. This property will change as the number of objects in the set changes.
  16056. @property length
  16057. @type number
  16058. @default 0
  16059. */
  16060. length: 0,
  16061. /**
  16062. Clears the set. This is useful if you want to reuse an existing set
  16063. without having to recreate it.
  16064. ```javascript
  16065. var colors = new Ember.Set(["red", "green", "blue"]);
  16066. colors.length; // 3
  16067. colors.clear();
  16068. colors.length; // 0
  16069. ```
  16070. @method clear
  16071. @return {Ember.Set} An empty Set
  16072. */
  16073. clear: function() {
  16074. if (this.isFrozen) { throw new Ember.Error(Ember.FROZEN_ERROR); }
  16075. var len = get(this, 'length');
  16076. if (len === 0) { return this; }
  16077. var guid;
  16078. this.enumerableContentWillChange(len, 0);
  16079. Ember.propertyWillChange(this, 'firstObject');
  16080. Ember.propertyWillChange(this, 'lastObject');
  16081. for (var i=0; i < len; i++) {
  16082. guid = guidFor(this[i]);
  16083. delete this[guid];
  16084. delete this[i];
  16085. }
  16086. set(this, 'length', 0);
  16087. Ember.propertyDidChange(this, 'firstObject');
  16088. Ember.propertyDidChange(this, 'lastObject');
  16089. this.enumerableContentDidChange(len, 0);
  16090. return this;
  16091. },
  16092. /**
  16093. Returns true if the passed object is also an enumerable that contains the
  16094. same objects as the receiver.
  16095. ```javascript
  16096. var colors = ["red", "green", "blue"],
  16097. same_colors = new Ember.Set(colors);
  16098. same_colors.isEqual(colors); // true
  16099. same_colors.isEqual(["purple", "brown"]); // false
  16100. ```
  16101. @method isEqual
  16102. @param {Ember.Set} obj the other object.
  16103. @return {Boolean}
  16104. */
  16105. isEqual: function(obj) {
  16106. // fail fast
  16107. if (!Ember.Enumerable.detect(obj)) return false;
  16108. var loc = get(this, 'length');
  16109. if (get(obj, 'length') !== loc) return false;
  16110. while(--loc >= 0) {
  16111. if (!obj.contains(this[loc])) return false;
  16112. }
  16113. return true;
  16114. },
  16115. /**
  16116. Adds an object to the set. Only non-`null` objects can be added to a set
  16117. and those can only be added once. If the object is already in the set or
  16118. the passed value is null this method will have no effect.
  16119. This is an alias for `Ember.MutableEnumerable.addObject()`.
  16120. ```javascript
  16121. var colors = new Ember.Set();
  16122. colors.add("blue"); // ["blue"]
  16123. colors.add("blue"); // ["blue"]
  16124. colors.add("red"); // ["blue", "red"]
  16125. colors.add(null); // ["blue", "red"]
  16126. colors.add(undefined); // ["blue", "red"]
  16127. ```
  16128. @method add
  16129. @param {Object} obj The object to add.
  16130. @return {Ember.Set} The set itself.
  16131. */
  16132. add: Ember.aliasMethod('addObject'),
  16133. /**
  16134. Removes the object from the set if it is found. If you pass a `null` value
  16135. or an object that is already not in the set, this method will have no
  16136. effect. This is an alias for `Ember.MutableEnumerable.removeObject()`.
  16137. ```javascript
  16138. var colors = new Ember.Set(["red", "green", "blue"]);
  16139. colors.remove("red"); // ["blue", "green"]
  16140. colors.remove("purple"); // ["blue", "green"]
  16141. colors.remove(null); // ["blue", "green"]
  16142. ```
  16143. @method remove
  16144. @param {Object} obj The object to remove
  16145. @return {Ember.Set} The set itself.
  16146. */
  16147. remove: Ember.aliasMethod('removeObject'),
  16148. /**
  16149. Removes the last element from the set and returns it, or `null` if it's empty.
  16150. ```javascript
  16151. var colors = new Ember.Set(["green", "blue"]);
  16152. colors.pop(); // "blue"
  16153. colors.pop(); // "green"
  16154. colors.pop(); // null
  16155. ```
  16156. @method pop
  16157. @return {Object} The removed object from the set or null.
  16158. */
  16159. pop: function() {
  16160. if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR);
  16161. var obj = this.length > 0 ? this[this.length-1] : null;
  16162. this.remove(obj);
  16163. return obj;
  16164. },
  16165. /**
  16166. Inserts the given object on to the end of the set. It returns
  16167. the set itself.
  16168. This is an alias for `Ember.MutableEnumerable.addObject()`.
  16169. ```javascript
  16170. var colors = new Ember.Set();
  16171. colors.push("red"); // ["red"]
  16172. colors.push("green"); // ["red", "green"]
  16173. colors.push("blue"); // ["red", "green", "blue"]
  16174. ```
  16175. @method push
  16176. @return {Ember.Set} The set itself.
  16177. */
  16178. push: Ember.aliasMethod('addObject'),
  16179. /**
  16180. Removes the last element from the set and returns it, or `null` if it's empty.
  16181. This is an alias for `Ember.Set.pop()`.
  16182. ```javascript
  16183. var colors = new Ember.Set(["green", "blue"]);
  16184. colors.shift(); // "blue"
  16185. colors.shift(); // "green"
  16186. colors.shift(); // null
  16187. ```
  16188. @method shift
  16189. @return {Object} The removed object from the set or null.
  16190. */
  16191. shift: Ember.aliasMethod('pop'),
  16192. /**
  16193. Inserts the given object on to the end of the set. It returns
  16194. the set itself.
  16195. This is an alias of `Ember.Set.push()`
  16196. ```javascript
  16197. var colors = new Ember.Set();
  16198. colors.unshift("red"); // ["red"]
  16199. colors.unshift("green"); // ["red", "green"]
  16200. colors.unshift("blue"); // ["red", "green", "blue"]
  16201. ```
  16202. @method unshift
  16203. @return {Ember.Set} The set itself.
  16204. */
  16205. unshift: Ember.aliasMethod('push'),
  16206. /**
  16207. Adds each object in the passed enumerable to the set.
  16208. This is an alias of `Ember.MutableEnumerable.addObjects()`
  16209. ```javascript
  16210. var colors = new Ember.Set();
  16211. colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"]
  16212. ```
  16213. @method addEach
  16214. @param {Ember.Enumerable} objects the objects to add.
  16215. @return {Ember.Set} The set itself.
  16216. */
  16217. addEach: Ember.aliasMethod('addObjects'),
  16218. /**
  16219. Removes each object in the passed enumerable to the set.
  16220. This is an alias of `Ember.MutableEnumerable.removeObjects()`
  16221. ```javascript
  16222. var colors = new Ember.Set(["red", "green", "blue"]);
  16223. colors.removeEach(["red", "blue"]); // ["green"]
  16224. ```
  16225. @method removeEach
  16226. @param {Ember.Enumerable} objects the objects to remove.
  16227. @return {Ember.Set} The set itself.
  16228. */
  16229. removeEach: Ember.aliasMethod('removeObjects'),
  16230. // ..........................................................
  16231. // PRIVATE ENUMERABLE SUPPORT
  16232. //
  16233. init: function(items) {
  16234. this._super();
  16235. if (items) this.addObjects(items);
  16236. },
  16237. // implement Ember.Enumerable
  16238. nextObject: function(idx) {
  16239. return this[idx];
  16240. },
  16241. // more optimized version
  16242. firstObject: Ember.computed(function() {
  16243. return this.length > 0 ? this[0] : undefined;
  16244. }),
  16245. // more optimized version
  16246. lastObject: Ember.computed(function() {
  16247. return this.length > 0 ? this[this.length-1] : undefined;
  16248. }),
  16249. // implements Ember.MutableEnumerable
  16250. addObject: function(obj) {
  16251. if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR);
  16252. if (isNone(obj)) return this; // nothing to do
  16253. var guid = guidFor(obj),
  16254. idx = this[guid],
  16255. len = get(this, 'length'),
  16256. added ;
  16257. if (idx>=0 && idx<len && (this[idx] === obj)) return this; // added
  16258. added = [obj];
  16259. this.enumerableContentWillChange(null, added);
  16260. Ember.propertyWillChange(this, 'lastObject');
  16261. len = get(this, 'length');
  16262. this[guid] = len;
  16263. this[len] = obj;
  16264. set(this, 'length', len+1);
  16265. Ember.propertyDidChange(this, 'lastObject');
  16266. this.enumerableContentDidChange(null, added);
  16267. return this;
  16268. },
  16269. // implements Ember.MutableEnumerable
  16270. removeObject: function(obj) {
  16271. if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR);
  16272. if (isNone(obj)) return this; // nothing to do
  16273. var guid = guidFor(obj),
  16274. idx = this[guid],
  16275. len = get(this, 'length'),
  16276. isFirst = idx === 0,
  16277. isLast = idx === len-1,
  16278. last, removed;
  16279. if (idx>=0 && idx<len && (this[idx] === obj)) {
  16280. removed = [obj];
  16281. this.enumerableContentWillChange(removed, null);
  16282. if (isFirst) { Ember.propertyWillChange(this, 'firstObject'); }
  16283. if (isLast) { Ember.propertyWillChange(this, 'lastObject'); }
  16284. // swap items - basically move the item to the end so it can be removed
  16285. if (idx < len-1) {
  16286. last = this[len-1];
  16287. this[idx] = last;
  16288. this[guidFor(last)] = idx;
  16289. }
  16290. delete this[guid];
  16291. delete this[len-1];
  16292. set(this, 'length', len-1);
  16293. if (isFirst) { Ember.propertyDidChange(this, 'firstObject'); }
  16294. if (isLast) { Ember.propertyDidChange(this, 'lastObject'); }
  16295. this.enumerableContentDidChange(removed, null);
  16296. }
  16297. return this;
  16298. },
  16299. // optimized version
  16300. contains: function(obj) {
  16301. return this[guidFor(obj)]>=0;
  16302. },
  16303. copy: function() {
  16304. var C = this.constructor, ret = new C(), loc = get(this, 'length');
  16305. set(ret, 'length', loc);
  16306. while(--loc>=0) {
  16307. ret[loc] = this[loc];
  16308. ret[guidFor(this[loc])] = loc;
  16309. }
  16310. return ret;
  16311. },
  16312. toString: function() {
  16313. var len = this.length, idx, array = [];
  16314. for(idx = 0; idx < len; idx++) {
  16315. array[idx] = this[idx];
  16316. }
  16317. return fmt("Ember.Set<%@>", [array.join(',')]);
  16318. }
  16319. });
  16320. })();
  16321. (function() {
  16322. var DeferredMixin = Ember.DeferredMixin, // mixins/deferred
  16323. get = Ember.get;
  16324. var Deferred = Ember.Object.extend(DeferredMixin);
  16325. Deferred.reopenClass({
  16326. promise: function(callback, binding) {
  16327. var deferred = Deferred.create();
  16328. callback.call(binding, deferred);
  16329. return deferred;
  16330. }
  16331. });
  16332. Ember.Deferred = Deferred;
  16333. })();
  16334. (function() {
  16335. var forEach = Ember.ArrayPolyfills.forEach;
  16336. /**
  16337. @module ember
  16338. @submodule ember-runtime
  16339. */
  16340. var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {};
  16341. var loaded = {};
  16342. /**
  16343. Detects when a specific package of Ember (e.g. 'Ember.Handlebars')
  16344. has fully loaded and is available for extension.
  16345. The provided `callback` will be called with the `name` passed
  16346. resolved from a string into the object:
  16347. ``` javascript
  16348. Ember.onLoad('Ember.Handlebars' function(hbars){
  16349. hbars.registerHelper(...);
  16350. });
  16351. ```
  16352. @method onLoad
  16353. @for Ember
  16354. @param name {String} name of hook
  16355. @param callback {Function} callback to be called
  16356. */
  16357. Ember.onLoad = function(name, callback) {
  16358. var object;
  16359. loadHooks[name] = loadHooks[name] || Ember.A();
  16360. loadHooks[name].pushObject(callback);
  16361. if (object = loaded[name]) {
  16362. callback(object);
  16363. }
  16364. };
  16365. /**
  16366. Called when an Ember.js package (e.g Ember.Handlebars) has finished
  16367. loading. Triggers any callbacks registered for this event.
  16368. @method runLoadHooks
  16369. @for Ember
  16370. @param name {String} name of hook
  16371. @param object {Object} object to pass to callbacks
  16372. */
  16373. Ember.runLoadHooks = function(name, object) {
  16374. loaded[name] = object;
  16375. if (loadHooks[name]) {
  16376. forEach.call(loadHooks[name], function(callback) {
  16377. callback(object);
  16378. });
  16379. }
  16380. };
  16381. })();
  16382. (function() {
  16383. })();
  16384. (function() {
  16385. var get = Ember.get;
  16386. /**
  16387. @module ember
  16388. @submodule ember-runtime
  16389. */
  16390. /**
  16391. `Ember.ControllerMixin` provides a standard interface for all classes that
  16392. compose Ember's controller layer: `Ember.Controller`,
  16393. `Ember.ArrayController`, and `Ember.ObjectController`.
  16394. @class ControllerMixin
  16395. @namespace Ember
  16396. @uses Ember.ActionHandler
  16397. */
  16398. Ember.ControllerMixin = Ember.Mixin.create(Ember.ActionHandler, {
  16399. /* ducktype as a controller */
  16400. isController: true,
  16401. /**
  16402. The object to which actions from the view should be sent.
  16403. For example, when a Handlebars template uses the `{{action}}` helper,
  16404. it will attempt to send the action to the view's controller's `target`.
  16405. By default, a controller's `target` is set to the router after it is
  16406. instantiated by `Ember.Application#initialize`.
  16407. @property target
  16408. @default null
  16409. */
  16410. target: null,
  16411. container: null,
  16412. parentController: null,
  16413. store: null,
  16414. model: Ember.computed.alias('content'),
  16415. deprecatedSendHandles: function(actionName) {
  16416. return !!this[actionName];
  16417. },
  16418. deprecatedSend: function(actionName) {
  16419. var args = [].slice.call(arguments, 1);
  16420. Ember.assert('' + this + " has the action " + actionName + " but it is not a function", typeof this[actionName] === 'function');
  16421. Ember.deprecate('Action handlers implemented directly on controllers are deprecated in favor of action handlers on an `actions` object ( action: `' + actionName + '` on ' + this + ')', false);
  16422. this[actionName].apply(this, args);
  16423. return;
  16424. }
  16425. });
  16426. /**
  16427. @class Controller
  16428. @namespace Ember
  16429. @extends Ember.Object
  16430. @uses Ember.ControllerMixin
  16431. */
  16432. Ember.Controller = Ember.Object.extend(Ember.ControllerMixin);
  16433. })();
  16434. (function() {
  16435. /**
  16436. @module ember
  16437. @submodule ember-runtime
  16438. */
  16439. var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach;
  16440. /**
  16441. `Ember.SortableMixin` provides a standard interface for array proxies
  16442. to specify a sort order and maintain this sorting when objects are added,
  16443. removed, or updated without changing the implicit order of their underlying
  16444. content array:
  16445. ```javascript
  16446. songs = [
  16447. {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'},
  16448. {trackNumber: 2, title: 'Back in the U.S.S.R.'},
  16449. {trackNumber: 3, title: 'Glass Onion'},
  16450. ];
  16451. songsController = Ember.ArrayController.create({
  16452. content: songs,
  16453. sortProperties: ['trackNumber'],
  16454. sortAscending: true
  16455. });
  16456. songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'}
  16457. songsController.addObject({trackNumber: 1, title: 'Dear Prudence'});
  16458. songsController.get('firstObject'); // {trackNumber: 1, title: 'Dear Prudence'}
  16459. ```
  16460. If you add or remove the properties to sort by or change the sort direction the content
  16461. sort order will be automatically updated.
  16462. ```javascript
  16463. songsController.set('sortProperties', ['title']);
  16464. songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'}
  16465. songsController.toggleProperty('sortAscending');
  16466. songsController.get('firstObject'); // {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'}
  16467. ```
  16468. SortableMixin works by sorting the arrangedContent array, which is the array that
  16469. arrayProxy displays. Due to the fact that the underlying 'content' array is not changed, that
  16470. array will not display the sorted list:
  16471. ```javascript
  16472. songsController.get('content').get('firstObject'); // Returns the unsorted original content
  16473. songsController.get('firstObject'); // Returns the sorted content.
  16474. ```
  16475. Although the sorted content can also be accessed through the arrangedContent property,
  16476. it is preferable to use the proxied class and not the arrangedContent array directly.
  16477. @class SortableMixin
  16478. @namespace Ember
  16479. @uses Ember.MutableEnumerable
  16480. */
  16481. Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
  16482. /**
  16483. Specifies which properties dictate the arrangedContent's sort order.
  16484. When specifying multiple properties the sorting will use properties
  16485. from the `sortProperties` array prioritized from first to last.
  16486. @property {Array} sortProperties
  16487. */
  16488. sortProperties: null,
  16489. /**
  16490. Specifies the arrangedContent's sort direction
  16491. @property {Boolean} sortAscending
  16492. */
  16493. sortAscending: true,
  16494. /**
  16495. The function used to compare two values. You can override this if you
  16496. want to do custom comparisons. Functions must be of the type expected by
  16497. Array#sort, i.e.
  16498. return 0 if the two parameters are equal,
  16499. return a negative value if the first parameter is smaller than the second or
  16500. return a positive value otherwise:
  16501. ```javascript
  16502. function(x,y) { // These are assumed to be integers
  16503. if (x === y)
  16504. return 0;
  16505. return x < y ? -1 : 1;
  16506. }
  16507. ```
  16508. @property sortFunction
  16509. @type {Function}
  16510. @default Ember.compare
  16511. */
  16512. sortFunction: Ember.compare,
  16513. orderBy: function(item1, item2) {
  16514. var result = 0,
  16515. sortProperties = get(this, 'sortProperties'),
  16516. sortAscending = get(this, 'sortAscending'),
  16517. sortFunction = get(this, 'sortFunction');
  16518. Ember.assert("you need to define `sortProperties`", !!sortProperties);
  16519. forEach(sortProperties, function(propertyName) {
  16520. if (result === 0) {
  16521. result = sortFunction(get(item1, propertyName), get(item2, propertyName));
  16522. if ((result !== 0) && !sortAscending) {
  16523. result = (-1) * result;
  16524. }
  16525. }
  16526. });
  16527. return result;
  16528. },
  16529. destroy: function() {
  16530. var content = get(this, 'content'),
  16531. sortProperties = get(this, 'sortProperties');
  16532. if (content && sortProperties) {
  16533. forEach(content, function(item) {
  16534. forEach(sortProperties, function(sortProperty) {
  16535. Ember.removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
  16536. }, this);
  16537. }, this);
  16538. }
  16539. return this._super();
  16540. },
  16541. isSorted: Ember.computed.bool('sortProperties'),
  16542. /**
  16543. Overrides the default arrangedContent from arrayProxy in order to sort by sortFunction.
  16544. Also sets up observers for each sortProperty on each item in the content Array.
  16545. @property arrangedContent
  16546. */
  16547. arrangedContent: Ember.computed('content', 'sortProperties.@each', function(key, value) {
  16548. var content = get(this, 'content'),
  16549. isSorted = get(this, 'isSorted'),
  16550. sortProperties = get(this, 'sortProperties'),
  16551. self = this;
  16552. if (content && isSorted) {
  16553. content = content.slice();
  16554. content.sort(function(item1, item2) {
  16555. return self.orderBy(item1, item2);
  16556. });
  16557. forEach(content, function(item) {
  16558. forEach(sortProperties, function(sortProperty) {
  16559. Ember.addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
  16560. }, this);
  16561. }, this);
  16562. return Ember.A(content);
  16563. }
  16564. return content;
  16565. }),
  16566. _contentWillChange: Ember.beforeObserver('content', function() {
  16567. var content = get(this, 'content'),
  16568. sortProperties = get(this, 'sortProperties');
  16569. if (content && sortProperties) {
  16570. forEach(content, function(item) {
  16571. forEach(sortProperties, function(sortProperty) {
  16572. Ember.removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
  16573. }, this);
  16574. }, this);
  16575. }
  16576. this._super();
  16577. }),
  16578. sortAscendingWillChange: Ember.beforeObserver('sortAscending', function() {
  16579. this._lastSortAscending = get(this, 'sortAscending');
  16580. }),
  16581. sortAscendingDidChange: Ember.observer('sortAscending', function() {
  16582. if (get(this, 'sortAscending') !== this._lastSortAscending) {
  16583. var arrangedContent = get(this, 'arrangedContent');
  16584. arrangedContent.reverseObjects();
  16585. }
  16586. }),
  16587. contentArrayWillChange: function(array, idx, removedCount, addedCount) {
  16588. var isSorted = get(this, 'isSorted');
  16589. if (isSorted) {
  16590. var arrangedContent = get(this, 'arrangedContent');
  16591. var removedObjects = array.slice(idx, idx+removedCount);
  16592. var sortProperties = get(this, 'sortProperties');
  16593. forEach(removedObjects, function(item) {
  16594. arrangedContent.removeObject(item);
  16595. forEach(sortProperties, function(sortProperty) {
  16596. Ember.removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
  16597. }, this);
  16598. }, this);
  16599. }
  16600. return this._super(array, idx, removedCount, addedCount);
  16601. },
  16602. contentArrayDidChange: function(array, idx, removedCount, addedCount) {
  16603. var isSorted = get(this, 'isSorted'),
  16604. sortProperties = get(this, 'sortProperties');
  16605. if (isSorted) {
  16606. var addedObjects = array.slice(idx, idx+addedCount);
  16607. forEach(addedObjects, function(item) {
  16608. this.insertItemSorted(item);
  16609. forEach(sortProperties, function(sortProperty) {
  16610. Ember.addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
  16611. }, this);
  16612. }, this);
  16613. }
  16614. return this._super(array, idx, removedCount, addedCount);
  16615. },
  16616. insertItemSorted: function(item) {
  16617. var arrangedContent = get(this, 'arrangedContent');
  16618. var length = get(arrangedContent, 'length');
  16619. var idx = this._binarySearch(item, 0, length);
  16620. arrangedContent.insertAt(idx, item);
  16621. },
  16622. contentItemSortPropertyDidChange: function(item) {
  16623. var arrangedContent = get(this, 'arrangedContent'),
  16624. oldIndex = arrangedContent.indexOf(item),
  16625. leftItem = arrangedContent.objectAt(oldIndex - 1),
  16626. rightItem = arrangedContent.objectAt(oldIndex + 1),
  16627. leftResult = leftItem && this.orderBy(item, leftItem),
  16628. rightResult = rightItem && this.orderBy(item, rightItem);
  16629. if (leftResult < 0 || rightResult > 0) {
  16630. arrangedContent.removeObject(item);
  16631. this.insertItemSorted(item);
  16632. }
  16633. },
  16634. _binarySearch: function(item, low, high) {
  16635. var mid, midItem, res, arrangedContent;
  16636. if (low === high) {
  16637. return low;
  16638. }
  16639. arrangedContent = get(this, 'arrangedContent');
  16640. mid = low + Math.floor((high - low) / 2);
  16641. midItem = arrangedContent.objectAt(mid);
  16642. res = this.orderBy(midItem, item);
  16643. if (res < 0) {
  16644. return this._binarySearch(item, mid+1, high);
  16645. } else if (res > 0) {
  16646. return this._binarySearch(item, low, mid);
  16647. }
  16648. return mid;
  16649. }
  16650. });
  16651. })();
  16652. (function() {
  16653. /**
  16654. @module ember
  16655. @submodule ember-runtime
  16656. */
  16657. var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach,
  16658. replace = Ember.EnumerableUtils.replace;
  16659. /**
  16660. `Ember.ArrayController` provides a way for you to publish a collection of
  16661. objects so that you can easily bind to the collection from a Handlebars
  16662. `#each` helper, an `Ember.CollectionView`, or other controllers.
  16663. The advantage of using an `ArrayController` is that you only have to set up
  16664. your view bindings once; to change what's displayed, simply swap out the
  16665. `content` property on the controller.
  16666. For example, imagine you wanted to display a list of items fetched via an XHR
  16667. request. Create an `Ember.ArrayController` and set its `content` property:
  16668. ```javascript
  16669. MyApp.listController = Ember.ArrayController.create();
  16670. $.get('people.json', function(data) {
  16671. MyApp.listController.set('content', data);
  16672. });
  16673. ```
  16674. Then, create a view that binds to your new controller:
  16675. ```handlebars
  16676. {{#each MyApp.listController}}
  16677. {{firstName}} {{lastName}}
  16678. {{/each}}
  16679. ```
  16680. Although you are binding to the controller, the behavior of this controller
  16681. is to pass through any methods or properties to the underlying array. This
  16682. capability comes from `Ember.ArrayProxy`, which this class inherits from.
  16683. Sometimes you want to display computed properties within the body of an
  16684. `#each` helper that depend on the underlying items in `content`, but are not
  16685. present on those items. To do this, set `itemController` to the name of a
  16686. controller (probably an `ObjectController`) that will wrap each individual item.
  16687. For example:
  16688. ```handlebars
  16689. {{#each post in controller}}
  16690. <li>{{title}} ({{titleLength}} characters)</li>
  16691. {{/each}}
  16692. ```
  16693. ```javascript
  16694. App.PostsController = Ember.ArrayController.extend({
  16695. itemController: 'post'
  16696. });
  16697. App.PostController = Ember.ObjectController.extend({
  16698. // the `title` property will be proxied to the underlying post.
  16699. titleLength: function() {
  16700. return this.get('title').length;
  16701. }.property('title')
  16702. });
  16703. ```
  16704. In some cases it is helpful to return a different `itemController` depending
  16705. on the particular item. Subclasses can do this by overriding
  16706. `lookupItemController`.
  16707. For example:
  16708. ```javascript
  16709. App.MyArrayController = Ember.ArrayController.extend({
  16710. lookupItemController: function( object ) {
  16711. if (object.get('isSpecial')) {
  16712. return "special"; // use App.SpecialController
  16713. } else {
  16714. return "regular"; // use App.RegularController
  16715. }
  16716. }
  16717. });
  16718. ```
  16719. The itemController instances will have a `parentController` property set to
  16720. the `ArrayController` instance.
  16721. @class ArrayController
  16722. @namespace Ember
  16723. @extends Ember.ArrayProxy
  16724. @uses Ember.SortableMixin
  16725. @uses Ember.ControllerMixin
  16726. */
  16727. Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
  16728. Ember.SortableMixin, {
  16729. /**
  16730. The controller used to wrap items, if any.
  16731. @property itemController
  16732. @type String
  16733. @default null
  16734. */
  16735. itemController: null,
  16736. /**
  16737. Return the name of the controller to wrap items, or `null` if items should
  16738. be returned directly. The default implementation simply returns the
  16739. `itemController` property, but subclasses can override this method to return
  16740. different controllers for different objects.
  16741. For example:
  16742. ```javascript
  16743. App.MyArrayController = Ember.ArrayController.extend({
  16744. lookupItemController: function( object ) {
  16745. if (object.get('isSpecial')) {
  16746. return "special"; // use App.SpecialController
  16747. } else {
  16748. return "regular"; // use App.RegularController
  16749. }
  16750. }
  16751. });
  16752. ```
  16753. @method lookupItemController
  16754. @param {Object} object
  16755. @return {String}
  16756. */
  16757. lookupItemController: function(object) {
  16758. return get(this, 'itemController');
  16759. },
  16760. objectAtContent: function(idx) {
  16761. var length = get(this, 'length'),
  16762. arrangedContent = get(this,'arrangedContent'),
  16763. object = arrangedContent && arrangedContent.objectAt(idx);
  16764. if (idx >= 0 && idx < length) {
  16765. var controllerClass = this.lookupItemController(object);
  16766. if (controllerClass) {
  16767. return this.controllerAt(idx, object, controllerClass);
  16768. }
  16769. }
  16770. // When `controllerClass` is falsy, we have not opted in to using item
  16771. // controllers, so return the object directly.
  16772. // When the index is out of range, we want to return the "out of range"
  16773. // value, whatever that might be. Rather than make assumptions
  16774. // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`.
  16775. return object;
  16776. },
  16777. arrangedContentDidChange: function() {
  16778. this._super();
  16779. this._resetSubControllers();
  16780. },
  16781. arrayContentDidChange: function(idx, removedCnt, addedCnt) {
  16782. var subControllers = get(this, '_subControllers'),
  16783. subControllersToRemove = subControllers.slice(idx, idx+removedCnt);
  16784. forEach(subControllersToRemove, function(subController) {
  16785. if (subController) { subController.destroy(); }
  16786. });
  16787. replace(subControllers, idx, removedCnt, new Array(addedCnt));
  16788. // The shadow array of subcontrollers must be updated before we trigger
  16789. // observers, otherwise observers will get the wrong subcontainer when
  16790. // calling `objectAt`
  16791. this._super(idx, removedCnt, addedCnt);
  16792. },
  16793. init: function() {
  16794. this._super();
  16795. this.set('_subControllers', Ember.A());
  16796. },
  16797. content: Ember.computed(function () {
  16798. return Ember.A();
  16799. }),
  16800. /**
  16801. * Flag to mark as being "virtual". Used to keep this instance
  16802. * from participating in the parentController hierarchy.
  16803. *
  16804. * @private
  16805. * @type Boolean
  16806. */
  16807. _isVirtual: false,
  16808. controllerAt: function(idx, object, controllerClass) {
  16809. var container = get(this, 'container'),
  16810. subControllers = get(this, '_subControllers'),
  16811. subController = subControllers[idx],
  16812. factory, fullName;
  16813. if (subController) { return subController; }
  16814. fullName = "controller:" + controllerClass;
  16815. if (!container.has(fullName)) {
  16816. throw new Ember.Error('Could not resolve itemController: "' + controllerClass + '"');
  16817. }
  16818. var parentController;
  16819. if (this._isVirtual) {
  16820. parentController = get(this, 'parentController');
  16821. }
  16822. parentController = parentController || this;
  16823. subController = container.lookupFactory(fullName).create({
  16824. target: this,
  16825. parentController: parentController,
  16826. content: object
  16827. });
  16828. subControllers[idx] = subController;
  16829. return subController;
  16830. },
  16831. _subControllers: null,
  16832. _resetSubControllers: function() {
  16833. var subControllers = get(this, '_subControllers');
  16834. if (subControllers) {
  16835. forEach(subControllers, function(subController) {
  16836. if (subController) { subController.destroy(); }
  16837. });
  16838. }
  16839. this.set('_subControllers', Ember.A());
  16840. }
  16841. });
  16842. })();
  16843. (function() {
  16844. /**
  16845. @module ember
  16846. @submodule ember-runtime
  16847. */
  16848. /**
  16849. `Ember.ObjectController` is part of Ember's Controller layer. It is intended
  16850. to wrap a single object, proxying unhandled attempts to `get` and `set` to the underlying
  16851. content object, and to forward unhandled action attempts to its `target`.
  16852. `Ember.ObjectController` derives this functionality from its superclass
  16853. `Ember.ObjectProxy` and the `Ember.ControllerMixin` mixin.
  16854. @class ObjectController
  16855. @namespace Ember
  16856. @extends Ember.ObjectProxy
  16857. @uses Ember.ControllerMixin
  16858. **/
  16859. Ember.ObjectController = Ember.ObjectProxy.extend(Ember.ControllerMixin);
  16860. })();
  16861. (function() {
  16862. })();
  16863. (function() {
  16864. /**
  16865. Ember Runtime
  16866. @module ember
  16867. @submodule ember-runtime
  16868. @requires ember-metal
  16869. */
  16870. })();
  16871. (function() {
  16872. /**
  16873. @module ember
  16874. @submodule ember-views
  16875. */
  16876. var jQuery = (this && this.jQuery) || (Ember.imports && Ember.imports.jQuery);
  16877. if (!jQuery && typeof require === 'function') {
  16878. jQuery = require('jquery');
  16879. }
  16880. Ember.assert("Ember Views require jQuery between 1.7 and 2.1", jQuery && (jQuery().jquery.match(/^((1\.(7|8|9|10|11))|(2\.(0|1)))(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY));
  16881. /**
  16882. Alias for jQuery
  16883. @method $
  16884. @for Ember
  16885. */
  16886. Ember.$ = jQuery;
  16887. })();
  16888. (function() {
  16889. /**
  16890. @module ember
  16891. @submodule ember-views
  16892. */
  16893. if (Ember.$) {
  16894. // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents
  16895. var dragEvents = Ember.String.w('dragstart drag dragenter dragleave dragover drop dragend');
  16896. // Copies the `dataTransfer` property from a browser event object onto the
  16897. // jQuery event object for the specified events
  16898. Ember.EnumerableUtils.forEach(dragEvents, function(eventName) {
  16899. Ember.$.event.fixHooks[eventName] = { props: ['dataTransfer'] };
  16900. });
  16901. }
  16902. })();
  16903. (function() {
  16904. /**
  16905. @module ember
  16906. @submodule ember-views
  16907. */
  16908. /* BEGIN METAMORPH HELPERS */
  16909. // Internet Explorer prior to 9 does not allow setting innerHTML if the first element
  16910. // is a "zero-scope" element. This problem can be worked around by making
  16911. // the first node an invisible text node. We, like Modernizr, use &shy;
  16912. var needsShy = typeof document !== 'undefined' && (function() {
  16913. var testEl = document.createElement('div');
  16914. testEl.innerHTML = "<div></div>";
  16915. testEl.firstChild.innerHTML = "<script></script>";
  16916. return testEl.firstChild.innerHTML === '';
  16917. })();
  16918. // IE 8 (and likely earlier) likes to move whitespace preceeding
  16919. // a script tag to appear after it. This means that we can
  16920. // accidentally remove whitespace when updating a morph.
  16921. var movesWhitespace = typeof document !== 'undefined' && (function() {
  16922. var testEl = document.createElement('div');
  16923. testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value";
  16924. return testEl.childNodes[0].nodeValue === 'Test:' &&
  16925. testEl.childNodes[2].nodeValue === ' Value';
  16926. })();
  16927. // Use this to find children by ID instead of using jQuery
  16928. var findChildById = function(element, id) {
  16929. if (element.getAttribute('id') === id) { return element; }
  16930. var len = element.childNodes.length, idx, node, found;
  16931. for (idx=0; idx<len; idx++) {
  16932. node = element.childNodes[idx];
  16933. found = node.nodeType === 1 && findChildById(node, id);
  16934. if (found) { return found; }
  16935. }
  16936. };
  16937. var setInnerHTMLWithoutFix = function(element, html) {
  16938. if (needsShy) {
  16939. html = '&shy;' + html;
  16940. }
  16941. var matches = [];
  16942. if (movesWhitespace) {
  16943. // Right now we only check for script tags with ids with the
  16944. // goal of targeting morphs.
  16945. html = html.replace(/(\s+)(<script id='([^']+)')/g, function(match, spaces, tag, id) {
  16946. matches.push([id, spaces]);
  16947. return tag;
  16948. });
  16949. }
  16950. element.innerHTML = html;
  16951. // If we have to do any whitespace adjustments do them now
  16952. if (matches.length > 0) {
  16953. var len = matches.length, idx;
  16954. for (idx=0; idx<len; idx++) {
  16955. var script = findChildById(element, matches[idx][0]),
  16956. node = document.createTextNode(matches[idx][1]);
  16957. script.parentNode.insertBefore(node, script);
  16958. }
  16959. }
  16960. if (needsShy) {
  16961. var shyElement = element.firstChild;
  16962. while (shyElement.nodeType === 1 && !shyElement.nodeName) {
  16963. shyElement = shyElement.firstChild;
  16964. }
  16965. if (shyElement.nodeType === 3 && shyElement.nodeValue.charAt(0) === "\u00AD") {
  16966. shyElement.nodeValue = shyElement.nodeValue.slice(1);
  16967. }
  16968. }
  16969. };
  16970. /* END METAMORPH HELPERS */
  16971. var innerHTMLTags = {};
  16972. var canSetInnerHTML = function(tagName) {
  16973. if (innerHTMLTags[tagName] !== undefined) {
  16974. return innerHTMLTags[tagName];
  16975. }
  16976. var canSet = true;
  16977. // IE 8 and earlier don't allow us to do innerHTML on select
  16978. if (tagName.toLowerCase() === 'select') {
  16979. var el = document.createElement('select');
  16980. setInnerHTMLWithoutFix(el, '<option value="test">Test</option>');
  16981. canSet = el.options.length === 1;
  16982. }
  16983. innerHTMLTags[tagName] = canSet;
  16984. return canSet;
  16985. };
  16986. var setInnerHTML = function(element, html) {
  16987. var tagName = element.tagName;
  16988. if (canSetInnerHTML(tagName)) {
  16989. setInnerHTMLWithoutFix(element, html);
  16990. } else {
  16991. // Firefox versions < 11 do not have support for element.outerHTML.
  16992. var outerHTML = element.outerHTML || new XMLSerializer().serializeToString(element);
  16993. Ember.assert("Can't set innerHTML on "+element.tagName+" in this browser", outerHTML);
  16994. var startTag = outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0],
  16995. endTag = '</'+tagName+'>';
  16996. var wrapper = document.createElement('div');
  16997. setInnerHTMLWithoutFix(wrapper, startTag + html + endTag);
  16998. element = wrapper.firstChild;
  16999. while (element.tagName !== tagName) {
  17000. element = element.nextSibling;
  17001. }
  17002. }
  17003. return element;
  17004. };
  17005. function isSimpleClick(event) {
  17006. var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey,
  17007. secondaryClick = event.which > 1; // IE9 may return undefined
  17008. return !modifier && !secondaryClick;
  17009. }
  17010. Ember.ViewUtils = {
  17011. setInnerHTML: setInnerHTML,
  17012. isSimpleClick: isSimpleClick
  17013. };
  17014. })();
  17015. (function() {
  17016. /**
  17017. @module ember
  17018. @submodule ember-views
  17019. */
  17020. var get = Ember.get, set = Ember.set;
  17021. var ClassSet = function() {
  17022. this.seen = {};
  17023. this.list = [];
  17024. };
  17025. ClassSet.prototype = {
  17026. add: function(string) {
  17027. if (string in this.seen) { return; }
  17028. this.seen[string] = true;
  17029. this.list.push(string);
  17030. },
  17031. toDOM: function() {
  17032. return this.list.join(" ");
  17033. }
  17034. };
  17035. var BAD_TAG_NAME_TEST_REGEXP = /[^a-zA-Z0-9\-]/;
  17036. var BAD_TAG_NAME_REPLACE_REGEXP = /[^a-zA-Z0-9\-]/g;
  17037. function stripTagName(tagName) {
  17038. if (!tagName) {
  17039. return tagName;
  17040. }
  17041. if (!BAD_TAG_NAME_TEST_REGEXP.test(tagName)) {
  17042. return tagName;
  17043. }
  17044. return tagName.replace(BAD_TAG_NAME_REPLACE_REGEXP, '');
  17045. }
  17046. var BAD_CHARS_REGEXP = /&(?!\w+;)|[<>"'`]/g;
  17047. var POSSIBLE_CHARS_REGEXP = /[&<>"'`]/;
  17048. function escapeAttribute(value) {
  17049. // Stolen shamelessly from Handlebars
  17050. var escape = {
  17051. "<": "&lt;",
  17052. ">": "&gt;",
  17053. '"': "&quot;",
  17054. "'": "&#x27;",
  17055. "`": "&#x60;"
  17056. };
  17057. var escapeChar = function(chr) {
  17058. return escape[chr] || "&amp;";
  17059. };
  17060. var string = value.toString();
  17061. if(!POSSIBLE_CHARS_REGEXP.test(string)) { return string; }
  17062. return string.replace(BAD_CHARS_REGEXP, escapeChar);
  17063. }
  17064. // IE 6/7 have bugs around setting names on inputs during creation.
  17065. // From http://msdn.microsoft.com/en-us/library/ie/ms536389(v=vs.85).aspx:
  17066. // "To include the NAME attribute at run time on objects created with the createElement method, use the eTag."
  17067. var canSetNameOnInputs = (function() {
  17068. var div = document.createElement('div'),
  17069. el = document.createElement('input');
  17070. el.setAttribute('name', 'foo');
  17071. div.appendChild(el);
  17072. return !!div.innerHTML.match('foo');
  17073. })();
  17074. /**
  17075. `Ember.RenderBuffer` gathers information regarding the a view and generates the
  17076. final representation. `Ember.RenderBuffer` will generate HTML which can be pushed
  17077. to the DOM.
  17078. ```javascript
  17079. var buffer = Ember.RenderBuffer('div');
  17080. ```
  17081. @class RenderBuffer
  17082. @namespace Ember
  17083. @constructor
  17084. @param {String} tagName tag name (such as 'div' or 'p') used for the buffer
  17085. */
  17086. Ember.RenderBuffer = function(tagName) {
  17087. return new Ember._RenderBuffer(tagName);
  17088. };
  17089. Ember._RenderBuffer = function(tagName) {
  17090. this.tagNames = [tagName || null];
  17091. this.buffer = "";
  17092. };
  17093. Ember._RenderBuffer.prototype = {
  17094. // The root view's element
  17095. _element: null,
  17096. _hasElement: true,
  17097. /**
  17098. An internal set used to de-dupe class names when `addClass()` is
  17099. used. After each call to `addClass()`, the `classes` property
  17100. will be updated.
  17101. @private
  17102. @property elementClasses
  17103. @type Array
  17104. @default []
  17105. */
  17106. elementClasses: null,
  17107. /**
  17108. Array of class names which will be applied in the class attribute.
  17109. You can use `setClasses()` to set this property directly. If you
  17110. use `addClass()`, it will be maintained for you.
  17111. @property classes
  17112. @type Array
  17113. @default []
  17114. */
  17115. classes: null,
  17116. /**
  17117. The id in of the element, to be applied in the id attribute.
  17118. You should not set this property yourself, rather, you should use
  17119. the `id()` method of `Ember.RenderBuffer`.
  17120. @property elementId
  17121. @type String
  17122. @default null
  17123. */
  17124. elementId: null,
  17125. /**
  17126. A hash keyed on the name of the attribute and whose value will be
  17127. applied to that attribute. For example, if you wanted to apply a
  17128. `data-view="Foo.bar"` property to an element, you would set the
  17129. elementAttributes hash to `{'data-view':'Foo.bar'}`.
  17130. You should not maintain this hash yourself, rather, you should use
  17131. the `attr()` method of `Ember.RenderBuffer`.
  17132. @property elementAttributes
  17133. @type Hash
  17134. @default {}
  17135. */
  17136. elementAttributes: null,
  17137. /**
  17138. A hash keyed on the name of the properties and whose value will be
  17139. applied to that property. For example, if you wanted to apply a
  17140. `checked=true` property to an element, you would set the
  17141. elementProperties hash to `{'checked':true}`.
  17142. You should not maintain this hash yourself, rather, you should use
  17143. the `prop()` method of `Ember.RenderBuffer`.
  17144. @property elementProperties
  17145. @type Hash
  17146. @default {}
  17147. */
  17148. elementProperties: null,
  17149. /**
  17150. The tagname of the element an instance of `Ember.RenderBuffer` represents.
  17151. Usually, this gets set as the first parameter to `Ember.RenderBuffer`. For
  17152. example, if you wanted to create a `p` tag, then you would call
  17153. ```javascript
  17154. Ember.RenderBuffer('p')
  17155. ```
  17156. @property elementTag
  17157. @type String
  17158. @default null
  17159. */
  17160. elementTag: null,
  17161. /**
  17162. A hash keyed on the name of the style attribute and whose value will
  17163. be applied to that attribute. For example, if you wanted to apply a
  17164. `background-color:black;` style to an element, you would set the
  17165. elementStyle hash to `{'background-color':'black'}`.
  17166. You should not maintain this hash yourself, rather, you should use
  17167. the `style()` method of `Ember.RenderBuffer`.
  17168. @property elementStyle
  17169. @type Hash
  17170. @default {}
  17171. */
  17172. elementStyle: null,
  17173. /**
  17174. Nested `RenderBuffers` will set this to their parent `RenderBuffer`
  17175. instance.
  17176. @property parentBuffer
  17177. @type Ember._RenderBuffer
  17178. */
  17179. parentBuffer: null,
  17180. /**
  17181. Adds a string of HTML to the `RenderBuffer`.
  17182. @method push
  17183. @param {String} string HTML to push into the buffer
  17184. @chainable
  17185. */
  17186. push: function(string) {
  17187. this.buffer += string;
  17188. return this;
  17189. },
  17190. /**
  17191. Adds a class to the buffer, which will be rendered to the class attribute.
  17192. @method addClass
  17193. @param {String} className Class name to add to the buffer
  17194. @chainable
  17195. */
  17196. addClass: function(className) {
  17197. // lazily create elementClasses
  17198. this.elementClasses = (this.elementClasses || new ClassSet());
  17199. this.elementClasses.add(className);
  17200. this.classes = this.elementClasses.list;
  17201. return this;
  17202. },
  17203. setClasses: function(classNames) {
  17204. this.elementClasses = null;
  17205. var len = classNames.length, i;
  17206. for (i = 0; i < len; i++) {
  17207. this.addClass(classNames[i]);
  17208. }
  17209. },
  17210. /**
  17211. Sets the elementID to be used for the element.
  17212. @method id
  17213. @param {String} id
  17214. @chainable
  17215. */
  17216. id: function(id) {
  17217. this.elementId = id;
  17218. return this;
  17219. },
  17220. // duck type attribute functionality like jQuery so a render buffer
  17221. // can be used like a jQuery object in attribute binding scenarios.
  17222. /**
  17223. Adds an attribute which will be rendered to the element.
  17224. @method attr
  17225. @param {String} name The name of the attribute
  17226. @param {String} value The value to add to the attribute
  17227. @chainable
  17228. @return {Ember.RenderBuffer|String} this or the current attribute value
  17229. */
  17230. attr: function(name, value) {
  17231. var attributes = this.elementAttributes = (this.elementAttributes || {});
  17232. if (arguments.length === 1) {
  17233. return attributes[name];
  17234. } else {
  17235. attributes[name] = value;
  17236. }
  17237. return this;
  17238. },
  17239. /**
  17240. Remove an attribute from the list of attributes to render.
  17241. @method removeAttr
  17242. @param {String} name The name of the attribute
  17243. @chainable
  17244. */
  17245. removeAttr: function(name) {
  17246. var attributes = this.elementAttributes;
  17247. if (attributes) { delete attributes[name]; }
  17248. return this;
  17249. },
  17250. /**
  17251. Adds a property which will be rendered to the element.
  17252. @method prop
  17253. @param {String} name The name of the property
  17254. @param {String} value The value to add to the property
  17255. @chainable
  17256. @return {Ember.RenderBuffer|String} this or the current property value
  17257. */
  17258. prop: function(name, value) {
  17259. var properties = this.elementProperties = (this.elementProperties || {});
  17260. if (arguments.length === 1) {
  17261. return properties[name];
  17262. } else {
  17263. properties[name] = value;
  17264. }
  17265. return this;
  17266. },
  17267. /**
  17268. Remove an property from the list of properties to render.
  17269. @method removeProp
  17270. @param {String} name The name of the property
  17271. @chainable
  17272. */
  17273. removeProp: function(name) {
  17274. var properties = this.elementProperties;
  17275. if (properties) { delete properties[name]; }
  17276. return this;
  17277. },
  17278. /**
  17279. Adds a style to the style attribute which will be rendered to the element.
  17280. @method style
  17281. @param {String} name Name of the style
  17282. @param {String} value
  17283. @chainable
  17284. */
  17285. style: function(name, value) {
  17286. this.elementStyle = (this.elementStyle || {});
  17287. this.elementStyle[name] = value;
  17288. return this;
  17289. },
  17290. begin: function(tagName) {
  17291. this.tagNames.push(tagName || null);
  17292. return this;
  17293. },
  17294. pushOpeningTag: function() {
  17295. var tagName = this.currentTagName();
  17296. if (!tagName) { return; }
  17297. if (this._hasElement && !this._element && this.buffer.length === 0) {
  17298. this._element = this.generateElement();
  17299. return;
  17300. }
  17301. var buffer = this.buffer,
  17302. id = this.elementId,
  17303. classes = this.classes,
  17304. attrs = this.elementAttributes,
  17305. props = this.elementProperties,
  17306. style = this.elementStyle,
  17307. attr, prop;
  17308. buffer += '<' + stripTagName(tagName);
  17309. if (id) {
  17310. buffer += ' id="' + escapeAttribute(id) + '"';
  17311. this.elementId = null;
  17312. }
  17313. if (classes) {
  17314. buffer += ' class="' + escapeAttribute(classes.join(' ')) + '"';
  17315. this.classes = null;
  17316. this.elementClasses = null;
  17317. }
  17318. if (style) {
  17319. buffer += ' style="';
  17320. for (prop in style) {
  17321. if (style.hasOwnProperty(prop)) {
  17322. buffer += prop + ':' + escapeAttribute(style[prop]) + ';';
  17323. }
  17324. }
  17325. buffer += '"';
  17326. this.elementStyle = null;
  17327. }
  17328. if (attrs) {
  17329. for (attr in attrs) {
  17330. if (attrs.hasOwnProperty(attr)) {
  17331. buffer += ' ' + attr + '="' + escapeAttribute(attrs[attr]) + '"';
  17332. }
  17333. }
  17334. this.elementAttributes = null;
  17335. }
  17336. if (props) {
  17337. for (prop in props) {
  17338. if (props.hasOwnProperty(prop)) {
  17339. var value = props[prop];
  17340. if (value || typeof(value) === 'number') {
  17341. if (value === true) {
  17342. buffer += ' ' + prop + '="' + prop + '"';
  17343. } else {
  17344. buffer += ' ' + prop + '="' + escapeAttribute(props[prop]) + '"';
  17345. }
  17346. }
  17347. }
  17348. }
  17349. this.elementProperties = null;
  17350. }
  17351. buffer += '>';
  17352. this.buffer = buffer;
  17353. },
  17354. pushClosingTag: function() {
  17355. var tagName = this.tagNames.pop();
  17356. if (tagName) { this.buffer += '</' + stripTagName(tagName) + '>'; }
  17357. },
  17358. currentTagName: function() {
  17359. return this.tagNames[this.tagNames.length-1];
  17360. },
  17361. generateElement: function() {
  17362. var tagName = this.tagNames.pop(), // pop since we don't need to close
  17363. id = this.elementId,
  17364. classes = this.classes,
  17365. attrs = this.elementAttributes,
  17366. props = this.elementProperties,
  17367. style = this.elementStyle,
  17368. styleBuffer = '', attr, prop, tagString;
  17369. if (attrs && attrs.name && !canSetNameOnInputs) {
  17370. // IE allows passing a tag to createElement. See note on `canSetNameOnInputs` above as well.
  17371. tagString = '<'+stripTagName(tagName)+' name="'+escapeAttribute(attrs.name)+'">';
  17372. } else {
  17373. tagString = tagName;
  17374. }
  17375. var element = document.createElement(tagString),
  17376. $element = Ember.$(element);
  17377. if (id) {
  17378. $element.attr('id', id);
  17379. this.elementId = null;
  17380. }
  17381. if (classes) {
  17382. $element.attr('class', classes.join(' '));
  17383. this.classes = null;
  17384. this.elementClasses = null;
  17385. }
  17386. if (style) {
  17387. for (prop in style) {
  17388. if (style.hasOwnProperty(prop)) {
  17389. styleBuffer += (prop + ':' + style[prop] + ';');
  17390. }
  17391. }
  17392. $element.attr('style', styleBuffer);
  17393. this.elementStyle = null;
  17394. }
  17395. if (attrs) {
  17396. for (attr in attrs) {
  17397. if (attrs.hasOwnProperty(attr)) {
  17398. $element.attr(attr, attrs[attr]);
  17399. }
  17400. }
  17401. this.elementAttributes = null;
  17402. }
  17403. if (props) {
  17404. for (prop in props) {
  17405. if (props.hasOwnProperty(prop)) {
  17406. $element.prop(prop, props[prop]);
  17407. }
  17408. }
  17409. this.elementProperties = null;
  17410. }
  17411. return element;
  17412. },
  17413. /**
  17414. @method element
  17415. @return {DOMElement} The element corresponding to the generated HTML
  17416. of this buffer
  17417. */
  17418. element: function() {
  17419. var html = this.innerString();
  17420. if (html) {
  17421. this._element = Ember.ViewUtils.setInnerHTML(this._element, html);
  17422. }
  17423. return this._element;
  17424. },
  17425. /**
  17426. Generates the HTML content for this buffer.
  17427. @method string
  17428. @return {String} The generated HTML
  17429. */
  17430. string: function() {
  17431. if (this._hasElement && this._element) {
  17432. // Firefox versions < 11 do not have support for element.outerHTML.
  17433. var thisElement = this.element(), outerHTML = thisElement.outerHTML;
  17434. if (typeof outerHTML === 'undefined') {
  17435. return Ember.$('<div/>').append(thisElement).html();
  17436. }
  17437. return outerHTML;
  17438. } else {
  17439. return this.innerString();
  17440. }
  17441. },
  17442. innerString: function() {
  17443. return this.buffer;
  17444. }
  17445. };
  17446. })();
  17447. (function() {
  17448. /**
  17449. @module ember
  17450. @submodule ember-views
  17451. */
  17452. var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
  17453. /**
  17454. `Ember.EventDispatcher` handles delegating browser events to their
  17455. corresponding `Ember.Views.` For example, when you click on a view,
  17456. `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets
  17457. called.
  17458. @class EventDispatcher
  17459. @namespace Ember
  17460. @private
  17461. @extends Ember.Object
  17462. */
  17463. Ember.EventDispatcher = Ember.Object.extend({
  17464. /**
  17465. The set of events names (and associated handler function names) to be setup
  17466. and dispatched by the `EventDispatcher`. Custom events can added to this list at setup
  17467. time, generally via the `Ember.Application.customEvents` hash. Only override this
  17468. default set to prevent the EventDispatcher from listening on some events all together.
  17469. This set will be modified by `setup` to also include any events added at that time.
  17470. @property events
  17471. @type Object
  17472. */
  17473. events: {
  17474. touchstart : 'touchStart',
  17475. touchmove : 'touchMove',
  17476. touchend : 'touchEnd',
  17477. touchcancel : 'touchCancel',
  17478. keydown : 'keyDown',
  17479. keyup : 'keyUp',
  17480. keypress : 'keyPress',
  17481. mousedown : 'mouseDown',
  17482. mouseup : 'mouseUp',
  17483. contextmenu : 'contextMenu',
  17484. click : 'click',
  17485. dblclick : 'doubleClick',
  17486. mousemove : 'mouseMove',
  17487. focusin : 'focusIn',
  17488. focusout : 'focusOut',
  17489. mouseenter : 'mouseEnter',
  17490. mouseleave : 'mouseLeave',
  17491. submit : 'submit',
  17492. input : 'input',
  17493. change : 'change',
  17494. dragstart : 'dragStart',
  17495. drag : 'drag',
  17496. dragenter : 'dragEnter',
  17497. dragleave : 'dragLeave',
  17498. dragover : 'dragOver',
  17499. drop : 'drop',
  17500. dragend : 'dragEnd'
  17501. },
  17502. /**
  17503. The root DOM element to which event listeners should be attached. Event
  17504. listeners will be attached to the document unless this is overridden.
  17505. Can be specified as a DOMElement or a selector string.
  17506. The default body is a string since this may be evaluated before document.body
  17507. exists in the DOM.
  17508. @private
  17509. @property rootElement
  17510. @type DOMElement
  17511. @default 'body'
  17512. */
  17513. rootElement: 'body',
  17514. /**
  17515. Sets up event listeners for standard browser events.
  17516. This will be called after the browser sends a `DOMContentReady` event. By
  17517. default, it will set up all of the listeners on the document body. If you
  17518. would like to register the listeners on a different element, set the event
  17519. dispatcher's `root` property.
  17520. @private
  17521. @method setup
  17522. @param addedEvents {Hash}
  17523. */
  17524. setup: function(addedEvents, rootElement) {
  17525. var event, events = get(this, 'events');
  17526. Ember.$.extend(events, addedEvents || {});
  17527. if (!Ember.isNone(rootElement)) {
  17528. set(this, 'rootElement', rootElement);
  17529. }
  17530. rootElement = Ember.$(get(this, 'rootElement'));
  17531. 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'));
  17532. 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);
  17533. 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);
  17534. rootElement.addClass('ember-application');
  17535. 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'));
  17536. for (event in events) {
  17537. if (events.hasOwnProperty(event)) {
  17538. this.setupHandler(rootElement, event, events[event]);
  17539. }
  17540. }
  17541. },
  17542. /**
  17543. Registers an event listener on the document. If the given event is
  17544. triggered, the provided event handler will be triggered on the target view.
  17545. If the target view does not implement the event handler, or if the handler
  17546. returns `false`, the parent view will be called. The event will continue to
  17547. bubble to each successive parent view until it reaches the top.
  17548. For example, to have the `mouseDown` method called on the target view when
  17549. a `mousedown` event is received from the browser, do the following:
  17550. ```javascript
  17551. setupHandler('mousedown', 'mouseDown');
  17552. ```
  17553. @private
  17554. @method setupHandler
  17555. @param {Element} rootElement
  17556. @param {String} event the browser-originated event to listen to
  17557. @param {String} eventName the name of the method to call on the view
  17558. */
  17559. setupHandler: function(rootElement, event, eventName) {
  17560. var self = this;
  17561. rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) {
  17562. return Ember.handleErrors(function handleViewEvent() {
  17563. var view = Ember.View.views[this.id],
  17564. result = true, manager = null;
  17565. manager = self._findNearestEventManager(view,eventName);
  17566. if (manager && manager !== triggeringManager) {
  17567. result = self._dispatchEvent(manager, evt, eventName, view);
  17568. } else if (view) {
  17569. result = self._bubbleEvent(view,evt,eventName);
  17570. } else {
  17571. evt.stopPropagation();
  17572. }
  17573. return result;
  17574. }, this);
  17575. });
  17576. rootElement.on(event + '.ember', '[data-ember-action]', function(evt) {
  17577. return Ember.handleErrors(function handleActionEvent() {
  17578. var actionId = Ember.$(evt.currentTarget).attr('data-ember-action'),
  17579. action = Ember.Handlebars.ActionHelper.registeredActions[actionId];
  17580. // We have to check for action here since in some cases, jQuery will trigger
  17581. // an event on `removeChild` (i.e. focusout) after we've already torn down the
  17582. // action handlers for the view.
  17583. if (action && action.eventName === eventName) {
  17584. return action.handler(evt);
  17585. }
  17586. }, this);
  17587. });
  17588. },
  17589. _findNearestEventManager: function(view, eventName) {
  17590. var manager = null;
  17591. while (view) {
  17592. manager = get(view, 'eventManager');
  17593. if (manager && manager[eventName]) { break; }
  17594. view = get(view, 'parentView');
  17595. }
  17596. return manager;
  17597. },
  17598. _dispatchEvent: function(object, evt, eventName, view) {
  17599. var result = true;
  17600. var handler = object[eventName];
  17601. if (Ember.typeOf(handler) === 'function') {
  17602. result = Ember.run(function() {
  17603. return handler.call(object, evt, view);
  17604. });
  17605. // Do not preventDefault in eventManagers.
  17606. evt.stopPropagation();
  17607. }
  17608. else {
  17609. result = this._bubbleEvent(view, evt, eventName);
  17610. }
  17611. return result;
  17612. },
  17613. _bubbleEvent: function(view, evt, eventName) {
  17614. return Ember.run(function bubbleEvent() {
  17615. return view.handleEvent(eventName, evt);
  17616. });
  17617. },
  17618. destroy: function() {
  17619. var rootElement = get(this, 'rootElement');
  17620. Ember.$(rootElement).off('.ember', '**').removeClass('ember-application');
  17621. return this._super();
  17622. }
  17623. });
  17624. })();
  17625. (function() {
  17626. /**
  17627. @module ember
  17628. @submodule ember-views
  17629. */
  17630. // Add a new named queue for rendering views that happens
  17631. // after bindings have synced, and a queue for scheduling actions
  17632. // that that should occur after view rendering.
  17633. var queues = Ember.run.queues,
  17634. indexOf = Ember.ArrayPolyfills.indexOf;
  17635. queues.splice(indexOf.call(queues, 'actions')+1, 0, 'render', 'afterRender');
  17636. })();
  17637. (function() {
  17638. /**
  17639. @module ember
  17640. @submodule ember-views
  17641. */
  17642. var get = Ember.get, set = Ember.set;
  17643. // Original class declaration and documentation in runtime/lib/controllers/controller.js
  17644. // NOTE: It may be possible with YUIDoc to combine docs in two locations
  17645. /**
  17646. Additional methods for the ControllerMixin
  17647. @class ControllerMixin
  17648. @namespace Ember
  17649. */
  17650. Ember.ControllerMixin.reopen({
  17651. target: null,
  17652. namespace: null,
  17653. view: null,
  17654. container: null,
  17655. _childContainers: null,
  17656. init: function() {
  17657. this._super();
  17658. set(this, '_childContainers', {});
  17659. },
  17660. _modelDidChange: Ember.observer('model', function() {
  17661. var containers = get(this, '_childContainers');
  17662. for (var prop in containers) {
  17663. if (!containers.hasOwnProperty(prop)) { continue; }
  17664. containers[prop].destroy();
  17665. }
  17666. set(this, '_childContainers', {});
  17667. })
  17668. });
  17669. })();
  17670. (function() {
  17671. })();
  17672. (function() {
  17673. var states = {};
  17674. /**
  17675. @module ember
  17676. @submodule ember-views
  17677. */
  17678. var get = Ember.get, set = Ember.set;
  17679. var guidFor = Ember.guidFor;
  17680. var a_forEach = Ember.EnumerableUtils.forEach;
  17681. var a_addObject = Ember.EnumerableUtils.addObject;
  17682. var meta = Ember.meta;
  17683. var childViewsProperty = Ember.computed(function() {
  17684. var childViews = this._childViews, ret = Ember.A(), view = this;
  17685. a_forEach(childViews, function(view) {
  17686. var currentChildViews;
  17687. if (view.isVirtual) {
  17688. if (currentChildViews = get(view, 'childViews')) {
  17689. ret.pushObjects(currentChildViews);
  17690. }
  17691. } else {
  17692. ret.push(view);
  17693. }
  17694. });
  17695. ret.replace = function (idx, removedCount, addedViews) {
  17696. if (view instanceof Ember.ContainerView) {
  17697. Ember.deprecate("Manipulating an Ember.ContainerView through its childViews property is deprecated. Please use the ContainerView instance itself as an Ember.MutableArray.");
  17698. return view.replace(idx, removedCount, addedViews);
  17699. }
  17700. throw new Ember.Error("childViews is immutable");
  17701. };
  17702. return ret;
  17703. });
  17704. Ember.warn("The VIEW_PRESERVES_CONTEXT flag has been removed and the functionality can no longer be disabled.", Ember.ENV.VIEW_PRESERVES_CONTEXT !== false);
  17705. /**
  17706. Global hash of shared templates. This will automatically be populated
  17707. by the build tools so that you can store your Handlebars templates in
  17708. separate files that get loaded into JavaScript at buildtime.
  17709. @property TEMPLATES
  17710. @for Ember
  17711. @type Hash
  17712. */
  17713. Ember.TEMPLATES = {};
  17714. /**
  17715. `Ember.CoreView` is an abstract class that exists to give view-like behavior
  17716. to both Ember's main view class `Ember.View` and other classes like
  17717. `Ember._SimpleMetamorphView` that don't need the fully functionaltiy of
  17718. `Ember.View`.
  17719. Unless you have specific needs for `CoreView`, you will use `Ember.View`
  17720. in your applications.
  17721. @class CoreView
  17722. @namespace Ember
  17723. @extends Ember.Object
  17724. @uses Ember.Evented
  17725. @uses Ember.ActionHandler
  17726. */
  17727. Ember.CoreView = Ember.Object.extend(Ember.Evented, Ember.ActionHandler, {
  17728. isView: true,
  17729. states: states,
  17730. init: function() {
  17731. this._super();
  17732. this.transitionTo('preRender');
  17733. },
  17734. /**
  17735. If the view is currently inserted into the DOM of a parent view, this
  17736. property will point to the parent of the view.
  17737. @property parentView
  17738. @type Ember.View
  17739. @default null
  17740. */
  17741. parentView: Ember.computed(function() {
  17742. var parent = this._parentView;
  17743. if (parent && parent.isVirtual) {
  17744. return get(parent, 'parentView');
  17745. } else {
  17746. return parent;
  17747. }
  17748. }).property('_parentView'),
  17749. state: null,
  17750. _parentView: null,
  17751. // return the current view, not including virtual views
  17752. concreteView: Ember.computed(function() {
  17753. if (!this.isVirtual) { return this; }
  17754. else { return get(this, 'parentView'); }
  17755. }).property('parentView'),
  17756. instrumentName: 'core_view',
  17757. instrumentDetails: function(hash) {
  17758. hash.object = this.toString();
  17759. },
  17760. /**
  17761. Invoked by the view system when this view needs to produce an HTML
  17762. representation. This method will create a new render buffer, if needed,
  17763. then apply any default attributes, such as class names and visibility.
  17764. Finally, the `render()` method is invoked, which is responsible for
  17765. doing the bulk of the rendering.
  17766. You should not need to override this method; instead, implement the
  17767. `template` property, or if you need more control, override the `render`
  17768. method.
  17769. @method renderToBuffer
  17770. @param {Ember.RenderBuffer} buffer the render buffer. If no buffer is
  17771. passed, a default buffer, using the current view's `tagName`, will
  17772. be used.
  17773. @private
  17774. */
  17775. renderToBuffer: function(parentBuffer, bufferOperation) {
  17776. var name = 'render.' + this.instrumentName,
  17777. details = {};
  17778. this.instrumentDetails(details);
  17779. return Ember.instrument(name, details, function instrumentRenderToBuffer() {
  17780. return this._renderToBuffer(parentBuffer, bufferOperation);
  17781. }, this);
  17782. },
  17783. _renderToBuffer: function(parentBuffer, bufferOperation) {
  17784. // If this is the top-most view, start a new buffer. Otherwise,
  17785. // create a new buffer relative to the original using the
  17786. // provided buffer operation (for example, `insertAfter` will
  17787. // insert a new buffer after the "parent buffer").
  17788. var tagName = this.tagName;
  17789. if (tagName === null || tagName === undefined) {
  17790. tagName = 'div';
  17791. }
  17792. var buffer = this.buffer = parentBuffer && parentBuffer.begin(tagName) || Ember.RenderBuffer(tagName);
  17793. this.transitionTo('inBuffer', false);
  17794. this.beforeRender(buffer);
  17795. this.render(buffer);
  17796. this.afterRender(buffer);
  17797. return buffer;
  17798. },
  17799. /**
  17800. Override the default event firing from `Ember.Evented` to
  17801. also call methods with the given name.
  17802. @method trigger
  17803. @param name {String}
  17804. @private
  17805. */
  17806. trigger: function(name) {
  17807. this._super.apply(this, arguments);
  17808. var method = this[name];
  17809. if (method) {
  17810. var args = [], i, l;
  17811. for (i = 1, l = arguments.length; i < l; i++) {
  17812. args.push(arguments[i]);
  17813. }
  17814. return method.apply(this, args);
  17815. }
  17816. },
  17817. deprecatedSendHandles: function(actionName) {
  17818. return !!this[actionName];
  17819. },
  17820. deprecatedSend: function(actionName) {
  17821. var args = [].slice.call(arguments, 1);
  17822. Ember.assert('' + this + " has the action " + actionName + " but it is not a function", typeof this[actionName] === 'function');
  17823. Ember.deprecate('Action handlers implemented directly on views are deprecated in favor of action handlers on an `actions` object ( action: `' + actionName + '` on ' + this + ')', false);
  17824. this[actionName].apply(this, args);
  17825. return;
  17826. },
  17827. has: function(name) {
  17828. return Ember.typeOf(this[name]) === 'function' || this._super(name);
  17829. },
  17830. destroy: function() {
  17831. var parent = this._parentView;
  17832. if (!this._super()) { return; }
  17833. // destroy the element -- this will avoid each child view destroying
  17834. // the element over and over again...
  17835. if (!this.removedFromDOM) { this.destroyElement(); }
  17836. // remove from parent if found. Don't call removeFromParent,
  17837. // as removeFromParent will try to remove the element from
  17838. // the DOM again.
  17839. if (parent) { parent.removeChild(this); }
  17840. this.transitionTo('destroying', false);
  17841. return this;
  17842. },
  17843. clearRenderedChildren: Ember.K,
  17844. triggerRecursively: Ember.K,
  17845. invokeRecursively: Ember.K,
  17846. transitionTo: Ember.K,
  17847. destroyElement: Ember.K
  17848. });
  17849. var ViewCollection = Ember._ViewCollection = function(initialViews) {
  17850. var views = this.views = initialViews || [];
  17851. this.length = views.length;
  17852. };
  17853. ViewCollection.prototype = {
  17854. length: 0,
  17855. trigger: function(eventName) {
  17856. var views = this.views, view;
  17857. for (var i = 0, l = views.length; i < l; i++) {
  17858. view = views[i];
  17859. if (view.trigger) { view.trigger(eventName); }
  17860. }
  17861. },
  17862. triggerRecursively: function(eventName) {
  17863. var views = this.views;
  17864. for (var i = 0, l = views.length; i < l; i++) {
  17865. views[i].triggerRecursively(eventName);
  17866. }
  17867. },
  17868. invokeRecursively: function(fn) {
  17869. var views = this.views, view;
  17870. for (var i = 0, l = views.length; i < l; i++) {
  17871. view = views[i];
  17872. fn(view);
  17873. }
  17874. },
  17875. transitionTo: function(state, children) {
  17876. var views = this.views;
  17877. for (var i = 0, l = views.length; i < l; i++) {
  17878. views[i].transitionTo(state, children);
  17879. }
  17880. },
  17881. push: function() {
  17882. this.length += arguments.length;
  17883. var views = this.views;
  17884. return views.push.apply(views, arguments);
  17885. },
  17886. objectAt: function(idx) {
  17887. return this.views[idx];
  17888. },
  17889. forEach: function(callback) {
  17890. var views = this.views;
  17891. return a_forEach(views, callback);
  17892. },
  17893. clear: function() {
  17894. this.length = 0;
  17895. this.views.length = 0;
  17896. }
  17897. };
  17898. var EMPTY_ARRAY = [];
  17899. /**
  17900. `Ember.View` is the class in Ember responsible for encapsulating templates of
  17901. HTML content, combining templates with data to render as sections of a page's
  17902. DOM, and registering and responding to user-initiated events.
  17903. ## HTML Tag
  17904. The default HTML tag name used for a view's DOM representation is `div`. This
  17905. can be customized by setting the `tagName` property. The following view
  17906. class:
  17907. ```javascript
  17908. ParagraphView = Ember.View.extend({
  17909. tagName: 'em'
  17910. });
  17911. ```
  17912. Would result in instances with the following HTML:
  17913. ```html
  17914. <em id="ember1" class="ember-view"></em>
  17915. ```
  17916. ## HTML `class` Attribute
  17917. The HTML `class` attribute of a view's tag can be set by providing a
  17918. `classNames` property that is set to an array of strings:
  17919. ```javascript
  17920. MyView = Ember.View.extend({
  17921. classNames: ['my-class', 'my-other-class']
  17922. });
  17923. ```
  17924. Will result in view instances with an HTML representation of:
  17925. ```html
  17926. <div id="ember1" class="ember-view my-class my-other-class"></div>
  17927. ```
  17928. `class` attribute values can also be set by providing a `classNameBindings`
  17929. property set to an array of properties names for the view. The return value
  17930. of these properties will be added as part of the value for the view's `class`
  17931. attribute. These properties can be computed properties:
  17932. ```javascript
  17933. MyView = Ember.View.extend({
  17934. classNameBindings: ['propertyA', 'propertyB'],
  17935. propertyA: 'from-a',
  17936. propertyB: function() {
  17937. if (someLogic) { return 'from-b'; }
  17938. }.property()
  17939. });
  17940. ```
  17941. Will result in view instances with an HTML representation of:
  17942. ```html
  17943. <div id="ember1" class="ember-view from-a from-b"></div>
  17944. ```
  17945. If the value of a class name binding returns a boolean the property name
  17946. itself will be used as the class name if the property is true. The class name
  17947. will not be added if the value is `false` or `undefined`.
  17948. ```javascript
  17949. MyView = Ember.View.extend({
  17950. classNameBindings: ['hovered'],
  17951. hovered: true
  17952. });
  17953. ```
  17954. Will result in view instances with an HTML representation of:
  17955. ```html
  17956. <div id="ember1" class="ember-view hovered"></div>
  17957. ```
  17958. When using boolean class name bindings you can supply a string value other
  17959. than the property name for use as the `class` HTML attribute by appending the
  17960. preferred value after a ":" character when defining the binding:
  17961. ```javascript
  17962. MyView = Ember.View.extend({
  17963. classNameBindings: ['awesome:so-very-cool'],
  17964. awesome: true
  17965. });
  17966. ```
  17967. Will result in view instances with an HTML representation of:
  17968. ```html
  17969. <div id="ember1" class="ember-view so-very-cool"></div>
  17970. ```
  17971. Boolean value class name bindings whose property names are in a
  17972. camelCase-style format will be converted to a dasherized format:
  17973. ```javascript
  17974. MyView = Ember.View.extend({
  17975. classNameBindings: ['isUrgent'],
  17976. isUrgent: true
  17977. });
  17978. ```
  17979. Will result in view instances with an HTML representation of:
  17980. ```html
  17981. <div id="ember1" class="ember-view is-urgent"></div>
  17982. ```
  17983. Class name bindings can also refer to object values that are found by
  17984. traversing a path relative to the view itself:
  17985. ```javascript
  17986. MyView = Ember.View.extend({
  17987. classNameBindings: ['messages.empty']
  17988. messages: Ember.Object.create({
  17989. empty: true
  17990. })
  17991. });
  17992. ```
  17993. Will result in view instances with an HTML representation of:
  17994. ```html
  17995. <div id="ember1" class="ember-view empty"></div>
  17996. ```
  17997. If you want to add a class name for a property which evaluates to true and
  17998. and a different class name if it evaluates to false, you can pass a binding
  17999. like this:
  18000. ```javascript
  18001. // Applies 'enabled' class when isEnabled is true and 'disabled' when isEnabled is false
  18002. Ember.View.extend({
  18003. classNameBindings: ['isEnabled:enabled:disabled']
  18004. isEnabled: true
  18005. });
  18006. ```
  18007. Will result in view instances with an HTML representation of:
  18008. ```html
  18009. <div id="ember1" class="ember-view enabled"></div>
  18010. ```
  18011. When isEnabled is `false`, the resulting HTML reprensentation looks like
  18012. this:
  18013. ```html
  18014. <div id="ember1" class="ember-view disabled"></div>
  18015. ```
  18016. This syntax offers the convenience to add a class if a property is `false`:
  18017. ```javascript
  18018. // Applies no class when isEnabled is true and class 'disabled' when isEnabled is false
  18019. Ember.View.extend({
  18020. classNameBindings: ['isEnabled::disabled']
  18021. isEnabled: true
  18022. });
  18023. ```
  18024. Will result in view instances with an HTML representation of:
  18025. ```html
  18026. <div id="ember1" class="ember-view"></div>
  18027. ```
  18028. When the `isEnabled` property on the view is set to `false`, it will result
  18029. in view instances with an HTML representation of:
  18030. ```html
  18031. <div id="ember1" class="ember-view disabled"></div>
  18032. ```
  18033. Updates to the the value of a class name binding will result in automatic
  18034. update of the HTML `class` attribute in the view's rendered HTML
  18035. representation. If the value becomes `false` or `undefined` the class name
  18036. will be removed.
  18037. Both `classNames` and `classNameBindings` are concatenated properties. See
  18038. [Ember.Object](/api/classes/Ember.Object.html) documentation for more
  18039. information about concatenated properties.
  18040. ## HTML Attributes
  18041. The HTML attribute section of a view's tag can be set by providing an
  18042. `attributeBindings` property set to an array of property names on the view.
  18043. The return value of these properties will be used as the value of the view's
  18044. HTML associated attribute:
  18045. ```javascript
  18046. AnchorView = Ember.View.extend({
  18047. tagName: 'a',
  18048. attributeBindings: ['href'],
  18049. href: 'http://google.com'
  18050. });
  18051. ```
  18052. Will result in view instances with an HTML representation of:
  18053. ```html
  18054. <a id="ember1" class="ember-view" href="http://google.com"></a>
  18055. ```
  18056. If the return value of an `attributeBindings` monitored property is a boolean
  18057. the property will follow HTML's pattern of repeating the attribute's name as
  18058. its value:
  18059. ```javascript
  18060. MyTextInput = Ember.View.extend({
  18061. tagName: 'input',
  18062. attributeBindings: ['disabled'],
  18063. disabled: true
  18064. });
  18065. ```
  18066. Will result in view instances with an HTML representation of:
  18067. ```html
  18068. <input id="ember1" class="ember-view" disabled="disabled" />
  18069. ```
  18070. `attributeBindings` can refer to computed properties:
  18071. ```javascript
  18072. MyTextInput = Ember.View.extend({
  18073. tagName: 'input',
  18074. attributeBindings: ['disabled'],
  18075. disabled: function() {
  18076. if (someLogic) {
  18077. return true;
  18078. } else {
  18079. return false;
  18080. }
  18081. }.property()
  18082. });
  18083. ```
  18084. Updates to the the property of an attribute binding will result in automatic
  18085. update of the HTML attribute in the view's rendered HTML representation.
  18086. `attributeBindings` is a concatenated property. See [Ember.Object](/api/classes/Ember.Object.html)
  18087. documentation for more information about concatenated properties.
  18088. ## Templates
  18089. The HTML contents of a view's rendered representation are determined by its
  18090. template. Templates can be any function that accepts an optional context
  18091. parameter and returns a string of HTML that will be inserted within the
  18092. view's tag. Most typically in Ember this function will be a compiled
  18093. `Ember.Handlebars` template.
  18094. ```javascript
  18095. AView = Ember.View.extend({
  18096. template: Ember.Handlebars.compile('I am the template')
  18097. });
  18098. ```
  18099. Will result in view instances with an HTML representation of:
  18100. ```html
  18101. <div id="ember1" class="ember-view">I am the template</div>
  18102. ```
  18103. Within an Ember application is more common to define a Handlebars templates as
  18104. part of a page:
  18105. ```html
  18106. <script type='text/x-handlebars' data-template-name='some-template'>
  18107. Hello
  18108. </script>
  18109. ```
  18110. And associate it by name using a view's `templateName` property:
  18111. ```javascript
  18112. AView = Ember.View.extend({
  18113. templateName: 'some-template'
  18114. });
  18115. ```
  18116. If you have nested resources, your Handlebars template will look like this:
  18117. ```html
  18118. <script type='text/x-handlebars' data-template-name='posts/new'>
  18119. <h1>New Post</h1>
  18120. </script>
  18121. ```
  18122. And `templateName` property:
  18123. ```javascript
  18124. AView = Ember.View.extend({
  18125. templateName: 'posts/new'
  18126. });
  18127. ```
  18128. Using a value for `templateName` that does not have a Handlebars template
  18129. with a matching `data-template-name` attribute will throw an error.
  18130. For views classes that may have a template later defined (e.g. as the block
  18131. portion of a `{{view}}` Handlebars helper call in another template or in
  18132. a subclass), you can provide a `defaultTemplate` property set to compiled
  18133. template function. If a template is not later provided for the view instance
  18134. the `defaultTemplate` value will be used:
  18135. ```javascript
  18136. AView = Ember.View.extend({
  18137. defaultTemplate: Ember.Handlebars.compile('I was the default'),
  18138. template: null,
  18139. templateName: null
  18140. });
  18141. ```
  18142. Will result in instances with an HTML representation of:
  18143. ```html
  18144. <div id="ember1" class="ember-view">I was the default</div>
  18145. ```
  18146. If a `template` or `templateName` is provided it will take precedence over
  18147. `defaultTemplate`:
  18148. ```javascript
  18149. AView = Ember.View.extend({
  18150. defaultTemplate: Ember.Handlebars.compile('I was the default')
  18151. });
  18152. aView = AView.create({
  18153. template: Ember.Handlebars.compile('I was the template, not default')
  18154. });
  18155. ```
  18156. Will result in the following HTML representation when rendered:
  18157. ```html
  18158. <div id="ember1" class="ember-view">I was the template, not default</div>
  18159. ```
  18160. ## View Context
  18161. The default context of the compiled template is the view's controller:
  18162. ```javascript
  18163. AView = Ember.View.extend({
  18164. template: Ember.Handlebars.compile('Hello {{excitedGreeting}}')
  18165. });
  18166. aController = Ember.Object.create({
  18167. firstName: 'Barry',
  18168. excitedGreeting: function() {
  18169. return this.get("content.firstName") + "!!!"
  18170. }.property()
  18171. });
  18172. aView = AView.create({
  18173. controller: aController,
  18174. });
  18175. ```
  18176. Will result in an HTML representation of:
  18177. ```html
  18178. <div id="ember1" class="ember-view">Hello Barry!!!</div>
  18179. ```
  18180. A context can also be explicitly supplied through the view's `context`
  18181. property. If the view has neither `context` nor `controller` properties, the
  18182. `parentView`'s context will be used.
  18183. ## Layouts
  18184. Views can have a secondary template that wraps their main template. Like
  18185. primary templates, layouts can be any function that accepts an optional
  18186. context parameter and returns a string of HTML that will be inserted inside
  18187. view's tag. Views whose HTML element is self closing (e.g. `<input />`)
  18188. cannot have a layout and this property will be ignored.
  18189. Most typically in Ember a layout will be a compiled `Ember.Handlebars`
  18190. template.
  18191. A view's layout can be set directly with the `layout` property or reference
  18192. an existing Handlebars template by name with the `layoutName` property.
  18193. A template used as a layout must contain a single use of the Handlebars
  18194. `{{yield}}` helper. The HTML contents of a view's rendered `template` will be
  18195. inserted at this location:
  18196. ```javascript
  18197. AViewWithLayout = Ember.View.extend({
  18198. layout: Ember.Handlebars.compile("<div class='my-decorative-class'>{{yield}}</div>")
  18199. template: Ember.Handlebars.compile("I got wrapped"),
  18200. });
  18201. ```
  18202. Will result in view instances with an HTML representation of:
  18203. ```html
  18204. <div id="ember1" class="ember-view">
  18205. <div class="my-decorative-class">
  18206. I got wrapped
  18207. </div>
  18208. </div>
  18209. ```
  18210. See [Ember.Handlebars.helpers.yield](/api/classes/Ember.Handlebars.helpers.html#method_yield)
  18211. for more information.
  18212. ## Responding to Browser Events
  18213. Views can respond to user-initiated events in one of three ways: method
  18214. implementation, through an event manager, and through `{{action}}` helper use
  18215. in their template or layout.
  18216. ### Method Implementation
  18217. Views can respond to user-initiated events by implementing a method that
  18218. matches the event name. A `jQuery.Event` object will be passed as the
  18219. argument to this method.
  18220. ```javascript
  18221. AView = Ember.View.extend({
  18222. click: function(event) {
  18223. // will be called when when an instance's
  18224. // rendered element is clicked
  18225. }
  18226. });
  18227. ```
  18228. ### Event Managers
  18229. Views can define an object as their `eventManager` property. This object can
  18230. then implement methods that match the desired event names. Matching events
  18231. that occur on the view's rendered HTML or the rendered HTML of any of its DOM
  18232. descendants will trigger this method. A `jQuery.Event` object will be passed
  18233. as the first argument to the method and an `Ember.View` object as the
  18234. second. The `Ember.View` will be the view whose rendered HTML was interacted
  18235. with. This may be the view with the `eventManager` property or one of its
  18236. descendent views.
  18237. ```javascript
  18238. AView = Ember.View.extend({
  18239. eventManager: Ember.Object.create({
  18240. doubleClick: function(event, view) {
  18241. // will be called when when an instance's
  18242. // rendered element or any rendering
  18243. // of this views's descendent
  18244. // elements is clicked
  18245. }
  18246. })
  18247. });
  18248. ```
  18249. An event defined for an event manager takes precedence over events of the
  18250. same name handled through methods on the view.
  18251. ```javascript
  18252. AView = Ember.View.extend({
  18253. mouseEnter: function(event) {
  18254. // will never trigger.
  18255. },
  18256. eventManager: Ember.Object.create({
  18257. mouseEnter: function(event, view) {
  18258. // takes precedence over AView#mouseEnter
  18259. }
  18260. })
  18261. });
  18262. ```
  18263. Similarly a view's event manager will take precedence for events of any views
  18264. rendered as a descendent. A method name that matches an event name will not
  18265. be called if the view instance was rendered inside the HTML representation of
  18266. a view that has an `eventManager` property defined that handles events of the
  18267. name. Events not handled by the event manager will still trigger method calls
  18268. on the descendent.
  18269. ```javascript
  18270. OuterView = Ember.View.extend({
  18271. template: Ember.Handlebars.compile("outer {{#view InnerView}}inner{{/view}} outer"),
  18272. eventManager: Ember.Object.create({
  18273. mouseEnter: function(event, view) {
  18274. // view might be instance of either
  18275. // OuterView or InnerView depending on
  18276. // where on the page the user interaction occured
  18277. }
  18278. })
  18279. });
  18280. InnerView = Ember.View.extend({
  18281. click: function(event) {
  18282. // will be called if rendered inside
  18283. // an OuterView because OuterView's
  18284. // eventManager doesn't handle click events
  18285. },
  18286. mouseEnter: function(event) {
  18287. // will never be called if rendered inside
  18288. // an OuterView.
  18289. }
  18290. });
  18291. ```
  18292. ### Handlebars `{{action}}` Helper
  18293. See [Handlebars.helpers.action](/api/classes/Ember.Handlebars.helpers.html#method_action).
  18294. ### Event Names
  18295. All of the event handling approaches described above respond to the same set
  18296. of events. The names of the built-in events are listed below. (The hash of
  18297. built-in events exists in `Ember.EventDispatcher`.) Additional, custom events
  18298. can be registered by using `Ember.Application.customEvents`.
  18299. Touch events:
  18300. * `touchStart`
  18301. * `touchMove`
  18302. * `touchEnd`
  18303. * `touchCancel`
  18304. Keyboard events
  18305. * `keyDown`
  18306. * `keyUp`
  18307. * `keyPress`
  18308. Mouse events
  18309. * `mouseDown`
  18310. * `mouseUp`
  18311. * `contextMenu`
  18312. * `click`
  18313. * `doubleClick`
  18314. * `mouseMove`
  18315. * `focusIn`
  18316. * `focusOut`
  18317. * `mouseEnter`
  18318. * `mouseLeave`
  18319. Form events:
  18320. * `submit`
  18321. * `change`
  18322. * `focusIn`
  18323. * `focusOut`
  18324. * `input`
  18325. HTML5 drag and drop events:
  18326. * `dragStart`
  18327. * `drag`
  18328. * `dragEnter`
  18329. * `dragLeave`
  18330. * `drop`
  18331. * `dragEnd`
  18332. ## Handlebars `{{view}}` Helper
  18333. Other `Ember.View` instances can be included as part of a view's template by
  18334. using the `{{view}}` Handlebars helper. See [Ember.Handlebars.helpers.view](/api/classes/Ember.Handlebars.helpers.html#method_view)
  18335. for additional information.
  18336. @class View
  18337. @namespace Ember
  18338. @extends Ember.CoreView
  18339. */
  18340. Ember.View = Ember.CoreView.extend({
  18341. concatenatedProperties: ['classNames', 'classNameBindings', 'attributeBindings'],
  18342. /**
  18343. @property isView
  18344. @type Boolean
  18345. @default true
  18346. @static
  18347. */
  18348. isView: true,
  18349. // ..........................................................
  18350. // TEMPLATE SUPPORT
  18351. //
  18352. /**
  18353. The name of the template to lookup if no template is provided.
  18354. By default `Ember.View` will lookup a template with this name in
  18355. `Ember.TEMPLATES` (a shared global object).
  18356. @property templateName
  18357. @type String
  18358. @default null
  18359. */
  18360. templateName: null,
  18361. /**
  18362. The name of the layout to lookup if no layout is provided.
  18363. By default `Ember.View` will lookup a template with this name in
  18364. `Ember.TEMPLATES` (a shared global object).
  18365. @property layoutName
  18366. @type String
  18367. @default null
  18368. */
  18369. layoutName: null,
  18370. /**
  18371. The template used to render the view. This should be a function that
  18372. accepts an optional context parameter and returns a string of HTML that
  18373. will be inserted into the DOM relative to its parent view.
  18374. In general, you should set the `templateName` property instead of setting
  18375. the template yourself.
  18376. @property template
  18377. @type Function
  18378. */
  18379. template: Ember.computed(function(key, value) {
  18380. if (value !== undefined) { return value; }
  18381. var templateName = get(this, 'templateName'),
  18382. template = this.templateForName(templateName, 'template');
  18383. Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template);
  18384. return template || get(this, 'defaultTemplate');
  18385. }).property('templateName'),
  18386. /**
  18387. The controller managing this view. If this property is set, it will be
  18388. made available for use by the template.
  18389. @property controller
  18390. @type Object
  18391. */
  18392. controller: Ember.computed(function(key) {
  18393. var parentView = get(this, '_parentView');
  18394. return parentView ? get(parentView, 'controller') : null;
  18395. }).property('_parentView'),
  18396. /**
  18397. A view may contain a layout. A layout is a regular template but
  18398. supersedes the `template` property during rendering. It is the
  18399. responsibility of the layout template to retrieve the `template`
  18400. property from the view (or alternatively, call `Handlebars.helpers.yield`,
  18401. `{{yield}}`) to render it in the correct location.
  18402. This is useful for a view that has a shared wrapper, but which delegates
  18403. the rendering of the contents of the wrapper to the `template` property
  18404. on a subclass.
  18405. @property layout
  18406. @type Function
  18407. */
  18408. layout: Ember.computed(function(key) {
  18409. var layoutName = get(this, 'layoutName'),
  18410. layout = this.templateForName(layoutName, 'layout');
  18411. Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || layout);
  18412. return layout || get(this, 'defaultLayout');
  18413. }).property('layoutName'),
  18414. _yield: function(context, options) {
  18415. var template = get(this, 'template');
  18416. if (template) { template(context, options); }
  18417. },
  18418. templateForName: function(name, type) {
  18419. if (!name) { return; }
  18420. Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') === -1);
  18421. // the defaultContainer is deprecated
  18422. var container = this.container || (Ember.Container && Ember.Container.defaultContainer);
  18423. return container && container.lookup('template:' + name);
  18424. },
  18425. /**
  18426. The object from which templates should access properties.
  18427. This object will be passed to the template function each time the render
  18428. method is called, but it is up to the individual function to decide what
  18429. to do with it.
  18430. By default, this will be the view's controller.
  18431. @property context
  18432. @type Object
  18433. */
  18434. context: Ember.computed(function(key, value) {
  18435. if (arguments.length === 2) {
  18436. set(this, '_context', value);
  18437. return value;
  18438. } else {
  18439. return get(this, '_context');
  18440. }
  18441. }).volatile(),
  18442. /**
  18443. Private copy of the view's template context. This can be set directly
  18444. by Handlebars without triggering the observer that causes the view
  18445. to be re-rendered.
  18446. The context of a view is looked up as follows:
  18447. 1. Supplied context (usually by Handlebars)
  18448. 2. Specified controller
  18449. 3. `parentView`'s context (for a child of a ContainerView)
  18450. The code in Handlebars that overrides the `_context` property first
  18451. checks to see whether the view has a specified controller. This is
  18452. something of a hack and should be revisited.
  18453. @property _context
  18454. @private
  18455. */
  18456. _context: Ember.computed(function(key) {
  18457. var parentView, controller;
  18458. if (controller = get(this, 'controller')) {
  18459. return controller;
  18460. }
  18461. parentView = this._parentView;
  18462. if (parentView) {
  18463. return get(parentView, '_context');
  18464. }
  18465. return null;
  18466. }),
  18467. /**
  18468. If a value that affects template rendering changes, the view should be
  18469. re-rendered to reflect the new value.
  18470. @method _contextDidChange
  18471. @private
  18472. */
  18473. _contextDidChange: Ember.observer('context', function() {
  18474. this.rerender();
  18475. }),
  18476. /**
  18477. If `false`, the view will appear hidden in DOM.
  18478. @property isVisible
  18479. @type Boolean
  18480. @default null
  18481. */
  18482. isVisible: true,
  18483. /**
  18484. Array of child views. You should never edit this array directly.
  18485. Instead, use `appendChild` and `removeFromParent`.
  18486. @property childViews
  18487. @type Array
  18488. @default []
  18489. @private
  18490. */
  18491. childViews: childViewsProperty,
  18492. _childViews: EMPTY_ARRAY,
  18493. // When it's a virtual view, we need to notify the parent that their
  18494. // childViews will change.
  18495. _childViewsWillChange: Ember.beforeObserver('childViews', function() {
  18496. if (this.isVirtual) {
  18497. var parentView = get(this, 'parentView');
  18498. if (parentView) { Ember.propertyWillChange(parentView, 'childViews'); }
  18499. }
  18500. }),
  18501. // When it's a virtual view, we need to notify the parent that their
  18502. // childViews did change.
  18503. _childViewsDidChange: Ember.observer('childViews', function() {
  18504. if (this.isVirtual) {
  18505. var parentView = get(this, 'parentView');
  18506. if (parentView) { Ember.propertyDidChange(parentView, 'childViews'); }
  18507. }
  18508. }),
  18509. /**
  18510. Return the nearest ancestor that is an instance of the provided
  18511. class.
  18512. @property nearestInstanceOf
  18513. @param {Class} klass Subclass of Ember.View (or Ember.View itself)
  18514. @return Ember.View
  18515. @deprecated
  18516. */
  18517. nearestInstanceOf: function(klass) {
  18518. Ember.deprecate("nearestInstanceOf is deprecated and will be removed from future releases. Use nearestOfType.");
  18519. var view = get(this, 'parentView');
  18520. while (view) {
  18521. if (view instanceof klass) { return view; }
  18522. view = get(view, 'parentView');
  18523. }
  18524. },
  18525. /**
  18526. Return the nearest ancestor that is an instance of the provided
  18527. class or mixin.
  18528. @property nearestOfType
  18529. @param {Class,Mixin} klass Subclass of Ember.View (or Ember.View itself),
  18530. or an instance of Ember.Mixin.
  18531. @return Ember.View
  18532. */
  18533. nearestOfType: function(klass) {
  18534. var view = get(this, 'parentView'),
  18535. isOfType = klass instanceof Ember.Mixin ?
  18536. function(view) { return klass.detect(view); } :
  18537. function(view) { return klass.detect(view.constructor); };
  18538. while (view) {
  18539. if (isOfType(view)) { return view; }
  18540. view = get(view, 'parentView');
  18541. }
  18542. },
  18543. /**
  18544. Return the nearest ancestor that has a given property.
  18545. @function nearestWithProperty
  18546. @param {String} property A property name
  18547. @return Ember.View
  18548. */
  18549. nearestWithProperty: function(property) {
  18550. var view = get(this, 'parentView');
  18551. while (view) {
  18552. if (property in view) { return view; }
  18553. view = get(view, 'parentView');
  18554. }
  18555. },
  18556. /**
  18557. Return the nearest ancestor whose parent is an instance of
  18558. `klass`.
  18559. @method nearestChildOf
  18560. @param {Class} klass Subclass of Ember.View (or Ember.View itself)
  18561. @return Ember.View
  18562. */
  18563. nearestChildOf: function(klass) {
  18564. var view = get(this, 'parentView');
  18565. while (view) {
  18566. if (get(view, 'parentView') instanceof klass) { return view; }
  18567. view = get(view, 'parentView');
  18568. }
  18569. },
  18570. /**
  18571. When the parent view changes, recursively invalidate `controller`
  18572. @method _parentViewDidChange
  18573. @private
  18574. */
  18575. _parentViewDidChange: Ember.observer('_parentView', function() {
  18576. if (this.isDestroying) { return; }
  18577. this.trigger('parentViewDidChange');
  18578. if (get(this, 'parentView.controller') && !get(this, 'controller')) {
  18579. this.notifyPropertyChange('controller');
  18580. }
  18581. }),
  18582. _controllerDidChange: Ember.observer('controller', function() {
  18583. if (this.isDestroying) { return; }
  18584. this.rerender();
  18585. this.forEachChildView(function(view) {
  18586. view.propertyDidChange('controller');
  18587. });
  18588. }),
  18589. cloneKeywords: function() {
  18590. var templateData = get(this, 'templateData');
  18591. var keywords = templateData ? Ember.copy(templateData.keywords) : {};
  18592. set(keywords, 'view', get(this, 'concreteView'));
  18593. set(keywords, '_view', this);
  18594. set(keywords, 'controller', get(this, 'controller'));
  18595. return keywords;
  18596. },
  18597. /**
  18598. Called on your view when it should push strings of HTML into a
  18599. `Ember.RenderBuffer`. Most users will want to override the `template`
  18600. or `templateName` properties instead of this method.
  18601. By default, `Ember.View` will look for a function in the `template`
  18602. property and invoke it with the value of `context`. The value of
  18603. `context` will be the view's controller unless you override it.
  18604. @method render
  18605. @param {Ember.RenderBuffer} buffer The render buffer
  18606. */
  18607. render: function(buffer) {
  18608. // If this view has a layout, it is the responsibility of the
  18609. // the layout to render the view's template. Otherwise, render the template
  18610. // directly.
  18611. var template = get(this, 'layout') || get(this, 'template');
  18612. if (template) {
  18613. var context = get(this, 'context');
  18614. var keywords = this.cloneKeywords();
  18615. var output;
  18616. var data = {
  18617. view: this,
  18618. buffer: buffer,
  18619. isRenderData: true,
  18620. keywords: keywords,
  18621. insideGroup: get(this, 'templateData.insideGroup')
  18622. };
  18623. // Invoke the template with the provided template context, which
  18624. // is the view's controller by default. A hash of data is also passed that provides
  18625. // the template with access to the view and render buffer.
  18626. Ember.assert('template must be a function. Did you mean to call Ember.Handlebars.compile("...") or specify templateName instead?', typeof template === 'function');
  18627. // The template should write directly to the render buffer instead
  18628. // of returning a string.
  18629. output = template(context, { data: data });
  18630. // If the template returned a string instead of writing to the buffer,
  18631. // push the string onto the buffer.
  18632. if (output !== undefined) { buffer.push(output); }
  18633. }
  18634. },
  18635. /**
  18636. Renders the view again. This will work regardless of whether the
  18637. view is already in the DOM or not. If the view is in the DOM, the
  18638. rendering process will be deferred to give bindings a chance
  18639. to synchronize.
  18640. If children were added during the rendering process using `appendChild`,
  18641. `rerender` will remove them, because they will be added again
  18642. if needed by the next `render`.
  18643. In general, if the display of your view changes, you should modify
  18644. the DOM element directly instead of manually calling `rerender`, which can
  18645. be slow.
  18646. @method rerender
  18647. */
  18648. rerender: function() {
  18649. return this.currentState.rerender(this);
  18650. },
  18651. clearRenderedChildren: function() {
  18652. var lengthBefore = this.lengthBeforeRender,
  18653. lengthAfter = this.lengthAfterRender;
  18654. // If there were child views created during the last call to render(),
  18655. // remove them under the assumption that they will be re-created when
  18656. // we re-render.
  18657. // VIEW-TODO: Unit test this path.
  18658. var childViews = this._childViews;
  18659. for (var i=lengthAfter-1; i>=lengthBefore; i--) {
  18660. if (childViews[i]) { childViews[i].destroy(); }
  18661. }
  18662. },
  18663. /**
  18664. Iterates over the view's `classNameBindings` array, inserts the value
  18665. of the specified property into the `classNames` array, then creates an
  18666. observer to update the view's element if the bound property ever changes
  18667. in the future.
  18668. @method _applyClassNameBindings
  18669. @private
  18670. */
  18671. _applyClassNameBindings: function(classBindings) {
  18672. var classNames = this.classNames,
  18673. elem, newClass, dasherizedClass;
  18674. // Loop through all of the configured bindings. These will be either
  18675. // property names ('isUrgent') or property paths relative to the view
  18676. // ('content.isUrgent')
  18677. a_forEach(classBindings, function(binding) {
  18678. Ember.assert("classNameBindings must not have spaces in them. Multiple class name bindings can be provided as elements of an array, e.g. ['foo', ':bar']", binding.indexOf(' ') === -1);
  18679. // Variable in which the old class value is saved. The observer function
  18680. // closes over this variable, so it knows which string to remove when
  18681. // the property changes.
  18682. var oldClass;
  18683. // Extract just the property name from bindings like 'foo:bar'
  18684. var parsedPath = Ember.View._parsePropertyPath(binding);
  18685. // Set up an observer on the context. If the property changes, toggle the
  18686. // class name.
  18687. var observer = function() {
  18688. // Get the current value of the property
  18689. newClass = this._classStringForProperty(binding);
  18690. elem = this.$();
  18691. // If we had previously added a class to the element, remove it.
  18692. if (oldClass) {
  18693. elem.removeClass(oldClass);
  18694. // Also remove from classNames so that if the view gets rerendered,
  18695. // the class doesn't get added back to the DOM.
  18696. classNames.removeObject(oldClass);
  18697. }
  18698. // If necessary, add a new class. Make sure we keep track of it so
  18699. // it can be removed in the future.
  18700. if (newClass) {
  18701. elem.addClass(newClass);
  18702. oldClass = newClass;
  18703. } else {
  18704. oldClass = null;
  18705. }
  18706. };
  18707. // Get the class name for the property at its current value
  18708. dasherizedClass = this._classStringForProperty(binding);
  18709. if (dasherizedClass) {
  18710. // Ensure that it gets into the classNames array
  18711. // so it is displayed when we render.
  18712. a_addObject(classNames, dasherizedClass);
  18713. // Save a reference to the class name so we can remove it
  18714. // if the observer fires. Remember that this variable has
  18715. // been closed over by the observer.
  18716. oldClass = dasherizedClass;
  18717. }
  18718. this.registerObserver(this, parsedPath.path, observer);
  18719. // Remove className so when the view is rerendered,
  18720. // the className is added based on binding reevaluation
  18721. this.one('willClearRender', function() {
  18722. if (oldClass) {
  18723. classNames.removeObject(oldClass);
  18724. oldClass = null;
  18725. }
  18726. });
  18727. }, this);
  18728. },
  18729. /**
  18730. Iterates through the view's attribute bindings, sets up observers for each,
  18731. then applies the current value of the attributes to the passed render buffer.
  18732. @method _applyAttributeBindings
  18733. @param {Ember.RenderBuffer} buffer
  18734. @private
  18735. */
  18736. _applyAttributeBindings: function(buffer, attributeBindings) {
  18737. var attributeValue, elem;
  18738. a_forEach(attributeBindings, function(binding) {
  18739. var split = binding.split(':'),
  18740. property = split[0],
  18741. attributeName = split[1] || property;
  18742. // Create an observer to add/remove/change the attribute if the
  18743. // JavaScript property changes.
  18744. var observer = function() {
  18745. elem = this.$();
  18746. attributeValue = get(this, property);
  18747. Ember.View.applyAttributeBindings(elem, attributeName, attributeValue);
  18748. };
  18749. this.registerObserver(this, property, observer);
  18750. // Determine the current value and add it to the render buffer
  18751. // if necessary.
  18752. attributeValue = get(this, property);
  18753. Ember.View.applyAttributeBindings(buffer, attributeName, attributeValue);
  18754. }, this);
  18755. },
  18756. /**
  18757. Given a property name, returns a dasherized version of that
  18758. property name if the property evaluates to a non-falsy value.
  18759. For example, if the view has property `isUrgent` that evaluates to true,
  18760. passing `isUrgent` to this method will return `"is-urgent"`.
  18761. @method _classStringForProperty
  18762. @param property
  18763. @private
  18764. */
  18765. _classStringForProperty: function(property) {
  18766. var parsedPath = Ember.View._parsePropertyPath(property);
  18767. var path = parsedPath.path;
  18768. var val = get(this, path);
  18769. if (val === undefined && Ember.isGlobalPath(path)) {
  18770. val = get(Ember.lookup, path);
  18771. }
  18772. return Ember.View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName);
  18773. },
  18774. // ..........................................................
  18775. // ELEMENT SUPPORT
  18776. //
  18777. /**
  18778. Returns the current DOM element for the view.
  18779. @property element
  18780. @type DOMElement
  18781. */
  18782. element: Ember.computed(function(key, value) {
  18783. if (value !== undefined) {
  18784. return this.currentState.setElement(this, value);
  18785. } else {
  18786. return this.currentState.getElement(this);
  18787. }
  18788. }).property('_parentView'),
  18789. /**
  18790. Returns a jQuery object for this view's element. If you pass in a selector
  18791. string, this method will return a jQuery object, using the current element
  18792. as its buffer.
  18793. For example, calling `view.$('li')` will return a jQuery object containing
  18794. all of the `li` elements inside the DOM element of this view.
  18795. @method $
  18796. @param {String} [selector] a jQuery-compatible selector string
  18797. @return {jQuery} the jQuery object for the DOM node
  18798. */
  18799. $: function(sel) {
  18800. return this.currentState.$(this, sel);
  18801. },
  18802. mutateChildViews: function(callback) {
  18803. var childViews = this._childViews,
  18804. idx = childViews.length,
  18805. view;
  18806. while(--idx >= 0) {
  18807. view = childViews[idx];
  18808. callback(this, view, idx);
  18809. }
  18810. return this;
  18811. },
  18812. forEachChildView: function(callback) {
  18813. var childViews = this._childViews;
  18814. if (!childViews) { return this; }
  18815. var len = childViews.length,
  18816. view, idx;
  18817. for (idx = 0; idx < len; idx++) {
  18818. view = childViews[idx];
  18819. callback(view);
  18820. }
  18821. return this;
  18822. },
  18823. /**
  18824. Appends the view's element to the specified parent element.
  18825. If the view does not have an HTML representation yet, `createElement()`
  18826. will be called automatically.
  18827. Note that this method just schedules the view to be appended; the DOM
  18828. element will not be appended to the given element until all bindings have
  18829. finished synchronizing.
  18830. This is not typically a function that you will need to call directly when
  18831. building your application. You might consider using `Ember.ContainerView`
  18832. instead. If you do need to use `appendTo`, be sure that the target element
  18833. you are providing is associated with an `Ember.Application` and does not
  18834. have an ancestor element that is associated with an Ember view.
  18835. @method appendTo
  18836. @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object
  18837. @return {Ember.View} receiver
  18838. */
  18839. appendTo: function(target) {
  18840. // Schedule the DOM element to be created and appended to the given
  18841. // element after bindings have synchronized.
  18842. this._insertElementLater(function() {
  18843. Ember.assert("You tried to append to (" + target + ") but that isn't in the DOM", Ember.$(target).length > 0);
  18844. 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'));
  18845. this.$().appendTo(target);
  18846. });
  18847. return this;
  18848. },
  18849. /**
  18850. Replaces the content of the specified parent element with this view's
  18851. element. If the view does not have an HTML representation yet,
  18852. `createElement()` will be called automatically.
  18853. Note that this method just schedules the view to be appended; the DOM
  18854. element will not be appended to the given element until all bindings have
  18855. finished synchronizing
  18856. @method replaceIn
  18857. @param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object
  18858. @return {Ember.View} received
  18859. */
  18860. replaceIn: function(target) {
  18861. Ember.assert("You tried to replace in (" + target + ") but that isn't in the DOM", Ember.$(target).length > 0);
  18862. 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'));
  18863. this._insertElementLater(function() {
  18864. Ember.$(target).empty();
  18865. this.$().appendTo(target);
  18866. });
  18867. return this;
  18868. },
  18869. /**
  18870. Schedules a DOM operation to occur during the next render phase. This
  18871. ensures that all bindings have finished synchronizing before the view is
  18872. rendered.
  18873. To use, pass a function that performs a DOM operation.
  18874. Before your function is called, this view and all child views will receive
  18875. the `willInsertElement` event. After your function is invoked, this view
  18876. and all of its child views will receive the `didInsertElement` event.
  18877. ```javascript
  18878. view._insertElementLater(function() {
  18879. this.createElement();
  18880. this.$().appendTo('body');
  18881. });
  18882. ```
  18883. @method _insertElementLater
  18884. @param {Function} fn the function that inserts the element into the DOM
  18885. @private
  18886. */
  18887. _insertElementLater: function(fn) {
  18888. this._scheduledInsert = Ember.run.scheduleOnce('render', this, '_insertElement', fn);
  18889. },
  18890. _insertElement: function (fn) {
  18891. this._scheduledInsert = null;
  18892. this.currentState.insertElement(this, fn);
  18893. },
  18894. /**
  18895. Appends the view's element to the document body. If the view does
  18896. not have an HTML representation yet, `createElement()` will be called
  18897. automatically.
  18898. If your application uses the `rootElement` property, you must append
  18899. the view within that element. Rendering views outside of the `rootElement`
  18900. is not supported.
  18901. Note that this method just schedules the view to be appended; the DOM
  18902. element will not be appended to the document body until all bindings have
  18903. finished synchronizing.
  18904. @method append
  18905. @return {Ember.View} receiver
  18906. */
  18907. append: function() {
  18908. return this.appendTo(document.body);
  18909. },
  18910. /**
  18911. Removes the view's element from the element to which it is attached.
  18912. @method remove
  18913. @return {Ember.View} receiver
  18914. */
  18915. remove: function() {
  18916. // What we should really do here is wait until the end of the run loop
  18917. // to determine if the element has been re-appended to a different
  18918. // element.
  18919. // In the interim, we will just re-render if that happens. It is more
  18920. // important than elements get garbage collected.
  18921. if (!this.removedFromDOM) { this.destroyElement(); }
  18922. this.invokeRecursively(function(view) {
  18923. if (view.clearRenderedChildren) { view.clearRenderedChildren(); }
  18924. });
  18925. },
  18926. elementId: null,
  18927. /**
  18928. Attempts to discover the element in the parent element. The default
  18929. implementation looks for an element with an ID of `elementId` (or the
  18930. view's guid if `elementId` is null). You can override this method to
  18931. provide your own form of lookup. For example, if you want to discover your
  18932. element using a CSS class name instead of an ID.
  18933. @method findElementInParentElement
  18934. @param {DOMElement} parentElement The parent's DOM element
  18935. @return {DOMElement} The discovered element
  18936. */
  18937. findElementInParentElement: function(parentElem) {
  18938. var id = "#" + this.elementId;
  18939. return Ember.$(id)[0] || Ember.$(id, parentElem)[0];
  18940. },
  18941. /**
  18942. Creates a DOM representation of the view and all of its
  18943. child views by recursively calling the `render()` method.
  18944. After the element has been created, `didInsertElement` will
  18945. be called on this view and all of its child views.
  18946. @method createElement
  18947. @return {Ember.View} receiver
  18948. */
  18949. createElement: function() {
  18950. if (get(this, 'element')) { return this; }
  18951. var buffer = this.renderToBuffer();
  18952. set(this, 'element', buffer.element());
  18953. return this;
  18954. },
  18955. /**
  18956. Called when a view is going to insert an element into the DOM.
  18957. @event willInsertElement
  18958. */
  18959. willInsertElement: Ember.K,
  18960. /**
  18961. Called when the element of the view has been inserted into the DOM
  18962. or after the view was re-rendered. Override this function to do any
  18963. set up that requires an element in the document body.
  18964. @event didInsertElement
  18965. */
  18966. didInsertElement: Ember.K,
  18967. /**
  18968. Called when the view is about to rerender, but before anything has
  18969. been torn down. This is a good opportunity to tear down any manual
  18970. observers you have installed based on the DOM state
  18971. @event willClearRender
  18972. */
  18973. willClearRender: Ember.K,
  18974. /**
  18975. Run this callback on the current view (unless includeSelf is false) and recursively on child views.
  18976. @method invokeRecursively
  18977. @param fn {Function}
  18978. @param includeSelf {Boolean} Includes itself if true.
  18979. @private
  18980. */
  18981. invokeRecursively: function(fn, includeSelf) {
  18982. var childViews = (includeSelf === false) ? this._childViews : [this];
  18983. var currentViews, view, currentChildViews;
  18984. while (childViews.length) {
  18985. currentViews = childViews.slice();
  18986. childViews = [];
  18987. for (var i=0, l=currentViews.length; i<l; i++) {
  18988. view = currentViews[i];
  18989. currentChildViews = view._childViews ? view._childViews.slice(0) : null;
  18990. fn(view);
  18991. if (currentChildViews) {
  18992. childViews.push.apply(childViews, currentChildViews);
  18993. }
  18994. }
  18995. }
  18996. },
  18997. triggerRecursively: function(eventName) {
  18998. var childViews = [this], currentViews, view, currentChildViews;
  18999. while (childViews.length) {
  19000. currentViews = childViews.slice();
  19001. childViews = [];
  19002. for (var i=0, l=currentViews.length; i<l; i++) {
  19003. view = currentViews[i];
  19004. currentChildViews = view._childViews ? view._childViews.slice(0) : null;
  19005. if (view.trigger) { view.trigger(eventName); }
  19006. if (currentChildViews) {
  19007. childViews.push.apply(childViews, currentChildViews);
  19008. }
  19009. }
  19010. }
  19011. },
  19012. viewHierarchyCollection: function() {
  19013. var currentView, viewCollection = new ViewCollection([this]);
  19014. for (var i = 0; i < viewCollection.length; i++) {
  19015. currentView = viewCollection.objectAt(i);
  19016. if (currentView._childViews) {
  19017. viewCollection.push.apply(viewCollection, currentView._childViews);
  19018. }
  19019. }
  19020. return viewCollection;
  19021. },
  19022. /**
  19023. Destroys any existing element along with the element for any child views
  19024. as well. If the view does not currently have a element, then this method
  19025. will do nothing.
  19026. If you implement `willDestroyElement()` on your view, then this method will
  19027. be invoked on your view before your element is destroyed to give you a
  19028. chance to clean up any event handlers, etc.
  19029. If you write a `willDestroyElement()` handler, you can assume that your
  19030. `didInsertElement()` handler was called earlier for the same element.
  19031. You should not call or override this method yourself, but you may
  19032. want to implement the above callbacks.
  19033. @method destroyElement
  19034. @return {Ember.View} receiver
  19035. */
  19036. destroyElement: function() {
  19037. return this.currentState.destroyElement(this);
  19038. },
  19039. /**
  19040. Called when the element of the view is going to be destroyed. Override
  19041. this function to do any teardown that requires an element, like removing
  19042. event listeners.
  19043. @event willDestroyElement
  19044. */
  19045. willDestroyElement: Ember.K,
  19046. /**
  19047. Triggers the `willDestroyElement` event (which invokes the
  19048. `willDestroyElement()` method if it exists) on this view and all child
  19049. views.
  19050. Before triggering `willDestroyElement`, it first triggers the
  19051. `willClearRender` event recursively.
  19052. @method _notifyWillDestroyElement
  19053. @private
  19054. */
  19055. _notifyWillDestroyElement: function() {
  19056. var viewCollection = this.viewHierarchyCollection();
  19057. viewCollection.trigger('willClearRender');
  19058. viewCollection.trigger('willDestroyElement');
  19059. return viewCollection;
  19060. },
  19061. /**
  19062. If this view's element changes, we need to invalidate the caches of our
  19063. child views so that we do not retain references to DOM elements that are
  19064. no longer needed.
  19065. @method _elementDidChange
  19066. @private
  19067. */
  19068. _elementDidChange: Ember.observer('element', function() {
  19069. this.forEachChildView(function(view) {
  19070. delete meta(view).cache.element;
  19071. });
  19072. }),
  19073. /**
  19074. Called when the parentView property has changed.
  19075. @event parentViewDidChange
  19076. */
  19077. parentViewDidChange: Ember.K,
  19078. instrumentName: 'view',
  19079. instrumentDetails: function(hash) {
  19080. hash.template = get(this, 'templateName');
  19081. this._super(hash);
  19082. },
  19083. _renderToBuffer: function(parentBuffer, bufferOperation) {
  19084. this.lengthBeforeRender = this._childViews.length;
  19085. var buffer = this._super(parentBuffer, bufferOperation);
  19086. this.lengthAfterRender = this._childViews.length;
  19087. return buffer;
  19088. },
  19089. renderToBufferIfNeeded: function (buffer) {
  19090. return this.currentState.renderToBufferIfNeeded(this, buffer);
  19091. },
  19092. beforeRender: function(buffer) {
  19093. this.applyAttributesToBuffer(buffer);
  19094. buffer.pushOpeningTag();
  19095. },
  19096. afterRender: function(buffer) {
  19097. buffer.pushClosingTag();
  19098. },
  19099. applyAttributesToBuffer: function(buffer) {
  19100. // Creates observers for all registered class name and attribute bindings,
  19101. // then adds them to the element.
  19102. var classNameBindings = get(this, 'classNameBindings');
  19103. if (classNameBindings.length) {
  19104. this._applyClassNameBindings(classNameBindings);
  19105. }
  19106. // Pass the render buffer so the method can apply attributes directly.
  19107. // This isn't needed for class name bindings because they use the
  19108. // existing classNames infrastructure.
  19109. var attributeBindings = get(this, 'attributeBindings');
  19110. if (attributeBindings.length) {
  19111. this._applyAttributeBindings(buffer, attributeBindings);
  19112. }
  19113. buffer.setClasses(this.classNames);
  19114. buffer.id(this.elementId);
  19115. var role = get(this, 'ariaRole');
  19116. if (role) {
  19117. buffer.attr('role', role);
  19118. }
  19119. if (get(this, 'isVisible') === false) {
  19120. buffer.style('display', 'none');
  19121. }
  19122. },
  19123. // ..........................................................
  19124. // STANDARD RENDER PROPERTIES
  19125. //
  19126. /**
  19127. Tag name for the view's outer element. The tag name is only used when an
  19128. element is first created. If you change the `tagName` for an element, you
  19129. must destroy and recreate the view element.
  19130. By default, the render buffer will use a `<div>` tag for views.
  19131. @property tagName
  19132. @type String
  19133. @default null
  19134. */
  19135. // We leave this null by default so we can tell the difference between
  19136. // the default case and a user-specified tag.
  19137. tagName: null,
  19138. /**
  19139. The WAI-ARIA role of the control represented by this view. For example, a
  19140. button may have a role of type 'button', or a pane may have a role of
  19141. type 'alertdialog'. This property is used by assistive software to help
  19142. visually challenged users navigate rich web applications.
  19143. The full list of valid WAI-ARIA roles is available at:
  19144. [http://www.w3.org/TR/wai-aria/roles#roles_categorization](http://www.w3.org/TR/wai-aria/roles#roles_categorization)
  19145. @property ariaRole
  19146. @type String
  19147. @default null
  19148. */
  19149. ariaRole: null,
  19150. /**
  19151. Standard CSS class names to apply to the view's outer element. This
  19152. property automatically inherits any class names defined by the view's
  19153. superclasses as well.
  19154. @property classNames
  19155. @type Array
  19156. @default ['ember-view']
  19157. */
  19158. classNames: ['ember-view'],
  19159. /**
  19160. A list of properties of the view to apply as class names. If the property
  19161. is a string value, the value of that string will be applied as a class
  19162. name.
  19163. ```javascript
  19164. // Applies the 'high' class to the view element
  19165. Ember.View.extend({
  19166. classNameBindings: ['priority']
  19167. priority: 'high'
  19168. });
  19169. ```
  19170. If the value of the property is a Boolean, the name of that property is
  19171. added as a dasherized class name.
  19172. ```javascript
  19173. // Applies the 'is-urgent' class to the view element
  19174. Ember.View.extend({
  19175. classNameBindings: ['isUrgent']
  19176. isUrgent: true
  19177. });
  19178. ```
  19179. If you would prefer to use a custom value instead of the dasherized
  19180. property name, you can pass a binding like this:
  19181. ```javascript
  19182. // Applies the 'urgent' class to the view element
  19183. Ember.View.extend({
  19184. classNameBindings: ['isUrgent:urgent']
  19185. isUrgent: true
  19186. });
  19187. ```
  19188. This list of properties is inherited from the view's superclasses as well.
  19189. @property classNameBindings
  19190. @type Array
  19191. @default []
  19192. */
  19193. classNameBindings: EMPTY_ARRAY,
  19194. /**
  19195. A list of properties of the view to apply as attributes. If the property is
  19196. a string value, the value of that string will be applied as the attribute.
  19197. ```javascript
  19198. // Applies the type attribute to the element
  19199. // with the value "button", like <div type="button">
  19200. Ember.View.extend({
  19201. attributeBindings: ['type'],
  19202. type: 'button'
  19203. });
  19204. ```
  19205. If the value of the property is a Boolean, the name of that property is
  19206. added as an attribute.
  19207. ```javascript
  19208. // Renders something like <div enabled="enabled">
  19209. Ember.View.extend({
  19210. attributeBindings: ['enabled'],
  19211. enabled: true
  19212. });
  19213. ```
  19214. @property attributeBindings
  19215. */
  19216. attributeBindings: EMPTY_ARRAY,
  19217. // .......................................................
  19218. // CORE DISPLAY METHODS
  19219. //
  19220. /**
  19221. Setup a view, but do not finish waking it up.
  19222. * configure `childViews`
  19223. * register the view with the global views hash, which is used for event
  19224. dispatch
  19225. @method init
  19226. @private
  19227. */
  19228. init: function() {
  19229. this.elementId = this.elementId || guidFor(this);
  19230. this._super();
  19231. // setup child views. be sure to clone the child views array first
  19232. this._childViews = this._childViews.slice();
  19233. Ember.assert("Only arrays are allowed for 'classNameBindings'", Ember.typeOf(this.classNameBindings) === 'array');
  19234. this.classNameBindings = Ember.A(this.classNameBindings.slice());
  19235. Ember.assert("Only arrays are allowed for 'classNames'", Ember.typeOf(this.classNames) === 'array');
  19236. this.classNames = Ember.A(this.classNames.slice());
  19237. },
  19238. appendChild: function(view, options) {
  19239. return this.currentState.appendChild(this, view, options);
  19240. },
  19241. /**
  19242. Removes the child view from the parent view.
  19243. @method removeChild
  19244. @param {Ember.View} view
  19245. @return {Ember.View} receiver
  19246. */
  19247. removeChild: function(view) {
  19248. // If we're destroying, the entire subtree will be
  19249. // freed, and the DOM will be handled separately,
  19250. // so no need to mess with childViews.
  19251. if (this.isDestroying) { return; }
  19252. // update parent node
  19253. set(view, '_parentView', null);
  19254. // remove view from childViews array.
  19255. var childViews = this._childViews;
  19256. Ember.EnumerableUtils.removeObject(childViews, view);
  19257. this.propertyDidChange('childViews'); // HUH?! what happened to will change?
  19258. return this;
  19259. },
  19260. /**
  19261. Removes all children from the `parentView`.
  19262. @method removeAllChildren
  19263. @return {Ember.View} receiver
  19264. */
  19265. removeAllChildren: function() {
  19266. return this.mutateChildViews(function(parentView, view) {
  19267. parentView.removeChild(view);
  19268. });
  19269. },
  19270. destroyAllChildren: function() {
  19271. return this.mutateChildViews(function(parentView, view) {
  19272. view.destroy();
  19273. });
  19274. },
  19275. /**
  19276. Removes the view from its `parentView`, if one is found. Otherwise
  19277. does nothing.
  19278. @method removeFromParent
  19279. @return {Ember.View} receiver
  19280. */
  19281. removeFromParent: function() {
  19282. var parent = this._parentView;
  19283. // Remove DOM element from parent
  19284. this.remove();
  19285. if (parent) { parent.removeChild(this); }
  19286. return this;
  19287. },
  19288. /**
  19289. You must call `destroy` on a view to destroy the view (and all of its
  19290. child views). This will remove the view from any parent node, then make
  19291. sure that the DOM element managed by the view can be released by the
  19292. memory manager.
  19293. @method destroy
  19294. */
  19295. destroy: function() {
  19296. var childViews = this._childViews,
  19297. // get parentView before calling super because it'll be destroyed
  19298. nonVirtualParentView = get(this, 'parentView'),
  19299. viewName = this.viewName,
  19300. childLen, i;
  19301. if (!this._super()) { return; }
  19302. childLen = childViews.length;
  19303. for (i=childLen-1; i>=0; i--) {
  19304. childViews[i].removedFromDOM = true;
  19305. }
  19306. // remove from non-virtual parent view if viewName was specified
  19307. if (viewName && nonVirtualParentView) {
  19308. nonVirtualParentView.set(viewName, null);
  19309. }
  19310. childLen = childViews.length;
  19311. for (i=childLen-1; i>=0; i--) {
  19312. childViews[i].destroy();
  19313. }
  19314. return this;
  19315. },
  19316. /**
  19317. Instantiates a view to be added to the childViews array during view
  19318. initialization. You generally will not call this method directly unless
  19319. you are overriding `createChildViews()`. Note that this method will
  19320. automatically configure the correct settings on the new view instance to
  19321. act as a child of the parent.
  19322. @method createChildView
  19323. @param {Class|String} viewClass
  19324. @param {Hash} [attrs] Attributes to add
  19325. @return {Ember.View} new instance
  19326. */
  19327. createChildView: function(view, attrs) {
  19328. if (!view) {
  19329. throw new TypeError("createChildViews first argument must exist");
  19330. }
  19331. if (view.isView && view._parentView === this && view.container === this.container) {
  19332. return view;
  19333. }
  19334. attrs = attrs || {};
  19335. attrs._parentView = this;
  19336. if (Ember.CoreView.detect(view)) {
  19337. attrs.templateData = attrs.templateData || get(this, 'templateData');
  19338. attrs.container = this.container;
  19339. view = view.create(attrs);
  19340. // don't set the property on a virtual view, as they are invisible to
  19341. // consumers of the view API
  19342. if (view.viewName) {
  19343. set(get(this, 'concreteView'), view.viewName, view);
  19344. }
  19345. } else if ('string' === typeof view) {
  19346. var fullName = 'view:' + view;
  19347. var View = this.container.lookupFactory(fullName);
  19348. Ember.assert("Could not find view: '" + fullName + "'", !!View);
  19349. attrs.templateData = get(this, 'templateData');
  19350. view = View.create(attrs);
  19351. } else {
  19352. Ember.assert('You must pass instance or subclass of View', view.isView);
  19353. attrs.container = this.container;
  19354. if (!get(view, 'templateData')) {
  19355. attrs.templateData = get(this, 'templateData');
  19356. }
  19357. Ember.setProperties(view, attrs);
  19358. }
  19359. return view;
  19360. },
  19361. becameVisible: Ember.K,
  19362. becameHidden: Ember.K,
  19363. /**
  19364. When the view's `isVisible` property changes, toggle the visibility
  19365. element of the actual DOM element.
  19366. @method _isVisibleDidChange
  19367. @private
  19368. */
  19369. _isVisibleDidChange: Ember.observer('isVisible', function() {
  19370. var $el = this.$();
  19371. if (!$el) { return; }
  19372. var isVisible = get(this, 'isVisible');
  19373. $el.toggle(isVisible);
  19374. if (this._isAncestorHidden()) { return; }
  19375. if (isVisible) {
  19376. this._notifyBecameVisible();
  19377. } else {
  19378. this._notifyBecameHidden();
  19379. }
  19380. }),
  19381. _notifyBecameVisible: function() {
  19382. this.trigger('becameVisible');
  19383. this.forEachChildView(function(view) {
  19384. var isVisible = get(view, 'isVisible');
  19385. if (isVisible || isVisible === null) {
  19386. view._notifyBecameVisible();
  19387. }
  19388. });
  19389. },
  19390. _notifyBecameHidden: function() {
  19391. this.trigger('becameHidden');
  19392. this.forEachChildView(function(view) {
  19393. var isVisible = get(view, 'isVisible');
  19394. if (isVisible || isVisible === null) {
  19395. view._notifyBecameHidden();
  19396. }
  19397. });
  19398. },
  19399. _isAncestorHidden: function() {
  19400. var parent = get(this, 'parentView');
  19401. while (parent) {
  19402. if (get(parent, 'isVisible') === false) { return true; }
  19403. parent = get(parent, 'parentView');
  19404. }
  19405. return false;
  19406. },
  19407. clearBuffer: function() {
  19408. this.invokeRecursively(function(view) {
  19409. view.buffer = null;
  19410. });
  19411. },
  19412. transitionTo: function(state, children) {
  19413. var priorState = this.currentState,
  19414. currentState = this.currentState = this.states[state];
  19415. this.state = state;
  19416. if (priorState && priorState.exit) { priorState.exit(this); }
  19417. if (currentState.enter) { currentState.enter(this); }
  19418. if (state === 'inDOM') { delete Ember.meta(this).cache.element; }
  19419. if (children !== false) {
  19420. this.forEachChildView(function(view) {
  19421. view.transitionTo(state);
  19422. });
  19423. }
  19424. },
  19425. // .......................................................
  19426. // EVENT HANDLING
  19427. //
  19428. /**
  19429. Handle events from `Ember.EventDispatcher`
  19430. @method handleEvent
  19431. @param eventName {String}
  19432. @param evt {Event}
  19433. @private
  19434. */
  19435. handleEvent: function(eventName, evt) {
  19436. return this.currentState.handleEvent(this, eventName, evt);
  19437. },
  19438. registerObserver: function(root, path, target, observer) {
  19439. if (!observer && 'function' === typeof target) {
  19440. observer = target;
  19441. target = null;
  19442. }
  19443. if (!root || typeof root !== 'object') {
  19444. return;
  19445. }
  19446. var view = this,
  19447. stateCheckedObserver = function() {
  19448. view.currentState.invokeObserver(this, observer);
  19449. },
  19450. scheduledObserver = function() {
  19451. Ember.run.scheduleOnce('render', this, stateCheckedObserver);
  19452. };
  19453. Ember.addObserver(root, path, target, scheduledObserver);
  19454. this.one('willClearRender', function() {
  19455. Ember.removeObserver(root, path, target, scheduledObserver);
  19456. });
  19457. }
  19458. });
  19459. /*
  19460. Describe how the specified actions should behave in the various
  19461. states that a view can exist in. Possible states:
  19462. * preRender: when a view is first instantiated, and after its
  19463. element was destroyed, it is in the preRender state
  19464. * inBuffer: once a view has been rendered, but before it has
  19465. been inserted into the DOM, it is in the inBuffer state
  19466. * hasElement: the DOM representation of the view is created,
  19467. and is ready to be inserted
  19468. * inDOM: once a view has been inserted into the DOM it is in
  19469. the inDOM state. A view spends the vast majority of its
  19470. existence in this state.
  19471. * destroyed: once a view has been destroyed (using the destroy
  19472. method), it is in this state. No further actions can be invoked
  19473. on a destroyed view.
  19474. */
  19475. // in the destroyed state, everything is illegal
  19476. // before rendering has begun, all legal manipulations are noops.
  19477. // inside the buffer, legal manipulations are done on the buffer
  19478. // once the view has been inserted into the DOM, legal manipulations
  19479. // are done on the DOM element.
  19480. function notifyMutationListeners() {
  19481. Ember.run.once(Ember.View, 'notifyMutationListeners');
  19482. }
  19483. var DOMManager = {
  19484. prepend: function(view, html) {
  19485. view.$().prepend(html);
  19486. notifyMutationListeners();
  19487. },
  19488. after: function(view, html) {
  19489. view.$().after(html);
  19490. notifyMutationListeners();
  19491. },
  19492. html: function(view, html) {
  19493. view.$().html(html);
  19494. notifyMutationListeners();
  19495. },
  19496. replace: function(view) {
  19497. var element = get(view, 'element');
  19498. set(view, 'element', null);
  19499. view._insertElementLater(function() {
  19500. Ember.$(element).replaceWith(get(view, 'element'));
  19501. notifyMutationListeners();
  19502. });
  19503. },
  19504. remove: function(view) {
  19505. view.$().remove();
  19506. notifyMutationListeners();
  19507. },
  19508. empty: function(view) {
  19509. view.$().empty();
  19510. notifyMutationListeners();
  19511. }
  19512. };
  19513. Ember.View.reopen({
  19514. domManager: DOMManager
  19515. });
  19516. Ember.View.reopenClass({
  19517. /**
  19518. Parse a path and return an object which holds the parsed properties.
  19519. For example a path like "content.isEnabled:enabled:disabled" will return the
  19520. following object:
  19521. ```javascript
  19522. {
  19523. path: "content.isEnabled",
  19524. className: "enabled",
  19525. falsyClassName: "disabled",
  19526. classNames: ":enabled:disabled"
  19527. }
  19528. ```
  19529. @method _parsePropertyPath
  19530. @static
  19531. @private
  19532. */
  19533. _parsePropertyPath: function(path) {
  19534. var split = path.split(':'),
  19535. propertyPath = split[0],
  19536. classNames = "",
  19537. className,
  19538. falsyClassName;
  19539. // check if the property is defined as prop:class or prop:trueClass:falseClass
  19540. if (split.length > 1) {
  19541. className = split[1];
  19542. if (split.length === 3) { falsyClassName = split[2]; }
  19543. classNames = ':' + className;
  19544. if (falsyClassName) { classNames += ":" + falsyClassName; }
  19545. }
  19546. return {
  19547. path: propertyPath,
  19548. classNames: classNames,
  19549. className: (className === '') ? undefined : className,
  19550. falsyClassName: falsyClassName
  19551. };
  19552. },
  19553. /**
  19554. Get the class name for a given value, based on the path, optional
  19555. `className` and optional `falsyClassName`.
  19556. - if a `className` or `falsyClassName` has been specified:
  19557. - if the value is truthy and `className` has been specified,
  19558. `className` is returned
  19559. - if the value is falsy and `falsyClassName` has been specified,
  19560. `falsyClassName` is returned
  19561. - otherwise `null` is returned
  19562. - if the value is `true`, the dasherized last part of the supplied path
  19563. is returned
  19564. - if the value is not `false`, `undefined` or `null`, the `value`
  19565. is returned
  19566. - if none of the above rules apply, `null` is returned
  19567. @method _classStringForValue
  19568. @param path
  19569. @param val
  19570. @param className
  19571. @param falsyClassName
  19572. @static
  19573. @private
  19574. */
  19575. _classStringForValue: function(path, val, className, falsyClassName) {
  19576. // When using the colon syntax, evaluate the truthiness or falsiness
  19577. // of the value to determine which className to return
  19578. if (className || falsyClassName) {
  19579. if (className && !!val) {
  19580. return className;
  19581. } else if (falsyClassName && !val) {
  19582. return falsyClassName;
  19583. } else {
  19584. return null;
  19585. }
  19586. // If value is a Boolean and true, return the dasherized property
  19587. // name.
  19588. } else if (val === true) {
  19589. // Normalize property path to be suitable for use
  19590. // as a class name. For exaple, content.foo.barBaz
  19591. // becomes bar-baz.
  19592. var parts = path.split('.');
  19593. return Ember.String.dasherize(parts[parts.length-1]);
  19594. // If the value is not false, undefined, or null, return the current
  19595. // value of the property.
  19596. } else if (val !== false && val != null) {
  19597. return val;
  19598. // Nothing to display. Return null so that the old class is removed
  19599. // but no new class is added.
  19600. } else {
  19601. return null;
  19602. }
  19603. }
  19604. });
  19605. var mutation = Ember.Object.extend(Ember.Evented).create();
  19606. Ember.View.addMutationListener = function(callback) {
  19607. mutation.on('change', callback);
  19608. };
  19609. Ember.View.removeMutationListener = function(callback) {
  19610. mutation.off('change', callback);
  19611. };
  19612. Ember.View.notifyMutationListeners = function() {
  19613. mutation.trigger('change');
  19614. };
  19615. /**
  19616. Global views hash
  19617. @property views
  19618. @static
  19619. @type Hash
  19620. */
  19621. Ember.View.views = {};
  19622. // If someone overrides the child views computed property when
  19623. // defining their class, we want to be able to process the user's
  19624. // supplied childViews and then restore the original computed property
  19625. // at view initialization time. This happens in Ember.ContainerView's init
  19626. // method.
  19627. Ember.View.childViewsProperty = childViewsProperty;
  19628. Ember.View.applyAttributeBindings = function(elem, name, value) {
  19629. var type = Ember.typeOf(value);
  19630. // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js
  19631. if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) {
  19632. if (value !== elem.attr(name)) {
  19633. elem.attr(name, value);
  19634. }
  19635. } else if (name === 'value' || type === 'boolean') {
  19636. if (Ember.isNone(value) || value === false) {
  19637. // `null`, `undefined` or `false` should remove attribute
  19638. elem.removeAttr(name);
  19639. elem.prop(name, '');
  19640. } else if (value !== elem.prop(name)) {
  19641. // value should always be properties
  19642. elem.prop(name, value);
  19643. }
  19644. } else if (!value) {
  19645. elem.removeAttr(name);
  19646. }
  19647. };
  19648. Ember.View.states = states;
  19649. })();
  19650. (function() {
  19651. /**
  19652. @module ember
  19653. @submodule ember-views
  19654. */
  19655. var get = Ember.get, set = Ember.set;
  19656. Ember.View.states._default = {
  19657. // appendChild is only legal while rendering the buffer.
  19658. appendChild: function() {
  19659. throw "You can't use appendChild outside of the rendering process";
  19660. },
  19661. $: function() {
  19662. return undefined;
  19663. },
  19664. getElement: function() {
  19665. return null;
  19666. },
  19667. // Handle events from `Ember.EventDispatcher`
  19668. handleEvent: function() {
  19669. return true; // continue event propagation
  19670. },
  19671. destroyElement: function(view) {
  19672. set(view, 'element', null);
  19673. if (view._scheduledInsert) {
  19674. Ember.run.cancel(view._scheduledInsert);
  19675. view._scheduledInsert = null;
  19676. }
  19677. return view;
  19678. },
  19679. renderToBufferIfNeeded: function () {
  19680. return false;
  19681. },
  19682. rerender: Ember.K,
  19683. invokeObserver: Ember.K
  19684. };
  19685. })();
  19686. (function() {
  19687. /**
  19688. @module ember
  19689. @submodule ember-views
  19690. */
  19691. var preRender = Ember.View.states.preRender = Ember.create(Ember.View.states._default);
  19692. Ember.merge(preRender, {
  19693. // a view leaves the preRender state once its element has been
  19694. // created (createElement).
  19695. insertElement: function(view, fn) {
  19696. view.createElement();
  19697. var viewCollection = view.viewHierarchyCollection();
  19698. viewCollection.trigger('willInsertElement');
  19699. fn.call(view);
  19700. // We transition to `inDOM` if the element exists in the DOM
  19701. var element = view.get('element');
  19702. while (element = element.parentNode) {
  19703. if (element === document) {
  19704. viewCollection.transitionTo('inDOM', false);
  19705. viewCollection.trigger('didInsertElement');
  19706. }
  19707. }
  19708. },
  19709. renderToBufferIfNeeded: function(view, buffer) {
  19710. view.renderToBuffer(buffer);
  19711. return true;
  19712. },
  19713. empty: Ember.K,
  19714. setElement: function(view, value) {
  19715. if (value !== null) {
  19716. view.transitionTo('hasElement');
  19717. }
  19718. return value;
  19719. }
  19720. });
  19721. })();
  19722. (function() {
  19723. /**
  19724. @module ember
  19725. @submodule ember-views
  19726. */
  19727. var get = Ember.get, set = Ember.set;
  19728. var inBuffer = Ember.View.states.inBuffer = Ember.create(Ember.View.states._default);
  19729. Ember.merge(inBuffer, {
  19730. $: function(view, sel) {
  19731. // if we don't have an element yet, someone calling this.$() is
  19732. // trying to update an element that isn't in the DOM. Instead,
  19733. // rerender the view to allow the render method to reflect the
  19734. // changes.
  19735. view.rerender();
  19736. return Ember.$();
  19737. },
  19738. // when a view is rendered in a buffer, rerendering it simply
  19739. // replaces the existing buffer with a new one
  19740. rerender: function(view) {
  19741. throw new Ember.Error("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.");
  19742. },
  19743. // when a view is rendered in a buffer, appending a child
  19744. // view will render that view and append the resulting
  19745. // buffer into its buffer.
  19746. appendChild: function(view, childView, options) {
  19747. var buffer = view.buffer, _childViews = view._childViews;
  19748. childView = view.createChildView(childView, options);
  19749. if (!_childViews.length) { _childViews = view._childViews = _childViews.slice(); }
  19750. _childViews.push(childView);
  19751. childView.renderToBuffer(buffer);
  19752. view.propertyDidChange('childViews');
  19753. return childView;
  19754. },
  19755. // when a view is rendered in a buffer, destroying the
  19756. // element will simply destroy the buffer and put the
  19757. // state back into the preRender state.
  19758. destroyElement: function(view) {
  19759. view.clearBuffer();
  19760. var viewCollection = view._notifyWillDestroyElement();
  19761. viewCollection.transitionTo('preRender', false);
  19762. return view;
  19763. },
  19764. empty: function() {
  19765. Ember.assert("Emptying a view in the inBuffer state is not allowed and " +
  19766. "should not happen under normal circumstances. Most likely " +
  19767. "there is a bug in your application. This may be due to " +
  19768. "excessive property change notifications.");
  19769. },
  19770. renderToBufferIfNeeded: function (view, buffer) {
  19771. return false;
  19772. },
  19773. // It should be impossible for a rendered view to be scheduled for
  19774. // insertion.
  19775. insertElement: function() {
  19776. throw "You can't insert an element that has already been rendered";
  19777. },
  19778. setElement: function(view, value) {
  19779. if (value === null) {
  19780. view.transitionTo('preRender');
  19781. } else {
  19782. view.clearBuffer();
  19783. view.transitionTo('hasElement');
  19784. }
  19785. return value;
  19786. },
  19787. invokeObserver: function(target, observer) {
  19788. observer.call(target);
  19789. }
  19790. });
  19791. })();
  19792. (function() {
  19793. /**
  19794. @module ember
  19795. @submodule ember-views
  19796. */
  19797. var get = Ember.get, set = Ember.set;
  19798. var hasElement = Ember.View.states.hasElement = Ember.create(Ember.View.states._default);
  19799. Ember.merge(hasElement, {
  19800. $: function(view, sel) {
  19801. var elem = get(view, 'element');
  19802. return sel ? Ember.$(sel, elem) : Ember.$(elem);
  19803. },
  19804. getElement: function(view) {
  19805. var parent = get(view, 'parentView');
  19806. if (parent) { parent = get(parent, 'element'); }
  19807. if (parent) { return view.findElementInParentElement(parent); }
  19808. return Ember.$("#" + get(view, 'elementId'))[0];
  19809. },
  19810. setElement: function(view, value) {
  19811. if (value === null) {
  19812. view.transitionTo('preRender');
  19813. } else {
  19814. throw "You cannot set an element to a non-null value when the element is already in the DOM.";
  19815. }
  19816. return value;
  19817. },
  19818. // once the view has been inserted into the DOM, rerendering is
  19819. // deferred to allow bindings to synchronize.
  19820. rerender: function(view) {
  19821. view.triggerRecursively('willClearRender');
  19822. view.clearRenderedChildren();
  19823. view.domManager.replace(view);
  19824. return view;
  19825. },
  19826. // once the view is already in the DOM, destroying it removes it
  19827. // from the DOM, nukes its element, and puts it back into the
  19828. // preRender state if inDOM.
  19829. destroyElement: function(view) {
  19830. view._notifyWillDestroyElement();
  19831. view.domManager.remove(view);
  19832. set(view, 'element', null);
  19833. if (view._scheduledInsert) {
  19834. Ember.run.cancel(view._scheduledInsert);
  19835. view._scheduledInsert = null;
  19836. }
  19837. return view;
  19838. },
  19839. empty: function(view) {
  19840. var _childViews = view._childViews, len, idx;
  19841. if (_childViews) {
  19842. len = _childViews.length;
  19843. for (idx = 0; idx < len; idx++) {
  19844. _childViews[idx]._notifyWillDestroyElement();
  19845. }
  19846. }
  19847. view.domManager.empty(view);
  19848. },
  19849. // Handle events from `Ember.EventDispatcher`
  19850. handleEvent: function(view, eventName, evt) {
  19851. if (view.has(eventName)) {
  19852. // Handler should be able to re-dispatch events, so we don't
  19853. // preventDefault or stopPropagation.
  19854. return view.trigger(eventName, evt);
  19855. } else {
  19856. return true; // continue event propagation
  19857. }
  19858. },
  19859. invokeObserver: function(target, observer) {
  19860. observer.call(target);
  19861. }
  19862. });
  19863. })();
  19864. (function() {
  19865. /**
  19866. @module ember
  19867. @submodule ember-views
  19868. */
  19869. var hasElement = Ember.View.states.hasElement;
  19870. var inDOM = Ember.View.states.inDOM = Ember.create(hasElement);
  19871. Ember.merge(inDOM, {
  19872. enter: function(view) {
  19873. // Register the view for event handling. This hash is used by
  19874. // Ember.EventDispatcher to dispatch incoming events.
  19875. if (!view.isVirtual) {
  19876. Ember.assert("Attempted to register a view with an id already in use: "+view.elementId, !Ember.View.views[view.elementId]);
  19877. Ember.View.views[view.elementId] = view;
  19878. }
  19879. view.addBeforeObserver('elementId', function() {
  19880. throw new Ember.Error("Changing a view's elementId after creation is not allowed");
  19881. });
  19882. },
  19883. exit: function(view) {
  19884. if (!this.isVirtual) delete Ember.View.views[view.elementId];
  19885. },
  19886. insertElement: function(view, fn) {
  19887. throw "You can't insert an element into the DOM that has already been inserted";
  19888. }
  19889. });
  19890. })();
  19891. (function() {
  19892. /**
  19893. @module ember
  19894. @submodule ember-views
  19895. */
  19896. var destroyingError = "You can't call %@ on a view being destroyed", fmt = Ember.String.fmt;
  19897. var destroying = Ember.View.states.destroying = Ember.create(Ember.View.states._default);
  19898. Ember.merge(destroying, {
  19899. appendChild: function() {
  19900. throw fmt(destroyingError, ['appendChild']);
  19901. },
  19902. rerender: function() {
  19903. throw fmt(destroyingError, ['rerender']);
  19904. },
  19905. destroyElement: function() {
  19906. throw fmt(destroyingError, ['destroyElement']);
  19907. },
  19908. empty: function() {
  19909. throw fmt(destroyingError, ['empty']);
  19910. },
  19911. setElement: function() {
  19912. throw fmt(destroyingError, ["set('element', ...)"]);
  19913. },
  19914. renderToBufferIfNeeded: function() {
  19915. return false;
  19916. },
  19917. // Since element insertion is scheduled, don't do anything if
  19918. // the view has been destroyed between scheduling and execution
  19919. insertElement: Ember.K
  19920. });
  19921. })();
  19922. (function() {
  19923. Ember.View.cloneStates = function(from) {
  19924. var into = {};
  19925. into._default = {};
  19926. into.preRender = Ember.create(into._default);
  19927. into.destroying = Ember.create(into._default);
  19928. into.inBuffer = Ember.create(into._default);
  19929. into.hasElement = Ember.create(into._default);
  19930. into.inDOM = Ember.create(into.hasElement);
  19931. for (var stateName in from) {
  19932. if (!from.hasOwnProperty(stateName)) { continue; }
  19933. Ember.merge(into[stateName], from[stateName]);
  19934. }
  19935. return into;
  19936. };
  19937. })();
  19938. (function() {
  19939. var states = Ember.View.cloneStates(Ember.View.states);
  19940. /**
  19941. @module ember
  19942. @submodule ember-views
  19943. */
  19944. var get = Ember.get, set = Ember.set;
  19945. var forEach = Ember.EnumerableUtils.forEach;
  19946. var ViewCollection = Ember._ViewCollection;
  19947. /**
  19948. A `ContainerView` is an `Ember.View` subclass that implements `Ember.MutableArray`
  19949. allowing programmatic management of its child views.
  19950. ## Setting Initial Child Views
  19951. The initial array of child views can be set in one of two ways. You can
  19952. provide a `childViews` property at creation time that contains instance of
  19953. `Ember.View`:
  19954. ```javascript
  19955. aContainer = Ember.ContainerView.create({
  19956. childViews: [Ember.View.create(), Ember.View.create()]
  19957. });
  19958. ```
  19959. You can also provide a list of property names whose values are instances of
  19960. `Ember.View`:
  19961. ```javascript
  19962. aContainer = Ember.ContainerView.create({
  19963. childViews: ['aView', 'bView', 'cView'],
  19964. aView: Ember.View.create(),
  19965. bView: Ember.View.create(),
  19966. cView: Ember.View.create()
  19967. });
  19968. ```
  19969. The two strategies can be combined:
  19970. ```javascript
  19971. aContainer = Ember.ContainerView.create({
  19972. childViews: ['aView', Ember.View.create()],
  19973. aView: Ember.View.create()
  19974. });
  19975. ```
  19976. Each child view's rendering will be inserted into the container's rendered
  19977. HTML in the same order as its position in the `childViews` property.
  19978. ## Adding and Removing Child Views
  19979. The container view implements `Ember.MutableArray` allowing programmatic management of its child views.
  19980. To remove a view, pass that view into a `removeObject` call on the container view.
  19981. Given an empty `<body>` the following code
  19982. ```javascript
  19983. aContainer = Ember.ContainerView.create({
  19984. classNames: ['the-container'],
  19985. childViews: ['aView', 'bView'],
  19986. aView: Ember.View.create({
  19987. template: Ember.Handlebars.compile("A")
  19988. }),
  19989. bView: Ember.View.create({
  19990. template: Ember.Handlebars.compile("B")
  19991. })
  19992. });
  19993. aContainer.appendTo('body');
  19994. ```
  19995. Results in the HTML
  19996. ```html
  19997. <div class="ember-view the-container">
  19998. <div class="ember-view">A</div>
  19999. <div class="ember-view">B</div>
  20000. </div>
  20001. ```
  20002. Removing a view
  20003. ```javascript
  20004. aContainer.toArray(); // [aContainer.aView, aContainer.bView]
  20005. aContainer.removeObject(aContainer.get('bView'));
  20006. aContainer.toArray(); // [aContainer.aView]
  20007. ```
  20008. Will result in the following HTML
  20009. ```html
  20010. <div class="ember-view the-container">
  20011. <div class="ember-view">A</div>
  20012. </div>
  20013. ```
  20014. Similarly, adding a child view is accomplished by adding `Ember.View` instances to the
  20015. container view.
  20016. Given an empty `<body>` the following code
  20017. ```javascript
  20018. aContainer = Ember.ContainerView.create({
  20019. classNames: ['the-container'],
  20020. childViews: ['aView', 'bView'],
  20021. aView: Ember.View.create({
  20022. template: Ember.Handlebars.compile("A")
  20023. }),
  20024. bView: Ember.View.create({
  20025. template: Ember.Handlebars.compile("B")
  20026. })
  20027. });
  20028. aContainer.appendTo('body');
  20029. ```
  20030. Results in the HTML
  20031. ```html
  20032. <div class="ember-view the-container">
  20033. <div class="ember-view">A</div>
  20034. <div class="ember-view">B</div>
  20035. </div>
  20036. ```
  20037. Adding a view
  20038. ```javascript
  20039. AnotherViewClass = Ember.View.extend({
  20040. template: Ember.Handlebars.compile("Another view")
  20041. });
  20042. aContainer.toArray(); // [aContainer.aView, aContainer.bView]
  20043. aContainer.pushObject(AnotherViewClass.create());
  20044. aContainer.toArray(); // [aContainer.aView, aContainer.bView, <AnotherViewClass instance>]
  20045. ```
  20046. Will result in the following HTML
  20047. ```html
  20048. <div class="ember-view the-container">
  20049. <div class="ember-view">A</div>
  20050. <div class="ember-view">B</div>
  20051. <div class="ember-view">Another view</div>
  20052. </div>
  20053. ```
  20054. ## Templates and Layout
  20055. A `template`, `templateName`, `defaultTemplate`, `layout`, `layoutName` or
  20056. `defaultLayout` property on a container view will not result in the template
  20057. or layout being rendered. The HTML contents of a `Ember.ContainerView`'s DOM
  20058. representation will only be the rendered HTML of its child views.
  20059. @class ContainerView
  20060. @namespace Ember
  20061. @extends Ember.View
  20062. */
  20063. Ember.ContainerView = Ember.View.extend(Ember.MutableArray, {
  20064. states: states,
  20065. init: function() {
  20066. this._super();
  20067. var childViews = get(this, 'childViews');
  20068. // redefine view's childViews property that was obliterated
  20069. Ember.defineProperty(this, 'childViews', Ember.View.childViewsProperty);
  20070. var _childViews = this._childViews;
  20071. forEach(childViews, function(viewName, idx) {
  20072. var view;
  20073. if ('string' === typeof viewName) {
  20074. view = get(this, viewName);
  20075. view = this.createChildView(view);
  20076. set(this, viewName, view);
  20077. } else {
  20078. view = this.createChildView(viewName);
  20079. }
  20080. _childViews[idx] = view;
  20081. }, this);
  20082. var currentView = get(this, 'currentView');
  20083. if (currentView) {
  20084. if (!_childViews.length) { _childViews = this._childViews = this._childViews.slice(); }
  20085. _childViews.push(this.createChildView(currentView));
  20086. }
  20087. },
  20088. replace: function(idx, removedCount, addedViews) {
  20089. var addedCount = addedViews ? get(addedViews, 'length') : 0;
  20090. var self = this;
  20091. Ember.assert("You can't add a child to a container that is already a child of another view", Ember.A(addedViews).every(function(item) { return !get(item, '_parentView') || get(item, '_parentView') === self; }));
  20092. this.arrayContentWillChange(idx, removedCount, addedCount);
  20093. this.childViewsWillChange(this._childViews, idx, removedCount);
  20094. if (addedCount === 0) {
  20095. this._childViews.splice(idx, removedCount) ;
  20096. } else {
  20097. var args = [idx, removedCount].concat(addedViews);
  20098. if (addedViews.length && !this._childViews.length) { this._childViews = this._childViews.slice(); }
  20099. this._childViews.splice.apply(this._childViews, args);
  20100. }
  20101. this.arrayContentDidChange(idx, removedCount, addedCount);
  20102. this.childViewsDidChange(this._childViews, idx, removedCount, addedCount);
  20103. return this;
  20104. },
  20105. objectAt: function(idx) {
  20106. return this._childViews[idx];
  20107. },
  20108. length: Ember.computed(function () {
  20109. return this._childViews.length;
  20110. }).volatile(),
  20111. /**
  20112. Instructs each child view to render to the passed render buffer.
  20113. @private
  20114. @method render
  20115. @param {Ember.RenderBuffer} buffer the buffer to render to
  20116. */
  20117. render: function(buffer) {
  20118. this.forEachChildView(function(view) {
  20119. view.renderToBuffer(buffer);
  20120. });
  20121. },
  20122. instrumentName: 'container',
  20123. /**
  20124. When a child view is removed, destroy its element so that
  20125. it is removed from the DOM.
  20126. The array observer that triggers this action is set up in the
  20127. `renderToBuffer` method.
  20128. @private
  20129. @method childViewsWillChange
  20130. @param {Ember.Array} views the child views array before mutation
  20131. @param {Number} start the start position of the mutation
  20132. @param {Number} removed the number of child views removed
  20133. **/
  20134. childViewsWillChange: function(views, start, removed) {
  20135. this.propertyWillChange('childViews');
  20136. if (removed > 0) {
  20137. var changedViews = views.slice(start, start+removed);
  20138. // transition to preRender before clearing parentView
  20139. this.currentState.childViewsWillChange(this, views, start, removed);
  20140. this.initializeViews(changedViews, null, null);
  20141. }
  20142. },
  20143. removeChild: function(child) {
  20144. this.removeObject(child);
  20145. return this;
  20146. },
  20147. /**
  20148. When a child view is added, make sure the DOM gets updated appropriately.
  20149. If the view has already rendered an element, we tell the child view to
  20150. create an element and insert it into the DOM. If the enclosing container
  20151. view has already written to a buffer, but not yet converted that buffer
  20152. into an element, we insert the string representation of the child into the
  20153. appropriate place in the buffer.
  20154. @private
  20155. @method childViewsDidChange
  20156. @param {Ember.Array} views the array of child views afte the mutation has occurred
  20157. @param {Number} start the start position of the mutation
  20158. @param {Number} removed the number of child views removed
  20159. @param {Number} the number of child views added
  20160. */
  20161. childViewsDidChange: function(views, start, removed, added) {
  20162. if (added > 0) {
  20163. var changedViews = views.slice(start, start+added);
  20164. this.initializeViews(changedViews, this, get(this, 'templateData'));
  20165. this.currentState.childViewsDidChange(this, views, start, added);
  20166. }
  20167. this.propertyDidChange('childViews');
  20168. },
  20169. initializeViews: function(views, parentView, templateData) {
  20170. forEach(views, function(view) {
  20171. set(view, '_parentView', parentView);
  20172. if (!view.container && parentView) {
  20173. set(view, 'container', parentView.container);
  20174. }
  20175. if (!get(view, 'templateData')) {
  20176. set(view, 'templateData', templateData);
  20177. }
  20178. });
  20179. },
  20180. currentView: null,
  20181. _currentViewWillChange: Ember.beforeObserver('currentView', function() {
  20182. var currentView = get(this, 'currentView');
  20183. if (currentView) {
  20184. currentView.destroy();
  20185. }
  20186. }),
  20187. _currentViewDidChange: Ember.observer('currentView', function() {
  20188. var currentView = get(this, 'currentView');
  20189. if (currentView) {
  20190. Ember.assert("You tried to set a current view that already has a parent. Make sure you don't have multiple outlets in the same view.", !get(currentView, '_parentView'));
  20191. this.pushObject(currentView);
  20192. }
  20193. }),
  20194. _ensureChildrenAreInDOM: function () {
  20195. this.currentState.ensureChildrenAreInDOM(this);
  20196. }
  20197. });
  20198. Ember.merge(states._default, {
  20199. childViewsWillChange: Ember.K,
  20200. childViewsDidChange: Ember.K,
  20201. ensureChildrenAreInDOM: Ember.K
  20202. });
  20203. Ember.merge(states.inBuffer, {
  20204. childViewsDidChange: function(parentView, views, start, added) {
  20205. throw new Ember.Error('You cannot modify child views while in the inBuffer state');
  20206. }
  20207. });
  20208. Ember.merge(states.hasElement, {
  20209. childViewsWillChange: function(view, views, start, removed) {
  20210. for (var i=start; i<start+removed; i++) {
  20211. views[i].remove();
  20212. }
  20213. },
  20214. childViewsDidChange: function(view, views, start, added) {
  20215. Ember.run.scheduleOnce('render', view, '_ensureChildrenAreInDOM');
  20216. },
  20217. ensureChildrenAreInDOM: function(view) {
  20218. var childViews = view._childViews, i, len, childView, previous, buffer, viewCollection = new ViewCollection();
  20219. for (i = 0, len = childViews.length; i < len; i++) {
  20220. childView = childViews[i];
  20221. if (!buffer) { buffer = Ember.RenderBuffer(); buffer._hasElement = false; }
  20222. if (childView.renderToBufferIfNeeded(buffer)) {
  20223. viewCollection.push(childView);
  20224. } else if (viewCollection.length) {
  20225. insertViewCollection(view, viewCollection, previous, buffer);
  20226. buffer = null;
  20227. previous = childView;
  20228. viewCollection.clear();
  20229. } else {
  20230. previous = childView;
  20231. }
  20232. }
  20233. if (viewCollection.length) {
  20234. insertViewCollection(view, viewCollection, previous, buffer);
  20235. }
  20236. }
  20237. });
  20238. function insertViewCollection(view, viewCollection, previous, buffer) {
  20239. viewCollection.triggerRecursively('willInsertElement');
  20240. if (previous) {
  20241. previous.domManager.after(previous, buffer.string());
  20242. } else {
  20243. view.domManager.prepend(view, buffer.string());
  20244. }
  20245. viewCollection.forEach(function(v) {
  20246. v.transitionTo('inDOM');
  20247. v.propertyDidChange('element');
  20248. v.triggerRecursively('didInsertElement');
  20249. });
  20250. }
  20251. })();
  20252. (function() {
  20253. /**
  20254. @module ember
  20255. @submodule ember-views
  20256. */
  20257. var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
  20258. /**
  20259. `Ember.CollectionView` is an `Ember.View` descendent responsible for managing
  20260. a collection (an array or array-like object) by maintaining a child view object
  20261. and associated DOM representation for each item in the array and ensuring
  20262. that child views and their associated rendered HTML are updated when items in
  20263. the array are added, removed, or replaced.
  20264. ## Setting content
  20265. The managed collection of objects is referenced as the `Ember.CollectionView`
  20266. instance's `content` property.
  20267. ```javascript
  20268. someItemsView = Ember.CollectionView.create({
  20269. content: ['A', 'B','C']
  20270. })
  20271. ```
  20272. The view for each item in the collection will have its `content` property set
  20273. to the item.
  20274. ## Specifying itemViewClass
  20275. By default the view class for each item in the managed collection will be an
  20276. instance of `Ember.View`. You can supply a different class by setting the
  20277. `CollectionView`'s `itemViewClass` property.
  20278. Given an empty `<body>` and the following code:
  20279. ```javascript
  20280. someItemsView = Ember.CollectionView.create({
  20281. classNames: ['a-collection'],
  20282. content: ['A','B','C'],
  20283. itemViewClass: Ember.View.extend({
  20284. template: Ember.Handlebars.compile("the letter: {{view.content}}")
  20285. })
  20286. });
  20287. someItemsView.appendTo('body');
  20288. ```
  20289. Will result in the following HTML structure
  20290. ```html
  20291. <div class="ember-view a-collection">
  20292. <div class="ember-view">the letter: A</div>
  20293. <div class="ember-view">the letter: B</div>
  20294. <div class="ember-view">the letter: C</div>
  20295. </div>
  20296. ```
  20297. ## Automatic matching of parent/child tagNames
  20298. Setting the `tagName` property of a `CollectionView` to any of
  20299. "ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result
  20300. in the item views receiving an appropriately matched `tagName` property.
  20301. Given an empty `<body>` and the following code:
  20302. ```javascript
  20303. anUnorderedListView = Ember.CollectionView.create({
  20304. tagName: 'ul',
  20305. content: ['A','B','C'],
  20306. itemViewClass: Ember.View.extend({
  20307. template: Ember.Handlebars.compile("the letter: {{view.content}}")
  20308. })
  20309. });
  20310. anUnorderedListView.appendTo('body');
  20311. ```
  20312. Will result in the following HTML structure
  20313. ```html
  20314. <ul class="ember-view a-collection">
  20315. <li class="ember-view">the letter: A</li>
  20316. <li class="ember-view">the letter: B</li>
  20317. <li class="ember-view">the letter: C</li>
  20318. </ul>
  20319. ```
  20320. Additional `tagName` pairs can be provided by adding to
  20321. `Ember.CollectionView.CONTAINER_MAP `
  20322. ```javascript
  20323. Ember.CollectionView.CONTAINER_MAP['article'] = 'section'
  20324. ```
  20325. ## Programmatic creation of child views
  20326. For cases where additional customization beyond the use of a single
  20327. `itemViewClass` or `tagName` matching is required CollectionView's
  20328. `createChildView` method can be overidden:
  20329. ```javascript
  20330. CustomCollectionView = Ember.CollectionView.extend({
  20331. createChildView: function(viewClass, attrs) {
  20332. if (attrs.content.kind == 'album') {
  20333. viewClass = App.AlbumView;
  20334. } else {
  20335. viewClass = App.SongView;
  20336. }
  20337. return this._super(viewClass, attrs);
  20338. }
  20339. });
  20340. ```
  20341. ## Empty View
  20342. You can provide an `Ember.View` subclass to the `Ember.CollectionView`
  20343. instance as its `emptyView` property. If the `content` property of a
  20344. `CollectionView` is set to `null` or an empty array, an instance of this view
  20345. will be the `CollectionView`s only child.
  20346. ```javascript
  20347. aListWithNothing = Ember.CollectionView.create({
  20348. classNames: ['nothing']
  20349. content: null,
  20350. emptyView: Ember.View.extend({
  20351. template: Ember.Handlebars.compile("The collection is empty")
  20352. })
  20353. });
  20354. aListWithNothing.appendTo('body');
  20355. ```
  20356. Will result in the following HTML structure
  20357. ```html
  20358. <div class="ember-view nothing">
  20359. <div class="ember-view">
  20360. The collection is empty
  20361. </div>
  20362. </div>
  20363. ```
  20364. ## Adding and Removing items
  20365. The `childViews` property of a `CollectionView` should not be directly
  20366. manipulated. Instead, add, remove, replace items from its `content` property.
  20367. This will trigger appropriate changes to its rendered HTML.
  20368. @class CollectionView
  20369. @namespace Ember
  20370. @extends Ember.ContainerView
  20371. @since Ember 0.9
  20372. */
  20373. Ember.CollectionView = Ember.ContainerView.extend({
  20374. /**
  20375. A list of items to be displayed by the `Ember.CollectionView`.
  20376. @property content
  20377. @type Ember.Array
  20378. @default null
  20379. */
  20380. content: null,
  20381. /**
  20382. This provides metadata about what kind of empty view class this
  20383. collection would like if it is being instantiated from another
  20384. system (like Handlebars)
  20385. @private
  20386. @property emptyViewClass
  20387. */
  20388. emptyViewClass: Ember.View,
  20389. /**
  20390. An optional view to display if content is set to an empty array.
  20391. @property emptyView
  20392. @type Ember.View
  20393. @default null
  20394. */
  20395. emptyView: null,
  20396. /**
  20397. @property itemViewClass
  20398. @type Ember.View
  20399. @default Ember.View
  20400. */
  20401. itemViewClass: Ember.View,
  20402. /**
  20403. Setup a CollectionView
  20404. @method init
  20405. */
  20406. init: function() {
  20407. var ret = this._super();
  20408. this._contentDidChange();
  20409. return ret;
  20410. },
  20411. /**
  20412. Invoked when the content property is about to change. Notifies observers that the
  20413. entire array content will change.
  20414. @private
  20415. @method _contentWillChange
  20416. */
  20417. _contentWillChange: Ember.beforeObserver('content', function() {
  20418. var content = this.get('content');
  20419. if (content) { content.removeArrayObserver(this); }
  20420. var len = content ? get(content, 'length') : 0;
  20421. this.arrayWillChange(content, 0, len);
  20422. }),
  20423. /**
  20424. Check to make sure that the content has changed, and if so,
  20425. update the children directly. This is always scheduled
  20426. asynchronously, to allow the element to be created before
  20427. bindings have synchronized and vice versa.
  20428. @private
  20429. @method _contentDidChange
  20430. */
  20431. _contentDidChange: Ember.observer('content', function() {
  20432. var content = get(this, 'content');
  20433. if (content) {
  20434. this._assertArrayLike(content);
  20435. content.addArrayObserver(this);
  20436. }
  20437. var len = content ? get(content, 'length') : 0;
  20438. this.arrayDidChange(content, 0, null, len);
  20439. }),
  20440. /**
  20441. Ensure that the content implements Ember.Array
  20442. @private
  20443. @method _assertArrayLike
  20444. */
  20445. _assertArrayLike: function(content) {
  20446. Ember.assert(fmt("an Ember.CollectionView's content must implement Ember.Array. You passed %@", [content]), Ember.Array.detect(content));
  20447. },
  20448. /**
  20449. Removes the content and content observers.
  20450. @method destroy
  20451. */
  20452. destroy: function() {
  20453. if (!this._super()) { return; }
  20454. var content = get(this, 'content');
  20455. if (content) { content.removeArrayObserver(this); }
  20456. if (this._createdEmptyView) {
  20457. this._createdEmptyView.destroy();
  20458. }
  20459. return this;
  20460. },
  20461. /**
  20462. Called when a mutation to the underlying content array will occur.
  20463. This method will remove any views that are no longer in the underlying
  20464. content array.
  20465. Invokes whenever the content array itself will change.
  20466. @method arrayWillChange
  20467. @param {Array} content the managed collection of objects
  20468. @param {Number} start the index at which the changes will occurr
  20469. @param {Number} removed number of object to be removed from content
  20470. */
  20471. arrayWillChange: function(content, start, removedCount) {
  20472. // If the contents were empty before and this template collection has an
  20473. // empty view remove it now.
  20474. var emptyView = get(this, 'emptyView');
  20475. if (emptyView && emptyView instanceof Ember.View) {
  20476. emptyView.removeFromParent();
  20477. }
  20478. // Loop through child views that correspond with the removed items.
  20479. // Note that we loop from the end of the array to the beginning because
  20480. // we are mutating it as we go.
  20481. var childViews = this._childViews, childView, idx, len;
  20482. len = this._childViews.length;
  20483. var removingAll = removedCount === len;
  20484. if (removingAll) {
  20485. this.currentState.empty(this);
  20486. this.invokeRecursively(function(view) {
  20487. view.removedFromDOM = true;
  20488. }, false);
  20489. }
  20490. for (idx = start + removedCount - 1; idx >= start; idx--) {
  20491. childView = childViews[idx];
  20492. childView.destroy();
  20493. }
  20494. },
  20495. /**
  20496. Called when a mutation to the underlying content array occurs.
  20497. This method will replay that mutation against the views that compose the
  20498. `Ember.CollectionView`, ensuring that the view reflects the model.
  20499. This array observer is added in `contentDidChange`.
  20500. @method arrayDidChange
  20501. @param {Array} content the managed collection of objects
  20502. @param {Number} start the index at which the changes occurred
  20503. @param {Number} removed number of object removed from content
  20504. @param {Number} added number of object added to content
  20505. */
  20506. arrayDidChange: function(content, start, removed, added) {
  20507. var addedViews = [], view, item, idx, len, itemViewClass,
  20508. emptyView;
  20509. len = content ? get(content, 'length') : 0;
  20510. if (len) {
  20511. itemViewClass = get(this, 'itemViewClass');
  20512. if ('string' === typeof itemViewClass) {
  20513. itemViewClass = get(itemViewClass) || itemViewClass;
  20514. }
  20515. Ember.assert(fmt("itemViewClass must be a subclass of Ember.View, not %@", [itemViewClass]), 'string' === typeof itemViewClass || Ember.View.detect(itemViewClass));
  20516. for (idx = start; idx < start+added; idx++) {
  20517. item = content.objectAt(idx);
  20518. view = this.createChildView(itemViewClass, {
  20519. content: item,
  20520. contentIndex: idx
  20521. });
  20522. addedViews.push(view);
  20523. }
  20524. } else {
  20525. emptyView = get(this, 'emptyView');
  20526. if (!emptyView) { return; }
  20527. if ('string' === typeof emptyView) {
  20528. emptyView = get(emptyView) || emptyView;
  20529. }
  20530. emptyView = this.createChildView(emptyView);
  20531. addedViews.push(emptyView);
  20532. set(this, 'emptyView', emptyView);
  20533. if (Ember.CoreView.detect(emptyView)) {
  20534. this._createdEmptyView = emptyView;
  20535. }
  20536. }
  20537. this.replace(start, 0, addedViews);
  20538. },
  20539. /**
  20540. Instantiates a view to be added to the childViews array during view
  20541. initialization. You generally will not call this method directly unless
  20542. you are overriding `createChildViews()`. Note that this method will
  20543. automatically configure the correct settings on the new view instance to
  20544. act as a child of the parent.
  20545. The tag name for the view will be set to the tagName of the viewClass
  20546. passed in.
  20547. @method createChildView
  20548. @param {Class} viewClass
  20549. @param {Hash} [attrs] Attributes to add
  20550. @return {Ember.View} new instance
  20551. */
  20552. createChildView: function(view, attrs) {
  20553. view = this._super(view, attrs);
  20554. var itemTagName = get(view, 'tagName');
  20555. if (itemTagName === null || itemTagName === undefined) {
  20556. itemTagName = Ember.CollectionView.CONTAINER_MAP[get(this, 'tagName')];
  20557. set(view, 'tagName', itemTagName);
  20558. }
  20559. return view;
  20560. }
  20561. });
  20562. /**
  20563. A map of parent tags to their default child tags. You can add
  20564. additional parent tags if you want collection views that use
  20565. a particular parent tag to default to a child tag.
  20566. @property CONTAINER_MAP
  20567. @type Hash
  20568. @static
  20569. @final
  20570. */
  20571. Ember.CollectionView.CONTAINER_MAP = {
  20572. ul: 'li',
  20573. ol: 'li',
  20574. table: 'tr',
  20575. thead: 'tr',
  20576. tbody: 'tr',
  20577. tfoot: 'tr',
  20578. tr: 'td',
  20579. select: 'option'
  20580. };
  20581. })();
  20582. (function() {
  20583. /**
  20584. The ComponentTemplateDeprecation mixin is used to provide a useful
  20585. deprecation warning when using either `template` or `templateName` with
  20586. a component. The `template` and `templateName` properties specified at
  20587. extend time are moved to `layout` and `layoutName` respectively.
  20588. `Ember.ComponentTemplateDeprecation` is used internally by Ember in
  20589. `Ember.Component`.
  20590. @class ComponentTemplateDeprecation
  20591. @namespace Ember
  20592. */
  20593. Ember.ComponentTemplateDeprecation = Ember.Mixin.create({
  20594. /**
  20595. @private
  20596. Moves `templateName` to `layoutName` and `template` to `layout` at extend
  20597. time if a layout is not also specified.
  20598. Note that this currently modifies the mixin themselves, which is technically
  20599. dubious but is practically of little consequence. This may change in the
  20600. future.
  20601. @method willMergeMixin
  20602. */
  20603. willMergeMixin: function(props) {
  20604. // must call _super here to ensure that the ActionHandler
  20605. // mixin is setup properly (moves actions -> _actions)
  20606. //
  20607. // Calling super is only OK here since we KNOW that
  20608. // there is another Mixin loaded first.
  20609. this._super.apply(this, arguments);
  20610. var deprecatedProperty, replacementProperty,
  20611. layoutSpecified = (props.layoutName || props.layout);
  20612. if (props.templateName && !layoutSpecified) {
  20613. deprecatedProperty = 'templateName';
  20614. replacementProperty = 'layoutName';
  20615. props.layoutName = props.templateName;
  20616. delete props['templateName'];
  20617. }
  20618. if (props.template && !layoutSpecified) {
  20619. deprecatedProperty = 'template';
  20620. replacementProperty = 'layout';
  20621. props.layout = props.template;
  20622. delete props['template'];
  20623. }
  20624. if (deprecatedProperty) {
  20625. Ember.deprecate('Do not specify ' + deprecatedProperty + ' on a Component, use ' + replacementProperty + ' instead.', false);
  20626. }
  20627. }
  20628. });
  20629. })();
  20630. (function() {
  20631. var get = Ember.get, set = Ember.set, isNone = Ember.isNone,
  20632. a_slice = Array.prototype.slice;
  20633. /**
  20634. @module ember
  20635. @submodule ember-views
  20636. */
  20637. /**
  20638. An `Ember.Component` is a view that is completely
  20639. isolated. Property access in its templates go
  20640. to the view object and actions are targeted at
  20641. the view object. There is no access to the
  20642. surrounding context or outer controller; all
  20643. contextual information must be passed in.
  20644. The easiest way to create an `Ember.Component` is via
  20645. a template. If you name a template
  20646. `components/my-foo`, you will be able to use
  20647. `{{my-foo}}` in other templates, which will make
  20648. an instance of the isolated component.
  20649. ```handlebars
  20650. {{app-profile person=currentUser}}
  20651. ```
  20652. ```handlebars
  20653. <!-- app-profile template -->
  20654. <h1>{{person.title}}</h1>
  20655. <img {{bind-attr src=person.avatar}}>
  20656. <p class='signature'>{{person.signature}}</p>
  20657. ```
  20658. You can use `yield` inside a template to
  20659. include the **contents** of any block attached to
  20660. the component. The block will be executed in the
  20661. context of the surrounding context or outer controller:
  20662. ```handlebars
  20663. {{#app-profile person=currentUser}}
  20664. <p>Admin mode</p>
  20665. {{! Executed in the controller's context. }}
  20666. {{/app-profile}}
  20667. ```
  20668. ```handlebars
  20669. <!-- app-profile template -->
  20670. <h1>{{person.title}}</h1>
  20671. {{! Executed in the components context. }}
  20672. {{yield}} {{! block contents }}
  20673. ```
  20674. If you want to customize the component, in order to
  20675. handle events or actions, you implement a subclass
  20676. of `Ember.Component` named after the name of the
  20677. component. Note that `Component` needs to be appended to the name of
  20678. your subclass like `AppProfileComponent`.
  20679. For example, you could implement the action
  20680. `hello` for the `app-profile` component:
  20681. ```javascript
  20682. App.AppProfileComponent = Ember.Component.extend({
  20683. actions: {
  20684. hello: function(name) {
  20685. console.log("Hello", name);
  20686. }
  20687. }
  20688. });
  20689. ```
  20690. And then use it in the component's template:
  20691. ```handlebars
  20692. <!-- app-profile template -->
  20693. <h1>{{person.title}}</h1>
  20694. {{yield}} <!-- block contents -->
  20695. <button {{action 'hello' person.name}}>
  20696. Say Hello to {{person.name}}
  20697. </button>
  20698. ```
  20699. Components must have a `-` in their name to avoid
  20700. conflicts with built-in controls that wrap HTML
  20701. elements. This is consistent with the same
  20702. requirement in web components.
  20703. @class Component
  20704. @namespace Ember
  20705. @extends Ember.View
  20706. */
  20707. Ember.Component = Ember.View.extend(Ember.TargetActionSupport, Ember.ComponentTemplateDeprecation, {
  20708. init: function() {
  20709. this._super();
  20710. set(this, 'context', this);
  20711. set(this, 'controller', this);
  20712. },
  20713. defaultLayout: function(context, options){
  20714. Ember.Handlebars.helpers['yield'].call(context, options);
  20715. },
  20716. /**
  20717. A components template property is set by passing a block
  20718. during its invocation. It is executed within the parent context.
  20719. Example:
  20720. ```handlebars
  20721. {{#my-component}}
  20722. // something that is run in the context
  20723. // of the parent context
  20724. {{/my-component}}
  20725. ```
  20726. Specifying a template directly to a component is deprecated without
  20727. also specifying the layout property.
  20728. @deprecated
  20729. @property template
  20730. */
  20731. template: Ember.computed(function(key, value) {
  20732. if (value !== undefined) { return value; }
  20733. var templateName = get(this, 'templateName'),
  20734. template = this.templateForName(templateName, 'template');
  20735. Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template);
  20736. return template || get(this, 'defaultTemplate');
  20737. }).property('templateName'),
  20738. /**
  20739. Specifying a components `templateName` is deprecated without also
  20740. providing the `layout` or `layoutName` properties.
  20741. @deprecated
  20742. @property templateName
  20743. */
  20744. templateName: null,
  20745. // during render, isolate keywords
  20746. cloneKeywords: function() {
  20747. return {
  20748. view: this,
  20749. controller: this
  20750. };
  20751. },
  20752. _yield: function(context, options) {
  20753. var view = options.data.view,
  20754. parentView = this._parentView,
  20755. template = get(this, 'template');
  20756. if (template) {
  20757. Ember.assert("A Component must have a parent view in order to yield.", parentView);
  20758. view.appendChild(Ember.View, {
  20759. isVirtual: true,
  20760. tagName: '',
  20761. _contextView: parentView,
  20762. template: template,
  20763. context: get(parentView, 'context'),
  20764. controller: get(parentView, 'controller'),
  20765. templateData: { keywords: parentView.cloneKeywords() }
  20766. });
  20767. }
  20768. },
  20769. /**
  20770. If the component is currently inserted into the DOM of a parent view, this
  20771. property will point to the controller of the parent view.
  20772. @property targetObject
  20773. @type Ember.Controller
  20774. @default null
  20775. */
  20776. targetObject: Ember.computed(function(key) {
  20777. var parentView = get(this, '_parentView');
  20778. return parentView ? get(parentView, 'controller') : null;
  20779. }).property('_parentView'),
  20780. /**
  20781. Triggers a named action on the controller context where the component is used if
  20782. this controller has registered for notifications of the action.
  20783. For example a component for playing or pausing music may translate click events
  20784. into action notifications of "play" or "stop" depending on some internal state
  20785. of the component:
  20786. ```javascript
  20787. App.PlayButtonComponent = Ember.Component.extend({
  20788. click: function(){
  20789. if (this.get('isPlaying')) {
  20790. this.sendAction('play');
  20791. } else {
  20792. this.sendAction('stop');
  20793. }
  20794. }
  20795. });
  20796. ```
  20797. When used inside a template these component actions are configured to
  20798. trigger actions in the outer application context:
  20799. ```handlebars
  20800. {{! application.hbs }}
  20801. {{play-button play="musicStarted" stop="musicStopped"}}
  20802. ```
  20803. When the component receives a browser `click` event it translate this
  20804. interaction into application-specific semantics ("play" or "stop") and
  20805. triggers the specified action name on the controller for the template
  20806. where the component is used:
  20807. ```javascript
  20808. App.ApplicationController = Ember.Controller.extend({
  20809. actions: {
  20810. musicStarted: function(){
  20811. // called when the play button is clicked
  20812. // and the music started playing
  20813. },
  20814. musicStopped: function(){
  20815. // called when the play button is clicked
  20816. // and the music stopped playing
  20817. }
  20818. }
  20819. });
  20820. ```
  20821. If no action name is passed to `sendAction` a default name of "action"
  20822. is assumed.
  20823. ```javascript
  20824. App.NextButtonComponent = Ember.Component.extend({
  20825. click: function(){
  20826. this.sendAction();
  20827. }
  20828. });
  20829. ```
  20830. ```handlebars
  20831. {{! application.hbs }}
  20832. {{next-button action="playNextSongInAlbum"}}
  20833. ```
  20834. ```javascript
  20835. App.ApplicationController = Ember.Controller.extend({
  20836. actions: {
  20837. playNextSongInAlbum: function(){
  20838. ...
  20839. }
  20840. }
  20841. });
  20842. ```
  20843. @method sendAction
  20844. @param [action] {String} the action to trigger
  20845. @param [context] {*} a context to send with the action
  20846. */
  20847. sendAction: function(action) {
  20848. var actionName,
  20849. contexts = a_slice.call(arguments, 1);
  20850. // Send the default action
  20851. if (action === undefined) {
  20852. actionName = get(this, 'action');
  20853. Ember.assert("The default action was triggered on the component " + this.toString() +
  20854. ", but the action name (" + actionName + ") was not a string.",
  20855. isNone(actionName) || typeof actionName === 'string');
  20856. } else {
  20857. actionName = get(this, action);
  20858. Ember.assert("The " + action + " action was triggered on the component " +
  20859. this.toString() + ", but the action name (" + actionName +
  20860. ") was not a string.",
  20861. isNone(actionName) || typeof actionName === 'string');
  20862. }
  20863. // If no action name for that action could be found, just abort.
  20864. if (actionName === undefined) { return; }
  20865. this.triggerAction({
  20866. action: actionName,
  20867. actionContext: contexts
  20868. });
  20869. }
  20870. });
  20871. })();
  20872. (function() {
  20873. })();
  20874. (function() {
  20875. /**
  20876. `Ember.ViewTargetActionSupport` is a mixin that can be included in a
  20877. view class to add a `triggerAction` method with semantics similar to
  20878. the Handlebars `{{action}}` helper. It provides intelligent defaults
  20879. for the action's target: the view's controller; and the context that is
  20880. sent with the action: the view's context.
  20881. Note: In normal Ember usage, the `{{action}}` helper is usually the best
  20882. choice. This mixin is most often useful when you are doing more complex
  20883. event handling in custom View subclasses.
  20884. For example:
  20885. ```javascript
  20886. App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, {
  20887. action: 'save',
  20888. click: function() {
  20889. this.triggerAction(); // Sends the `save` action, along with the current context
  20890. // to the current controller
  20891. }
  20892. });
  20893. ```
  20894. The `action` can be provided as properties of an optional object argument
  20895. to `triggerAction` as well.
  20896. ```javascript
  20897. App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, {
  20898. click: function() {
  20899. this.triggerAction({
  20900. action: 'save'
  20901. }); // Sends the `save` action, along with the current context
  20902. // to the current controller
  20903. }
  20904. });
  20905. ```
  20906. @class ViewTargetActionSupport
  20907. @namespace Ember
  20908. @extends Ember.TargetActionSupport
  20909. */
  20910. Ember.ViewTargetActionSupport = Ember.Mixin.create(Ember.TargetActionSupport, {
  20911. /**
  20912. @property target
  20913. */
  20914. target: Ember.computed.alias('controller'),
  20915. /**
  20916. @property actionContext
  20917. */
  20918. actionContext: Ember.computed.alias('context')
  20919. });
  20920. })();
  20921. (function() {
  20922. })();
  20923. (function() {
  20924. /**
  20925. Ember Views
  20926. @module ember
  20927. @submodule ember-views
  20928. @requires ember-runtime
  20929. @main ember-views
  20930. */
  20931. })();
  20932. (function() {
  20933. define("metamorph",
  20934. [],
  20935. function() {
  20936. "use strict";
  20937. // ==========================================================================
  20938. // Project: metamorph
  20939. // Copyright: ©2014 Tilde, Inc. All rights reserved.
  20940. // ==========================================================================
  20941. var K = function() {},
  20942. guid = 0,
  20943. disableRange = (function(){
  20944. if ('undefined' !== typeof MetamorphENV) {
  20945. return MetamorphENV.DISABLE_RANGE_API;
  20946. } else if ('undefined' !== ENV) {
  20947. return ENV.DISABLE_RANGE_API;
  20948. } else {
  20949. return false;
  20950. }
  20951. })(),
  20952. // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
  20953. supportsRange = (!disableRange) && typeof document !== 'undefined' && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
  20954. // Internet Explorer prior to 9 does not allow setting innerHTML if the first element
  20955. // is a "zero-scope" element. This problem can be worked around by making
  20956. // the first node an invisible text node. We, like Modernizr, use &shy;
  20957. needsShy = typeof document !== 'undefined' && (function() {
  20958. var testEl = document.createElement('div');
  20959. testEl.innerHTML = "<div></div>";
  20960. testEl.firstChild.innerHTML = "<script></script>";
  20961. return testEl.firstChild.innerHTML === '';
  20962. })(),
  20963. // IE 8 (and likely earlier) likes to move whitespace preceeding
  20964. // a script tag to appear after it. This means that we can
  20965. // accidentally remove whitespace when updating a morph.
  20966. movesWhitespace = document && (function() {
  20967. var testEl = document.createElement('div');
  20968. testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value";
  20969. return testEl.childNodes[0].nodeValue === 'Test:' &&
  20970. testEl.childNodes[2].nodeValue === ' Value';
  20971. })();
  20972. // Constructor that supports either Metamorph('foo') or new
  20973. // Metamorph('foo');
  20974. //
  20975. // Takes a string of HTML as the argument.
  20976. var Metamorph = function(html) {
  20977. var self;
  20978. if (this instanceof Metamorph) {
  20979. self = this;
  20980. } else {
  20981. self = new K();
  20982. }
  20983. self.innerHTML = html;
  20984. var myGuid = 'metamorph-'+(guid++);
  20985. self.start = myGuid + '-start';
  20986. self.end = myGuid + '-end';
  20987. return self;
  20988. };
  20989. K.prototype = Metamorph.prototype;
  20990. var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, afterFunc, prependFunc, startTagFunc, endTagFunc;
  20991. outerHTMLFunc = function() {
  20992. return this.startTag() + this.innerHTML + this.endTag();
  20993. };
  20994. startTagFunc = function() {
  20995. /*
  20996. * We replace chevron by its hex code in order to prevent escaping problems.
  20997. * Check this thread for more explaination:
  20998. * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript
  20999. */
  21000. return "<script id='" + this.start + "' type='text/x-placeholder'>\x3C/script>";
  21001. };
  21002. endTagFunc = function() {
  21003. /*
  21004. * We replace chevron by its hex code in order to prevent escaping problems.
  21005. * Check this thread for more explaination:
  21006. * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript
  21007. */
  21008. return "<script id='" + this.end + "' type='text/x-placeholder'>\x3C/script>";
  21009. };
  21010. // If we have the W3C range API, this process is relatively straight forward.
  21011. if (supportsRange) {
  21012. // Get a range for the current morph. Optionally include the starting and
  21013. // ending placeholders.
  21014. rangeFor = function(morph, outerToo) {
  21015. var range = document.createRange();
  21016. var before = document.getElementById(morph.start);
  21017. var after = document.getElementById(morph.end);
  21018. if (outerToo) {
  21019. range.setStartBefore(before);
  21020. range.setEndAfter(after);
  21021. } else {
  21022. range.setStartAfter(before);
  21023. range.setEndBefore(after);
  21024. }
  21025. return range;
  21026. };
  21027. htmlFunc = function(html, outerToo) {
  21028. // get a range for the current metamorph object
  21029. var range = rangeFor(this, outerToo);
  21030. // delete the contents of the range, which will be the
  21031. // nodes between the starting and ending placeholder.
  21032. range.deleteContents();
  21033. // create a new document fragment for the HTML
  21034. var fragment = range.createContextualFragment(html);
  21035. // insert the fragment into the range
  21036. range.insertNode(fragment);
  21037. };
  21038. /**
  21039. * @public
  21040. *
  21041. * Remove this object (including starting and ending
  21042. * placeholders).
  21043. *
  21044. * @method remove
  21045. */
  21046. removeFunc = function() {
  21047. // get a range for the current metamorph object including
  21048. // the starting and ending placeholders.
  21049. var range = rangeFor(this, true);
  21050. // delete the entire range.
  21051. range.deleteContents();
  21052. };
  21053. appendToFunc = function(node) {
  21054. var range = document.createRange();
  21055. range.setStart(node);
  21056. range.collapse(false);
  21057. var frag = range.createContextualFragment(this.outerHTML());
  21058. node.appendChild(frag);
  21059. };
  21060. afterFunc = function(html) {
  21061. var range = document.createRange();
  21062. var after = document.getElementById(this.end);
  21063. range.setStartAfter(after);
  21064. range.setEndAfter(after);
  21065. var fragment = range.createContextualFragment(html);
  21066. range.insertNode(fragment);
  21067. };
  21068. prependFunc = function(html) {
  21069. var range = document.createRange();
  21070. var start = document.getElementById(this.start);
  21071. range.setStartAfter(start);
  21072. range.setEndAfter(start);
  21073. var fragment = range.createContextualFragment(html);
  21074. range.insertNode(fragment);
  21075. };
  21076. } else {
  21077. /*
  21078. * This code is mostly taken from jQuery, with one exception. In jQuery's case, we
  21079. * have some HTML and we need to figure out how to convert it into some nodes.
  21080. *
  21081. * In this case, jQuery needs to scan the HTML looking for an opening tag and use
  21082. * that as the key for the wrap map. In our case, we know the parent node, and
  21083. * can use its type as the key for the wrap map.
  21084. **/
  21085. var wrapMap = {
  21086. select: [ 1, "<select multiple='multiple'>", "</select>" ],
  21087. fieldset: [ 1, "<fieldset>", "</fieldset>" ],
  21088. table: [ 1, "<table>", "</table>" ],
  21089. tbody: [ 2, "<table><tbody>", "</tbody></table>" ],
  21090. tr: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
  21091. colgroup: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
  21092. map: [ 1, "<map>", "</map>" ],
  21093. _default: [ 0, "", "" ]
  21094. };
  21095. var findChildById = function(element, id) {
  21096. if (element.getAttribute('id') === id) { return element; }
  21097. var len = element.childNodes.length, idx, node, found;
  21098. for (idx=0; idx<len; idx++) {
  21099. node = element.childNodes[idx];
  21100. found = node.nodeType === 1 && findChildById(node, id);
  21101. if (found) { return found; }
  21102. }
  21103. };
  21104. var setInnerHTML = function(element, html) {
  21105. var matches = [];
  21106. if (movesWhitespace) {
  21107. // Right now we only check for script tags with ids with the
  21108. // goal of targeting morphs.
  21109. html = html.replace(/(\s+)(<script id='([^']+)')/g, function(match, spaces, tag, id) {
  21110. matches.push([id, spaces]);
  21111. return tag;
  21112. });
  21113. }
  21114. element.innerHTML = html;
  21115. // If we have to do any whitespace adjustments do them now
  21116. if (matches.length > 0) {
  21117. var len = matches.length, idx;
  21118. for (idx=0; idx<len; idx++) {
  21119. var script = findChildById(element, matches[idx][0]),
  21120. node = document.createTextNode(matches[idx][1]);
  21121. script.parentNode.insertBefore(node, script);
  21122. }
  21123. }
  21124. };
  21125. /*
  21126. * Given a parent node and some HTML, generate a set of nodes. Return the first
  21127. * node, which will allow us to traverse the rest using nextSibling.
  21128. *
  21129. * We need to do this because innerHTML in IE does not really parse the nodes.
  21130. */
  21131. var firstNodeFor = function(parentNode, html) {
  21132. var arr = wrapMap[parentNode.tagName.toLowerCase()] || wrapMap._default;
  21133. var depth = arr[0], start = arr[1], end = arr[2];
  21134. if (needsShy) { html = '&shy;'+html; }
  21135. var element = document.createElement('div');
  21136. setInnerHTML(element, start + html + end);
  21137. for (var i=0; i<=depth; i++) {
  21138. element = element.firstChild;
  21139. }
  21140. // Look for &shy; to remove it.
  21141. if (needsShy) {
  21142. var shyElement = element;
  21143. // Sometimes we get nameless elements with the shy inside
  21144. while (shyElement.nodeType === 1 && !shyElement.nodeName) {
  21145. shyElement = shyElement.firstChild;
  21146. }
  21147. // At this point it's the actual unicode character.
  21148. if (shyElement.nodeType === 3 && shyElement.nodeValue.charAt(0) === "\u00AD") {
  21149. shyElement.nodeValue = shyElement.nodeValue.slice(1);
  21150. }
  21151. }
  21152. return element;
  21153. };
  21154. /*
  21155. * In some cases, Internet Explorer can create an anonymous node in
  21156. * the hierarchy with no tagName. You can create this scenario via:
  21157. *
  21158. * div = document.createElement("div");
  21159. * div.innerHTML = "<table>&shy<script></script><tr><td>hi</td></tr></table>";
  21160. * div.firstChild.firstChild.tagName //=> ""
  21161. *
  21162. * If our script markers are inside such a node, we need to find that
  21163. * node and use *it* as the marker.
  21164. */
  21165. var realNode = function(start) {
  21166. while (start.parentNode.tagName === "") {
  21167. start = start.parentNode;
  21168. }
  21169. return start;
  21170. };
  21171. /*
  21172. * When automatically adding a tbody, Internet Explorer inserts the
  21173. * tbody immediately before the first <tr>. Other browsers create it
  21174. * before the first node, no matter what.
  21175. *
  21176. * This means the the following code:
  21177. *
  21178. * div = document.createElement("div");
  21179. * div.innerHTML = "<table><script id='first'></script><tr><td>hi</td></tr><script id='last'></script></table>
  21180. *
  21181. * Generates the following DOM in IE:
  21182. *
  21183. * + div
  21184. * + table
  21185. * - script id='first'
  21186. * + tbody
  21187. * + tr
  21188. * + td
  21189. * - "hi"
  21190. * - script id='last'
  21191. *
  21192. * Which means that the two script tags, even though they were
  21193. * inserted at the same point in the hierarchy in the original
  21194. * HTML, now have different parents.
  21195. *
  21196. * This code reparents the first script tag by making it the tbody's
  21197. * first child.
  21198. *
  21199. */
  21200. var fixParentage = function(start, end) {
  21201. if (start.parentNode !== end.parentNode) {
  21202. end.parentNode.insertBefore(start, end.parentNode.firstChild);
  21203. }
  21204. };
  21205. htmlFunc = function(html, outerToo) {
  21206. // get the real starting node. see realNode for details.
  21207. var start = realNode(document.getElementById(this.start));
  21208. var end = document.getElementById(this.end);
  21209. var parentNode = end.parentNode;
  21210. var node, nextSibling, last;
  21211. // make sure that the start and end nodes share the same
  21212. // parent. If not, fix it.
  21213. fixParentage(start, end);
  21214. // remove all of the nodes after the starting placeholder and
  21215. // before the ending placeholder.
  21216. node = start.nextSibling;
  21217. while (node) {
  21218. nextSibling = node.nextSibling;
  21219. last = node === end;
  21220. // if this is the last node, and we want to remove it as well,
  21221. // set the `end` node to the next sibling. This is because
  21222. // for the rest of the function, we insert the new nodes
  21223. // before the end (note that insertBefore(node, null) is
  21224. // the same as appendChild(node)).
  21225. //
  21226. // if we do not want to remove it, just break.
  21227. if (last) {
  21228. if (outerToo) { end = node.nextSibling; } else { break; }
  21229. }
  21230. node.parentNode.removeChild(node);
  21231. // if this is the last node and we didn't break before
  21232. // (because we wanted to remove the outer nodes), break
  21233. // now.
  21234. if (last) { break; }
  21235. node = nextSibling;
  21236. }
  21237. // get the first node for the HTML string, even in cases like
  21238. // tables and lists where a simple innerHTML on a div would
  21239. // swallow some of the content.
  21240. node = firstNodeFor(start.parentNode, html);
  21241. if (outerToo) {
  21242. start.parentNode.removeChild(start);
  21243. }
  21244. // copy the nodes for the HTML between the starting and ending
  21245. // placeholder.
  21246. while (node) {
  21247. nextSibling = node.nextSibling;
  21248. parentNode.insertBefore(node, end);
  21249. node = nextSibling;
  21250. }
  21251. };
  21252. // remove the nodes in the DOM representing this metamorph.
  21253. //
  21254. // this includes the starting and ending placeholders.
  21255. removeFunc = function() {
  21256. var start = realNode(document.getElementById(this.start));
  21257. var end = document.getElementById(this.end);
  21258. this.html('');
  21259. start.parentNode.removeChild(start);
  21260. end.parentNode.removeChild(end);
  21261. };
  21262. appendToFunc = function(parentNode) {
  21263. var node = firstNodeFor(parentNode, this.outerHTML());
  21264. var nextSibling;
  21265. while (node) {
  21266. nextSibling = node.nextSibling;
  21267. parentNode.appendChild(node);
  21268. node = nextSibling;
  21269. }
  21270. };
  21271. afterFunc = function(html) {
  21272. // get the real starting node. see realNode for details.
  21273. var end = document.getElementById(this.end);
  21274. var insertBefore = end.nextSibling;
  21275. var parentNode = end.parentNode;
  21276. var nextSibling;
  21277. var node;
  21278. // get the first node for the HTML string, even in cases like
  21279. // tables and lists where a simple innerHTML on a div would
  21280. // swallow some of the content.
  21281. node = firstNodeFor(parentNode, html);
  21282. // copy the nodes for the HTML between the starting and ending
  21283. // placeholder.
  21284. while (node) {
  21285. nextSibling = node.nextSibling;
  21286. parentNode.insertBefore(node, insertBefore);
  21287. node = nextSibling;
  21288. }
  21289. };
  21290. prependFunc = function(html) {
  21291. var start = document.getElementById(this.start);
  21292. var parentNode = start.parentNode;
  21293. var nextSibling;
  21294. var node;
  21295. node = firstNodeFor(parentNode, html);
  21296. var insertBefore = start.nextSibling;
  21297. while (node) {
  21298. nextSibling = node.nextSibling;
  21299. parentNode.insertBefore(node, insertBefore);
  21300. node = nextSibling;
  21301. }
  21302. };
  21303. }
  21304. Metamorph.prototype.html = function(html) {
  21305. this.checkRemoved();
  21306. if (html === undefined) { return this.innerHTML; }
  21307. htmlFunc.call(this, html);
  21308. this.innerHTML = html;
  21309. };
  21310. Metamorph.prototype.replaceWith = function(html) {
  21311. this.checkRemoved();
  21312. htmlFunc.call(this, html, true);
  21313. };
  21314. Metamorph.prototype.remove = removeFunc;
  21315. Metamorph.prototype.outerHTML = outerHTMLFunc;
  21316. Metamorph.prototype.appendTo = appendToFunc;
  21317. Metamorph.prototype.after = afterFunc;
  21318. Metamorph.prototype.prepend = prependFunc;
  21319. Metamorph.prototype.startTag = startTagFunc;
  21320. Metamorph.prototype.endTag = endTagFunc;
  21321. Metamorph.prototype.isRemoved = function() {
  21322. var before = document.getElementById(this.start);
  21323. var after = document.getElementById(this.end);
  21324. return !before || !after;
  21325. };
  21326. Metamorph.prototype.checkRemoved = function() {
  21327. if (this.isRemoved()) {
  21328. throw new Error("Cannot perform operations on a Metamorph that is not in the DOM.");
  21329. }
  21330. };
  21331. return Metamorph;
  21332. });
  21333. })();
  21334. (function() {
  21335. /**
  21336. @module ember
  21337. @submodule ember-handlebars-compiler
  21338. */
  21339. // Eliminate dependency on any Ember to simplify precompilation workflow
  21340. var objectCreate = Object.create || function(parent) {
  21341. function F() {}
  21342. F.prototype = parent;
  21343. return new F();
  21344. };
  21345. var Handlebars = (Ember.imports && Ember.imports.Handlebars) || (this && this.Handlebars);
  21346. if (!Handlebars && typeof require === 'function') {
  21347. Handlebars = require('handlebars');
  21348. }
  21349. Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1. Include " +
  21350. "a SCRIPT tag in the HTML HEAD linking to the Handlebars file " +
  21351. "before you link to Ember.", Handlebars);
  21352. Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1, " +
  21353. "COMPILER_REVISION expected: 4, got: " + Handlebars.COMPILER_REVISION +
  21354. " - Please note: Builds of master may have other COMPILER_REVISION values.",
  21355. Handlebars.COMPILER_REVISION === 4);
  21356. /**
  21357. Prepares the Handlebars templating library for use inside Ember's view
  21358. system.
  21359. The `Ember.Handlebars` object is the standard Handlebars library, extended to
  21360. use Ember's `get()` method instead of direct property access, which allows
  21361. computed properties to be used inside templates.
  21362. To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`.
  21363. This will return a function that can be used by `Ember.View` for rendering.
  21364. @class Handlebars
  21365. @namespace Ember
  21366. */
  21367. Ember.Handlebars = objectCreate(Handlebars);
  21368. /**
  21369. Register a bound helper or custom view helper.
  21370. ## Simple bound helper example
  21371. ```javascript
  21372. Ember.Handlebars.helper('capitalize', function(value) {
  21373. return value.toUpperCase();
  21374. });
  21375. ```
  21376. The above bound helper can be used inside of templates as follows:
  21377. ```handlebars
  21378. {{capitalize name}}
  21379. ```
  21380. In this case, when the `name` property of the template's context changes,
  21381. the rendered value of the helper will update to reflect this change.
  21382. For more examples of bound helpers, see documentation for
  21383. `Ember.Handlebars.registerBoundHelper`.
  21384. ## Custom view helper example
  21385. Assuming a view subclass named `App.CalendarView` were defined, a helper
  21386. for rendering instances of this view could be registered as follows:
  21387. ```javascript
  21388. Ember.Handlebars.helper('calendar', App.CalendarView):
  21389. ```
  21390. The above bound helper can be used inside of templates as follows:
  21391. ```handlebars
  21392. {{calendar}}
  21393. ```
  21394. Which is functionally equivalent to:
  21395. ```handlebars
  21396. {{view App.CalendarView}}
  21397. ```
  21398. Options in the helper will be passed to the view in exactly the same
  21399. manner as with the `view` helper.
  21400. @method helper
  21401. @for Ember.Handlebars
  21402. @param {String} name
  21403. @param {Function|Ember.View} function or view class constructor
  21404. @param {String} dependentKeys*
  21405. */
  21406. Ember.Handlebars.helper = function(name, value) {
  21407. Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", !Ember.Component.detect(value) || name.match(/-/));
  21408. if (Ember.View.detect(value)) {
  21409. Ember.Handlebars.registerHelper(name, Ember.Handlebars.makeViewHelper(value));
  21410. } else {
  21411. Ember.Handlebars.registerBoundHelper.apply(null, arguments);
  21412. }
  21413. };
  21414. /**
  21415. Returns a helper function that renders the provided ViewClass.
  21416. Used internally by Ember.Handlebars.helper and other methods
  21417. involving helper/component registration.
  21418. @private
  21419. @method helper
  21420. @for Ember.Handlebars
  21421. @param {Function} ViewClass view class constructor
  21422. */
  21423. Ember.Handlebars.makeViewHelper = function(ViewClass) {
  21424. return function(options) {
  21425. Ember.assert("You can only pass attributes (such as name=value) not bare values to a helper for a View found in '" + ViewClass.toString() + "'", arguments.length < 2);
  21426. return Ember.Handlebars.helpers.view.call(this, ViewClass, options);
  21427. };
  21428. };
  21429. /**
  21430. @class helpers
  21431. @namespace Ember.Handlebars
  21432. */
  21433. Ember.Handlebars.helpers = objectCreate(Handlebars.helpers);
  21434. /**
  21435. Override the the opcode compiler and JavaScript compiler for Handlebars.
  21436. @class Compiler
  21437. @namespace Ember.Handlebars
  21438. @private
  21439. @constructor
  21440. */
  21441. Ember.Handlebars.Compiler = function() {};
  21442. // Handlebars.Compiler doesn't exist in runtime-only
  21443. if (Handlebars.Compiler) {
  21444. Ember.Handlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype);
  21445. }
  21446. Ember.Handlebars.Compiler.prototype.compiler = Ember.Handlebars.Compiler;
  21447. /**
  21448. @class JavaScriptCompiler
  21449. @namespace Ember.Handlebars
  21450. @private
  21451. @constructor
  21452. */
  21453. Ember.Handlebars.JavaScriptCompiler = function() {};
  21454. // Handlebars.JavaScriptCompiler doesn't exist in runtime-only
  21455. if (Handlebars.JavaScriptCompiler) {
  21456. Ember.Handlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype);
  21457. Ember.Handlebars.JavaScriptCompiler.prototype.compiler = Ember.Handlebars.JavaScriptCompiler;
  21458. }
  21459. Ember.Handlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars";
  21460. Ember.Handlebars.JavaScriptCompiler.prototype.initializeBuffer = function() {
  21461. return "''";
  21462. };
  21463. /**
  21464. Override the default buffer for Ember Handlebars. By default, Handlebars
  21465. creates an empty String at the beginning of each invocation and appends to
  21466. it. Ember's Handlebars overrides this to append to a single shared buffer.
  21467. @private
  21468. @method appendToBuffer
  21469. @param string {String}
  21470. */
  21471. Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) {
  21472. return "data.buffer.push("+string+");";
  21473. };
  21474. // Hacks ahead:
  21475. // Handlebars presently has a bug where the `blockHelperMissing` hook
  21476. // doesn't get passed the name of the missing helper name, but rather
  21477. // gets passed the value of that missing helper evaluated on the current
  21478. // context, which is most likely `undefined` and totally useless.
  21479. //
  21480. // So we alter the compiled template function to pass the name of the helper
  21481. // instead, as expected.
  21482. //
  21483. // This can go away once the following is closed:
  21484. // https://github.com/wycats/handlebars.js/issues/634
  21485. var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/,
  21486. BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/,
  21487. INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/;
  21488. Ember.Handlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) {
  21489. var helperInvocation = source[source.length - 1],
  21490. helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1],
  21491. matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation);
  21492. source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3];
  21493. }
  21494. var stringifyBlockHelperMissing = Ember.Handlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation;
  21495. var originalBlockValue = Ember.Handlebars.JavaScriptCompiler.prototype.blockValue;
  21496. Ember.Handlebars.JavaScriptCompiler.prototype.blockValue = function() {
  21497. originalBlockValue.apply(this, arguments);
  21498. stringifyBlockHelperMissing(this.source);
  21499. };
  21500. var originalAmbiguousBlockValue = Ember.Handlebars.JavaScriptCompiler.prototype.ambiguousBlockValue;
  21501. Ember.Handlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() {
  21502. originalAmbiguousBlockValue.apply(this, arguments);
  21503. stringifyBlockHelperMissing(this.source);
  21504. };
  21505. var prefix = "ember" + (+new Date()), incr = 1;
  21506. /**
  21507. Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that
  21508. all simple mustaches in Ember's Handlebars will also set up an observer to
  21509. keep the DOM up to date when the underlying property changes.
  21510. @private
  21511. @method mustache
  21512. @for Ember.Handlebars.Compiler
  21513. @param mustache
  21514. */
  21515. Ember.Handlebars.Compiler.prototype.mustache = function(mustache) {
  21516. if (mustache.isHelper && mustache.id.string === 'control') {
  21517. mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
  21518. mustache.hash.pairs.push(["controlID", new Handlebars.AST.StringNode(prefix + incr++)]);
  21519. } else if (mustache.params.length || mustache.hash) {
  21520. // no changes required
  21521. } else {
  21522. var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]);
  21523. // Update the mustache node to include a hash value indicating whether the original node
  21524. // was escaped. This will allow us to properly escape values when the underlying value
  21525. // changes and we need to re-render the value.
  21526. if (!mustache.escaped) {
  21527. mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
  21528. mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]);
  21529. }
  21530. mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped);
  21531. }
  21532. return Handlebars.Compiler.prototype.mustache.call(this, mustache);
  21533. };
  21534. /**
  21535. Used for precompilation of Ember Handlebars templates. This will not be used
  21536. during normal app execution.
  21537. @method precompile
  21538. @for Ember.Handlebars
  21539. @static
  21540. @param {String} string The template to precompile
  21541. */
  21542. Ember.Handlebars.precompile = function(string) {
  21543. var ast = Handlebars.parse(string);
  21544. var options = {
  21545. knownHelpers: {
  21546. action: true,
  21547. unbound: true,
  21548. 'bind-attr': true,
  21549. template: true,
  21550. view: true,
  21551. _triageMustache: true
  21552. },
  21553. data: true,
  21554. stringParams: true
  21555. };
  21556. var environment = new Ember.Handlebars.Compiler().compile(ast, options);
  21557. return new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
  21558. };
  21559. // We don't support this for Handlebars runtime-only
  21560. if (Handlebars.compile) {
  21561. /**
  21562. The entry point for Ember Handlebars. This replaces the default
  21563. `Handlebars.compile` and turns on template-local data and String
  21564. parameters.
  21565. @method compile
  21566. @for Ember.Handlebars
  21567. @static
  21568. @param {String} string The template to compile
  21569. @return {Function}
  21570. */
  21571. Ember.Handlebars.compile = function(string) {
  21572. var ast = Handlebars.parse(string);
  21573. var options = { data: true, stringParams: true };
  21574. var environment = new Ember.Handlebars.Compiler().compile(ast, options);
  21575. var templateSpec = new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
  21576. var template = Ember.Handlebars.template(templateSpec);
  21577. template.isMethod = false; //Make sure we don't wrap templates with ._super
  21578. return template;
  21579. };
  21580. }
  21581. })();
  21582. (function() {
  21583. var slice = Array.prototype.slice,
  21584. originalTemplate = Ember.Handlebars.template;
  21585. /**
  21586. If a path starts with a reserved keyword, returns the root
  21587. that should be used.
  21588. @private
  21589. @method normalizePath
  21590. @for Ember
  21591. @param root {Object}
  21592. @param path {String}
  21593. @param data {Hash}
  21594. */
  21595. var normalizePath = Ember.Handlebars.normalizePath = function(root, path, data) {
  21596. var keywords = (data && data.keywords) || {},
  21597. keyword, isKeyword;
  21598. // Get the first segment of the path. For example, if the
  21599. // path is "foo.bar.baz", returns "foo".
  21600. keyword = path.split('.', 1)[0];
  21601. // Test to see if the first path is a keyword that has been
  21602. // passed along in the view's data hash. If so, we will treat
  21603. // that object as the new root.
  21604. if (keywords.hasOwnProperty(keyword)) {
  21605. // Look up the value in the template's data hash.
  21606. root = keywords[keyword];
  21607. isKeyword = true;
  21608. // Handle cases where the entire path is the reserved
  21609. // word. In that case, return the object itself.
  21610. if (path === keyword) {
  21611. path = '';
  21612. } else {
  21613. // Strip the keyword from the path and look up
  21614. // the remainder from the newly found root.
  21615. path = path.substr(keyword.length+1);
  21616. }
  21617. }
  21618. return { root: root, path: path, isKeyword: isKeyword };
  21619. };
  21620. /**
  21621. Lookup both on root and on window. If the path starts with
  21622. a keyword, the corresponding object will be looked up in the
  21623. template's data hash and used to resolve the path.
  21624. @method get
  21625. @for Ember.Handlebars
  21626. @param {Object} root The object to look up the property on
  21627. @param {String} path The path to be lookedup
  21628. @param {Object} options The template's option hash
  21629. */
  21630. var handlebarsGet = Ember.Handlebars.get = function(root, path, options) {
  21631. var data = options && options.data,
  21632. normalizedPath = normalizePath(root, path, data),
  21633. value;
  21634. root = normalizedPath.root;
  21635. path = normalizedPath.path;
  21636. value = Ember.get(root, path);
  21637. if (value === undefined && root !== Ember.lookup && Ember.isGlobalPath(path)) {
  21638. value = Ember.get(Ember.lookup, path);
  21639. }
  21640. return value;
  21641. };
  21642. /**
  21643. This method uses `Ember.Handlebars.get` to lookup a value, then ensures
  21644. that the value is escaped properly.
  21645. If `unescaped` is a truthy value then the escaping will not be performed.
  21646. @method getEscaped
  21647. @for Ember.Handlebars
  21648. @param {Object} root The object to look up the property on
  21649. @param {String} path The path to be lookedup
  21650. @param {Object} options The template's option hash
  21651. */
  21652. Ember.Handlebars.getEscaped = function(root, path, options) {
  21653. var result = handlebarsGet(root, path, options);
  21654. if (result === null || result === undefined) {
  21655. result = "";
  21656. } else if (!(result instanceof Handlebars.SafeString)) {
  21657. result = String(result);
  21658. }
  21659. if (!options.hash.unescaped){
  21660. result = Handlebars.Utils.escapeExpression(result);
  21661. }
  21662. return result;
  21663. };
  21664. Ember.Handlebars.resolveParams = function(context, params, options) {
  21665. var resolvedParams = [], types = options.types, param, type;
  21666. for (var i=0, l=params.length; i<l; i++) {
  21667. param = params[i];
  21668. type = types[i];
  21669. if (type === 'ID') {
  21670. resolvedParams.push(handlebarsGet(context, param, options));
  21671. } else {
  21672. resolvedParams.push(param);
  21673. }
  21674. }
  21675. return resolvedParams;
  21676. };
  21677. Ember.Handlebars.resolveHash = function(context, hash, options) {
  21678. var resolvedHash = {}, types = options.hashTypes, type;
  21679. for (var key in hash) {
  21680. if (!hash.hasOwnProperty(key)) { continue; }
  21681. type = types[key];
  21682. if (type === 'ID') {
  21683. resolvedHash[key] = handlebarsGet(context, hash[key], options);
  21684. } else {
  21685. resolvedHash[key] = hash[key];
  21686. }
  21687. }
  21688. return resolvedHash;
  21689. };
  21690. /**
  21691. Registers a helper in Handlebars that will be called if no property with the
  21692. given name can be found on the current context object, and no helper with
  21693. that name is registered.
  21694. This throws an exception with a more helpful error message so the user can
  21695. track down where the problem is happening.
  21696. @private
  21697. @method helperMissing
  21698. @for Ember.Handlebars.helpers
  21699. @param {String} path
  21700. @param {Hash} options
  21701. */
  21702. Ember.Handlebars.registerHelper('helperMissing', function(path) {
  21703. var error, view = "";
  21704. var options = arguments[arguments.length - 1];
  21705. var helper = Ember.Handlebars.resolveHelper(options.data.view.container, path);
  21706. if (helper) {
  21707. return helper.apply(this, slice.call(arguments, 1));
  21708. }
  21709. error = "%@ Handlebars error: Could not find property '%@' on object %@.";
  21710. if (options.data) {
  21711. view = options.data.view;
  21712. }
  21713. throw new Ember.Error(Ember.String.fmt(error, [view, path, this]));
  21714. });
  21715. /**
  21716. Registers a helper in Handlebars that will be called if no property with the
  21717. given name can be found on the current context object, and no helper with
  21718. that name is registered.
  21719. This throws an exception with a more helpful error message so the user can
  21720. track down where the problem is happening.
  21721. @private
  21722. @method helperMissing
  21723. @for Ember.Handlebars.helpers
  21724. @param {String} path
  21725. @param {Hash} options
  21726. */
  21727. Ember.Handlebars.registerHelper('blockHelperMissing', function(path) {
  21728. var options = arguments[arguments.length - 1];
  21729. Ember.assert("`blockHelperMissing` was invoked without a helper name, which " +
  21730. "is most likely due to a mismatch between the version of " +
  21731. "Ember.js you're running now and the one used to precompile your " +
  21732. "templates. Please make sure the version of " +
  21733. "`ember-handlebars-compiler` you're using is up to date.", path);
  21734. var helper = Ember.Handlebars.resolveHelper(options.data.view.container, path);
  21735. if (helper) {
  21736. return helper.apply(this, slice.call(arguments, 1));
  21737. } else {
  21738. return Handlebars.helpers.helperMissing.call(this, path);
  21739. }
  21740. return Handlebars.helpers.blockHelperMissing.apply(this, arguments);
  21741. });
  21742. /**
  21743. Register a bound handlebars helper. Bound helpers behave similarly to regular
  21744. handlebars helpers, with the added ability to re-render when the underlying data
  21745. changes.
  21746. ## Simple example
  21747. ```javascript
  21748. Ember.Handlebars.registerBoundHelper('capitalize', function(value) {
  21749. return value.toUpperCase();
  21750. });
  21751. ```
  21752. The above bound helper can be used inside of templates as follows:
  21753. ```handlebars
  21754. {{capitalize name}}
  21755. ```
  21756. In this case, when the `name` property of the template's context changes,
  21757. the rendered value of the helper will update to reflect this change.
  21758. ## Example with options
  21759. Like normal handlebars helpers, bound helpers have access to the options
  21760. passed into the helper call.
  21761. ```javascript
  21762. Ember.Handlebars.registerBoundHelper('repeat', function(value, options) {
  21763. var count = options.hash.count;
  21764. var a = [];
  21765. while(a.length < count) {
  21766. a.push(value);
  21767. }
  21768. return a.join('');
  21769. });
  21770. ```
  21771. This helper could be used in a template as follows:
  21772. ```handlebars
  21773. {{repeat text count=3}}
  21774. ```
  21775. ## Example with bound options
  21776. Bound hash options are also supported. Example:
  21777. ```handlebars
  21778. {{repeat text countBinding="numRepeats"}}
  21779. ```
  21780. In this example, count will be bound to the value of
  21781. the `numRepeats` property on the context. If that property
  21782. changes, the helper will be re-rendered.
  21783. ## Example with extra dependencies
  21784. The `Ember.Handlebars.registerBoundHelper` method takes a variable length
  21785. third parameter which indicates extra dependencies on the passed in value.
  21786. This allows the handlebars helper to update when these dependencies change.
  21787. ```javascript
  21788. Ember.Handlebars.registerBoundHelper('capitalizeName', function(value) {
  21789. return value.get('name').toUpperCase();
  21790. }, 'name');
  21791. ```
  21792. ## Example with multiple bound properties
  21793. `Ember.Handlebars.registerBoundHelper` supports binding to
  21794. multiple properties, e.g.:
  21795. ```javascript
  21796. Ember.Handlebars.registerBoundHelper('concatenate', function() {
  21797. var values = Array.prototype.slice.call(arguments, 0, -1);
  21798. return values.join('||');
  21799. });
  21800. ```
  21801. Which allows for template syntax such as `{{concatenate prop1 prop2}}` or
  21802. `{{concatenate prop1 prop2 prop3}}`. If any of the properties change,
  21803. the helpr will re-render. Note that dependency keys cannot be
  21804. using in conjunction with multi-property helpers, since it is ambiguous
  21805. which property the dependent keys would belong to.
  21806. ## Use with unbound helper
  21807. The `{{unbound}}` helper can be used with bound helper invocations
  21808. to render them in their unbound form, e.g.
  21809. ```handlebars
  21810. {{unbound capitalize name}}
  21811. ```
  21812. In this example, if the name property changes, the helper
  21813. will not re-render.
  21814. ## Use with blocks not supported
  21815. Bound helpers do not support use with Handlebars blocks or
  21816. the addition of child views of any kind.
  21817. @method registerBoundHelper
  21818. @for Ember.Handlebars
  21819. @param {String} name
  21820. @param {Function} function
  21821. @param {String} dependentKeys*
  21822. */
  21823. Ember.Handlebars.registerBoundHelper = function(name, fn) {
  21824. var boundHelperArgs = slice.call(arguments, 1),
  21825. boundFn = Ember.Handlebars.makeBoundHelper.apply(this, boundHelperArgs);
  21826. Ember.Handlebars.registerHelper(name, boundFn);
  21827. };
  21828. /**
  21829. A (mostly) private helper function to `registerBoundHelper`. Takes the
  21830. provided Handlebars helper function fn and returns it in wrapped
  21831. bound helper form.
  21832. The main use case for using this outside of `registerBoundHelper`
  21833. is for registering helpers on the container:
  21834. ```js
  21835. var boundHelperFn = Ember.Handlebars.makeBoundHelper(function(word) {
  21836. return word.toUpperCase();
  21837. });
  21838. container.register('helper:my-bound-helper', boundHelperFn);
  21839. ```
  21840. In the above example, if the helper function hadn't been wrapped in
  21841. `makeBoundHelper`, the registered helper would be unbound.
  21842. @private
  21843. @method makeBoundHelper
  21844. @for Ember.Handlebars
  21845. @param {Function} function
  21846. @param {String} dependentKeys*
  21847. */
  21848. Ember.Handlebars.makeBoundHelper = function(fn) {
  21849. var dependentKeys = slice.call(arguments, 1);
  21850. function helper() {
  21851. var properties = slice.call(arguments, 0, -1),
  21852. numProperties = properties.length,
  21853. options = arguments[arguments.length - 1],
  21854. normalizedProperties = [],
  21855. data = options.data,
  21856. types = data.isUnbound ? slice.call(options.types, 1) : options.types,
  21857. hash = options.hash,
  21858. view = data.view,
  21859. contexts = options.contexts,
  21860. currentContext = (contexts && contexts.length) ? contexts[0] : this,
  21861. prefixPathForDependentKeys = '',
  21862. loc, len, hashOption,
  21863. boundOption, property,
  21864. normalizedValue = Ember._SimpleHandlebarsView.prototype.normalizedValue;
  21865. Ember.assert("registerBoundHelper-generated helpers do not support use with Handlebars blocks.", !options.fn);
  21866. // Detect bound options (e.g. countBinding="otherCount")
  21867. var boundOptions = hash.boundOptions = {};
  21868. for (hashOption in hash) {
  21869. if (Ember.IS_BINDING.test(hashOption)) {
  21870. // Lop off 'Binding' suffix.
  21871. boundOptions[hashOption.slice(0, -7)] = hash[hashOption];
  21872. }
  21873. }
  21874. // Expose property names on data.properties object.
  21875. var watchedProperties = [];
  21876. data.properties = [];
  21877. for (loc = 0; loc < numProperties; ++loc) {
  21878. data.properties.push(properties[loc]);
  21879. if (types[loc] === 'ID') {
  21880. var normalizedProp = normalizePath(currentContext, properties[loc], data);
  21881. normalizedProperties.push(normalizedProp);
  21882. watchedProperties.push(normalizedProp);
  21883. } else {
  21884. if(data.isUnbound) {
  21885. normalizedProperties.push({path: properties[loc]});
  21886. }else {
  21887. normalizedProperties.push(null);
  21888. }
  21889. }
  21890. }
  21891. // Handle case when helper invocation is preceded by `unbound`, e.g.
  21892. // {{unbound myHelper foo}}
  21893. if (data.isUnbound) {
  21894. return evaluateUnboundHelper(this, fn, normalizedProperties, options);
  21895. }
  21896. var bindView = new Ember._SimpleHandlebarsView(null, null, !options.hash.unescaped, options.data);
  21897. // Override SimpleHandlebarsView's method for generating the view's content.
  21898. bindView.normalizedValue = function() {
  21899. var args = [], boundOption;
  21900. // Copy over bound hash options.
  21901. for (boundOption in boundOptions) {
  21902. if (!boundOptions.hasOwnProperty(boundOption)) { continue; }
  21903. property = normalizePath(currentContext, boundOptions[boundOption], data);
  21904. bindView.path = property.path;
  21905. bindView.pathRoot = property.root;
  21906. hash[boundOption] = normalizedValue.call(bindView);
  21907. }
  21908. for (loc = 0; loc < numProperties; ++loc) {
  21909. property = normalizedProperties[loc];
  21910. if (property) {
  21911. bindView.path = property.path;
  21912. bindView.pathRoot = property.root;
  21913. args.push(normalizedValue.call(bindView));
  21914. } else {
  21915. args.push(properties[loc]);
  21916. }
  21917. }
  21918. args.push(options);
  21919. // Run the supplied helper function.
  21920. return fn.apply(currentContext, args);
  21921. };
  21922. view.appendChild(bindView);
  21923. // Assemble list of watched properties that'll re-render this helper.
  21924. for (boundOption in boundOptions) {
  21925. if (boundOptions.hasOwnProperty(boundOption)) {
  21926. watchedProperties.push(normalizePath(currentContext, boundOptions[boundOption], data));
  21927. }
  21928. }
  21929. // Observe each property.
  21930. for (loc = 0, len = watchedProperties.length; loc < len; ++loc) {
  21931. property = watchedProperties[loc];
  21932. view.registerObserver(property.root, property.path, bindView, bindView.rerender);
  21933. }
  21934. if (types[0] !== 'ID' || normalizedProperties.length === 0) {
  21935. return;
  21936. }
  21937. // Add dependent key observers to the first param
  21938. var normalized = normalizedProperties[0],
  21939. pathRoot = normalized.root,
  21940. path = normalized.path;
  21941. if(!Ember.isEmpty(path)) {
  21942. prefixPathForDependentKeys = path + '.';
  21943. }
  21944. for (var i=0, l=dependentKeys.length; i<l; i++) {
  21945. view.registerObserver(pathRoot, prefixPathForDependentKeys + dependentKeys[i], bindView, bindView.rerender);
  21946. }
  21947. }
  21948. helper._rawFunction = fn;
  21949. return helper;
  21950. };
  21951. /**
  21952. Renders the unbound form of an otherwise bound helper function.
  21953. @private
  21954. @method evaluateUnboundHelper
  21955. @param {Function} fn
  21956. @param {Object} context
  21957. @param {Array} normalizedProperties
  21958. @param {String} options
  21959. */
  21960. function evaluateUnboundHelper(context, fn, normalizedProperties, options) {
  21961. var args = [],
  21962. hash = options.hash,
  21963. boundOptions = hash.boundOptions,
  21964. types = slice.call(options.types, 1),
  21965. loc,
  21966. len,
  21967. property,
  21968. propertyType,
  21969. boundOption;
  21970. for (boundOption in boundOptions) {
  21971. if (!boundOptions.hasOwnProperty(boundOption)) { continue; }
  21972. hash[boundOption] = Ember.Handlebars.get(context, boundOptions[boundOption], options);
  21973. }
  21974. for(loc = 0, len = normalizedProperties.length; loc < len; ++loc) {
  21975. property = normalizedProperties[loc];
  21976. propertyType = types[loc];
  21977. if(propertyType === "ID") {
  21978. args.push(Ember.Handlebars.get(property.root, property.path, options));
  21979. } else {
  21980. args.push(property.path);
  21981. }
  21982. }
  21983. args.push(options);
  21984. return fn.apply(context, args);
  21985. }
  21986. /**
  21987. Overrides Handlebars.template so that we can distinguish
  21988. user-created, top-level templates from inner contexts.
  21989. @private
  21990. @method template
  21991. @for Ember.Handlebars
  21992. @param {String} spec
  21993. */
  21994. Ember.Handlebars.template = function(spec) {
  21995. var t = originalTemplate(spec);
  21996. t.isTop = true;
  21997. return t;
  21998. };
  21999. })();
  22000. (function() {
  22001. /**
  22002. Mark a string as safe for unescaped output with Handlebars. If you
  22003. return HTML from a Handlebars helper, use this function to
  22004. ensure Handlebars does not escape the HTML.
  22005. ```javascript
  22006. Ember.String.htmlSafe('<div>someString</div>')
  22007. ```
  22008. @method htmlSafe
  22009. @for Ember.String
  22010. @static
  22011. @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars
  22012. */
  22013. Ember.String.htmlSafe = function(str) {
  22014. return new Handlebars.SafeString(str);
  22015. };
  22016. var htmlSafe = Ember.String.htmlSafe;
  22017. if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
  22018. /**
  22019. Mark a string as being safe for unescaped output with Handlebars.
  22020. ```javascript
  22021. '<div>someString</div>'.htmlSafe()
  22022. ```
  22023. See [Ember.String.htmlSafe](/api/classes/Ember.String.html#method_htmlSafe).
  22024. @method htmlSafe
  22025. @for String
  22026. @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars
  22027. */
  22028. String.prototype.htmlSafe = function() {
  22029. return htmlSafe(this);
  22030. };
  22031. }
  22032. })();
  22033. (function() {
  22034. Ember.Handlebars.resolvePaths = function(options) {
  22035. var ret = [],
  22036. contexts = options.contexts,
  22037. roots = options.roots,
  22038. data = options.data;
  22039. for (var i=0, l=contexts.length; i<l; i++) {
  22040. ret.push( Ember.Handlebars.get(roots[i], contexts[i], { data: data }) );
  22041. }
  22042. return ret;
  22043. };
  22044. })();
  22045. (function() {
  22046. /*jshint newcap:false*/
  22047. /**
  22048. @module ember
  22049. @submodule ember-handlebars
  22050. */
  22051. var set = Ember.set, get = Ember.get;
  22052. var Metamorph = requireModule('metamorph');
  22053. function notifyMutationListeners() {
  22054. Ember.run.once(Ember.View, 'notifyMutationListeners');
  22055. }
  22056. // DOMManager should just abstract dom manipulation between jquery and metamorph
  22057. var DOMManager = {
  22058. remove: function(view) {
  22059. view.morph.remove();
  22060. notifyMutationListeners();
  22061. },
  22062. prepend: function(view, html) {
  22063. view.morph.prepend(html);
  22064. notifyMutationListeners();
  22065. },
  22066. after: function(view, html) {
  22067. view.morph.after(html);
  22068. notifyMutationListeners();
  22069. },
  22070. html: function(view, html) {
  22071. view.morph.html(html);
  22072. notifyMutationListeners();
  22073. },
  22074. // This is messed up.
  22075. replace: function(view) {
  22076. var morph = view.morph;
  22077. view.transitionTo('preRender');
  22078. Ember.run.schedule('render', this, function renderMetamorphView() {
  22079. if (view.isDestroying) { return; }
  22080. view.clearRenderedChildren();
  22081. var buffer = view.renderToBuffer();
  22082. view.invokeRecursively(function(view) {
  22083. view.propertyWillChange('element');
  22084. });
  22085. view.triggerRecursively('willInsertElement');
  22086. morph.replaceWith(buffer.string());
  22087. view.transitionTo('inDOM');
  22088. view.invokeRecursively(function(view) {
  22089. view.propertyDidChange('element');
  22090. });
  22091. view.triggerRecursively('didInsertElement');
  22092. notifyMutationListeners();
  22093. });
  22094. },
  22095. empty: function(view) {
  22096. view.morph.html("");
  22097. notifyMutationListeners();
  22098. }
  22099. };
  22100. // The `morph` and `outerHTML` properties are internal only
  22101. // and not observable.
  22102. /**
  22103. @class _Metamorph
  22104. @namespace Ember
  22105. @private
  22106. */
  22107. Ember._Metamorph = Ember.Mixin.create({
  22108. isVirtual: true,
  22109. tagName: '',
  22110. instrumentName: 'metamorph',
  22111. init: function() {
  22112. this._super();
  22113. this.morph = Metamorph();
  22114. Ember.deprecate('Supplying a tagName to Metamorph views is unreliable and is deprecated. You may be setting the tagName on a Handlebars helper that creates a Metamorph.', !this.tagName);
  22115. },
  22116. beforeRender: function(buffer) {
  22117. buffer.push(this.morph.startTag());
  22118. buffer.pushOpeningTag();
  22119. },
  22120. afterRender: function(buffer) {
  22121. buffer.pushClosingTag();
  22122. buffer.push(this.morph.endTag());
  22123. },
  22124. createElement: function() {
  22125. var buffer = this.renderToBuffer();
  22126. this.outerHTML = buffer.string();
  22127. this.clearBuffer();
  22128. },
  22129. domManager: DOMManager
  22130. });
  22131. /**
  22132. @class _MetamorphView
  22133. @namespace Ember
  22134. @extends Ember.View
  22135. @uses Ember._Metamorph
  22136. @private
  22137. */
  22138. Ember._MetamorphView = Ember.View.extend(Ember._Metamorph);
  22139. /**
  22140. @class _SimpleMetamorphView
  22141. @namespace Ember
  22142. @extends Ember.CoreView
  22143. @uses Ember._Metamorph
  22144. @private
  22145. */
  22146. Ember._SimpleMetamorphView = Ember.CoreView.extend(Ember._Metamorph);
  22147. })();
  22148. (function() {
  22149. /*globals Handlebars */
  22150. /*jshint newcap:false*/
  22151. /**
  22152. @module ember
  22153. @submodule ember-handlebars
  22154. */
  22155. var get = Ember.get, set = Ember.set, handlebarsGet = Ember.Handlebars.get;
  22156. var Metamorph = requireModule('metamorph');
  22157. function SimpleHandlebarsView(path, pathRoot, isEscaped, templateData) {
  22158. this.path = path;
  22159. this.pathRoot = pathRoot;
  22160. this.isEscaped = isEscaped;
  22161. this.templateData = templateData;
  22162. this.morph = Metamorph();
  22163. this.state = 'preRender';
  22164. this.updateId = null;
  22165. this._parentView = null;
  22166. this.buffer = null;
  22167. }
  22168. Ember._SimpleHandlebarsView = SimpleHandlebarsView;
  22169. SimpleHandlebarsView.prototype = {
  22170. isVirtual: true,
  22171. isView: true,
  22172. destroy: function () {
  22173. if (this.updateId) {
  22174. Ember.run.cancel(this.updateId);
  22175. this.updateId = null;
  22176. }
  22177. if (this._parentView) {
  22178. this._parentView.removeChild(this);
  22179. }
  22180. this.morph = null;
  22181. this.state = 'destroyed';
  22182. },
  22183. propertyWillChange: Ember.K,
  22184. propertyDidChange: Ember.K,
  22185. normalizedValue: function() {
  22186. var path = this.path,
  22187. pathRoot = this.pathRoot,
  22188. result, templateData;
  22189. // Use the pathRoot as the result if no path is provided. This
  22190. // happens if the path is `this`, which gets normalized into
  22191. // a `pathRoot` of the current Handlebars context and a path
  22192. // of `''`.
  22193. if (path === '') {
  22194. result = pathRoot;
  22195. } else {
  22196. templateData = this.templateData;
  22197. result = handlebarsGet(pathRoot, path, { data: templateData });
  22198. }
  22199. return result;
  22200. },
  22201. renderToBuffer: function(buffer) {
  22202. var string = '';
  22203. string += this.morph.startTag();
  22204. string += this.render();
  22205. string += this.morph.endTag();
  22206. buffer.push(string);
  22207. },
  22208. render: function() {
  22209. // If not invoked via a triple-mustache ({{{foo}}}), escape
  22210. // the content of the template.
  22211. var escape = this.isEscaped;
  22212. var result = this.normalizedValue();
  22213. if (result === null || result === undefined) {
  22214. result = "";
  22215. } else if (!(result instanceof Handlebars.SafeString)) {
  22216. result = String(result);
  22217. }
  22218. if (escape) { result = Handlebars.Utils.escapeExpression(result); }
  22219. return result;
  22220. },
  22221. rerender: function() {
  22222. switch(this.state) {
  22223. case 'preRender':
  22224. case 'destroyed':
  22225. break;
  22226. case 'inBuffer':
  22227. throw new Ember.Error("Something you did tried to replace an {{expression}} before it was inserted into the DOM.");
  22228. case 'hasElement':
  22229. case 'inDOM':
  22230. this.updateId = Ember.run.scheduleOnce('render', this, 'update');
  22231. break;
  22232. }
  22233. return this;
  22234. },
  22235. update: function () {
  22236. this.updateId = null;
  22237. this.morph.html(this.render());
  22238. },
  22239. transitionTo: function(state) {
  22240. this.state = state;
  22241. }
  22242. };
  22243. var states = Ember.View.cloneStates(Ember.View.states), merge = Ember.merge;
  22244. merge(states._default, {
  22245. rerenderIfNeeded: Ember.K
  22246. });
  22247. merge(states.inDOM, {
  22248. rerenderIfNeeded: function(view) {
  22249. if (view.normalizedValue() !== view._lastNormalizedValue) {
  22250. view.rerender();
  22251. }
  22252. }
  22253. });
  22254. /**
  22255. `Ember._HandlebarsBoundView` is a private view created by the Handlebars
  22256. `{{bind}}` helpers that is used to keep track of bound properties.
  22257. Every time a property is bound using a `{{mustache}}`, an anonymous subclass
  22258. of `Ember._HandlebarsBoundView` is created with the appropriate sub-template
  22259. and context set up. When the associated property changes, just the template
  22260. for this view will re-render.
  22261. @class _HandlebarsBoundView
  22262. @namespace Ember
  22263. @extends Ember._MetamorphView
  22264. @private
  22265. */
  22266. Ember._HandlebarsBoundView = Ember._MetamorphView.extend({
  22267. instrumentName: 'boundHandlebars',
  22268. states: states,
  22269. /**
  22270. The function used to determine if the `displayTemplate` or
  22271. `inverseTemplate` should be rendered. This should be a function that takes
  22272. a value and returns a Boolean.
  22273. @property shouldDisplayFunc
  22274. @type Function
  22275. @default null
  22276. */
  22277. shouldDisplayFunc: null,
  22278. /**
  22279. Whether the template rendered by this view gets passed the context object
  22280. of its parent template, or gets passed the value of retrieving `path`
  22281. from the `pathRoot`.
  22282. For example, this is true when using the `{{#if}}` helper, because the
  22283. template inside the helper should look up properties relative to the same
  22284. object as outside the block. This would be `false` when used with `{{#with
  22285. foo}}` because the template should receive the object found by evaluating
  22286. `foo`.
  22287. @property preserveContext
  22288. @type Boolean
  22289. @default false
  22290. */
  22291. preserveContext: false,
  22292. /**
  22293. If `preserveContext` is true, this is the object that will be used
  22294. to render the template.
  22295. @property previousContext
  22296. @type Object
  22297. */
  22298. previousContext: null,
  22299. /**
  22300. The template to render when `shouldDisplayFunc` evaluates to `true`.
  22301. @property displayTemplate
  22302. @type Function
  22303. @default null
  22304. */
  22305. displayTemplate: null,
  22306. /**
  22307. The template to render when `shouldDisplayFunc` evaluates to `false`.
  22308. @property inverseTemplate
  22309. @type Function
  22310. @default null
  22311. */
  22312. inverseTemplate: null,
  22313. /**
  22314. The path to look up on `pathRoot` that is passed to
  22315. `shouldDisplayFunc` to determine which template to render.
  22316. In addition, if `preserveContext` is `false,` the object at this path will
  22317. be passed to the template when rendering.
  22318. @property path
  22319. @type String
  22320. @default null
  22321. */
  22322. path: null,
  22323. /**
  22324. The object from which the `path` will be looked up. Sometimes this is the
  22325. same as the `previousContext`, but in cases where this view has been
  22326. generated for paths that start with a keyword such as `view` or
  22327. `controller`, the path root will be that resolved object.
  22328. @property pathRoot
  22329. @type Object
  22330. */
  22331. pathRoot: null,
  22332. normalizedValue: function() {
  22333. var path = get(this, 'path'),
  22334. pathRoot = get(this, 'pathRoot'),
  22335. valueNormalizer = get(this, 'valueNormalizerFunc'),
  22336. result, templateData;
  22337. // Use the pathRoot as the result if no path is provided. This
  22338. // happens if the path is `this`, which gets normalized into
  22339. // a `pathRoot` of the current Handlebars context and a path
  22340. // of `''`.
  22341. if (path === '') {
  22342. result = pathRoot;
  22343. } else {
  22344. templateData = get(this, 'templateData');
  22345. result = handlebarsGet(pathRoot, path, { data: templateData });
  22346. }
  22347. return valueNormalizer ? valueNormalizer(result) : result;
  22348. },
  22349. rerenderIfNeeded: function() {
  22350. this.currentState.rerenderIfNeeded(this);
  22351. },
  22352. /**
  22353. Determines which template to invoke, sets up the correct state based on
  22354. that logic, then invokes the default `Ember.View` `render` implementation.
  22355. This method will first look up the `path` key on `pathRoot`,
  22356. then pass that value to the `shouldDisplayFunc` function. If that returns
  22357. `true,` the `displayTemplate` function will be rendered to DOM. Otherwise,
  22358. `inverseTemplate`, if specified, will be rendered.
  22359. For example, if this `Ember._HandlebarsBoundView` represented the `{{#with
  22360. foo}}` helper, it would look up the `foo` property of its context, and
  22361. `shouldDisplayFunc` would always return true. The object found by looking
  22362. up `foo` would be passed to `displayTemplate`.
  22363. @method render
  22364. @param {Ember.RenderBuffer} buffer
  22365. */
  22366. render: function(buffer) {
  22367. // If not invoked via a triple-mustache ({{{foo}}}), escape
  22368. // the content of the template.
  22369. var escape = get(this, 'isEscaped');
  22370. var shouldDisplay = get(this, 'shouldDisplayFunc'),
  22371. preserveContext = get(this, 'preserveContext'),
  22372. context = get(this, 'previousContext');
  22373. var _contextController = get(this, '_contextController');
  22374. var inverseTemplate = get(this, 'inverseTemplate'),
  22375. displayTemplate = get(this, 'displayTemplate');
  22376. var result = this.normalizedValue();
  22377. this._lastNormalizedValue = result;
  22378. // First, test the conditional to see if we should
  22379. // render the template or not.
  22380. if (shouldDisplay(result)) {
  22381. set(this, 'template', displayTemplate);
  22382. // If we are preserving the context (for example, if this
  22383. // is an #if block, call the template with the same object.
  22384. if (preserveContext) {
  22385. set(this, '_context', context);
  22386. } else {
  22387. // Otherwise, determine if this is a block bind or not.
  22388. // If so, pass the specified object to the template
  22389. if (displayTemplate) {
  22390. if (_contextController) {
  22391. set(_contextController, 'content', result);
  22392. result = _contextController;
  22393. }
  22394. set(this, '_context', result);
  22395. } else {
  22396. // This is not a bind block, just push the result of the
  22397. // expression to the render context and return.
  22398. if (result === null || result === undefined) {
  22399. result = "";
  22400. } else if (!(result instanceof Handlebars.SafeString)) {
  22401. result = String(result);
  22402. }
  22403. if (escape) { result = Handlebars.Utils.escapeExpression(result); }
  22404. buffer.push(result);
  22405. return;
  22406. }
  22407. }
  22408. } else if (inverseTemplate) {
  22409. set(this, 'template', inverseTemplate);
  22410. if (preserveContext) {
  22411. set(this, '_context', context);
  22412. } else {
  22413. set(this, '_context', result);
  22414. }
  22415. } else {
  22416. set(this, 'template', function() { return ''; });
  22417. }
  22418. return this._super(buffer);
  22419. }
  22420. });
  22421. })();
  22422. (function() {
  22423. /**
  22424. @module ember
  22425. @submodule ember-handlebars
  22426. */
  22427. var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
  22428. var handlebarsGet = Ember.Handlebars.get, normalizePath = Ember.Handlebars.normalizePath;
  22429. var handlebarsGetEscaped = Ember.Handlebars.getEscaped;
  22430. var forEach = Ember.ArrayPolyfills.forEach;
  22431. var o_create = Ember.create;
  22432. var EmberHandlebars = Ember.Handlebars, helpers = EmberHandlebars.helpers;
  22433. function exists(value) {
  22434. return !Ember.isNone(value);
  22435. }
  22436. // Binds a property into the DOM. This will create a hook in DOM that the
  22437. // KVO system will look for and update if the property changes.
  22438. function bind(property, options, preserveContext, shouldDisplay, valueNormalizer, childProperties) {
  22439. var data = options.data,
  22440. fn = options.fn,
  22441. inverse = options.inverse,
  22442. view = data.view,
  22443. currentContext = this,
  22444. normalized, observer, i;
  22445. normalized = normalizePath(currentContext, property, data);
  22446. // Set up observers for observable objects
  22447. if ('object' === typeof this) {
  22448. if (data.insideGroup) {
  22449. observer = function() {
  22450. Ember.run.once(view, 'rerender');
  22451. };
  22452. var template, context, result = handlebarsGet(currentContext, property, options);
  22453. result = valueNormalizer ? valueNormalizer(result) : result;
  22454. context = preserveContext ? currentContext : result;
  22455. if (shouldDisplay(result)) {
  22456. template = fn;
  22457. } else if (inverse) {
  22458. template = inverse;
  22459. }
  22460. template(context, { data: options.data });
  22461. } else {
  22462. // Create the view that will wrap the output of this template/property
  22463. // and add it to the nearest view's childViews array.
  22464. // See the documentation of Ember._HandlebarsBoundView for more.
  22465. var bindView = view.createChildView(Ember._HandlebarsBoundView, {
  22466. preserveContext: preserveContext,
  22467. shouldDisplayFunc: shouldDisplay,
  22468. valueNormalizerFunc: valueNormalizer,
  22469. displayTemplate: fn,
  22470. inverseTemplate: inverse,
  22471. path: property,
  22472. pathRoot: currentContext,
  22473. previousContext: currentContext,
  22474. isEscaped: !options.hash.unescaped,
  22475. templateData: options.data
  22476. });
  22477. if (options.hash.controller) {
  22478. bindView.set('_contextController', this.container.lookupFactory('controller:'+options.hash.controller).create({
  22479. container: currentContext.container,
  22480. parentController: currentContext,
  22481. target: currentContext
  22482. }));
  22483. }
  22484. view.appendChild(bindView);
  22485. observer = function() {
  22486. Ember.run.scheduleOnce('render', bindView, 'rerenderIfNeeded');
  22487. };
  22488. }
  22489. // Observes the given property on the context and
  22490. // tells the Ember._HandlebarsBoundView to re-render. If property
  22491. // is an empty string, we are printing the current context
  22492. // object ({{this}}) so updating it is not our responsibility.
  22493. if (normalized.path !== '') {
  22494. view.registerObserver(normalized.root, normalized.path, observer);
  22495. if (childProperties) {
  22496. for (i=0; i<childProperties.length; i++) {
  22497. view.registerObserver(normalized.root, normalized.path+'.'+childProperties[i], observer);
  22498. }
  22499. }
  22500. }
  22501. } else {
  22502. // The object is not observable, so just render it out and
  22503. // be done with it.
  22504. data.buffer.push(handlebarsGetEscaped(currentContext, property, options));
  22505. }
  22506. }
  22507. EmberHandlebars.bind = bind;
  22508. function simpleBind(currentContext, property, options) {
  22509. var data = options.data,
  22510. view = data.view,
  22511. normalized, observer, pathRoot, output;
  22512. normalized = normalizePath(currentContext, property, data);
  22513. pathRoot = normalized.root;
  22514. // Set up observers for observable objects
  22515. if (pathRoot && ('object' === typeof pathRoot)) {
  22516. if (data.insideGroup) {
  22517. observer = function() {
  22518. Ember.run.once(view, 'rerender');
  22519. };
  22520. output = handlebarsGetEscaped(currentContext, property, options);
  22521. data.buffer.push(output);
  22522. } else {
  22523. var bindView = new Ember._SimpleHandlebarsView(
  22524. property, currentContext, !options.hash.unescaped, options.data
  22525. );
  22526. bindView._parentView = view;
  22527. view.appendChild(bindView);
  22528. observer = function() {
  22529. Ember.run.scheduleOnce('render', bindView, 'rerender');
  22530. };
  22531. }
  22532. // Observes the given property on the context and
  22533. // tells the Ember._HandlebarsBoundView to re-render. If property
  22534. // is an empty string, we are printing the current context
  22535. // object ({{this}}) so updating it is not our responsibility.
  22536. if (normalized.path !== '') {
  22537. view.registerObserver(normalized.root, normalized.path, observer);
  22538. }
  22539. } else {
  22540. // The object is not observable, so just render it out and
  22541. // be done with it.
  22542. output = handlebarsGetEscaped(currentContext, property, options);
  22543. data.buffer.push(output);
  22544. }
  22545. }
  22546. function shouldDisplayIfHelperContent(result) {
  22547. var truthy = result && get(result, 'isTruthy');
  22548. if (typeof truthy === 'boolean') { return truthy; }
  22549. if (Ember.isArray(result)) {
  22550. return get(result, 'length') !== 0;
  22551. } else {
  22552. return !!result;
  22553. }
  22554. }
  22555. /**
  22556. '_triageMustache' is used internally select between a binding, helper, or component for
  22557. the given context. Until this point, it would be hard to determine if the
  22558. mustache is a property reference or a regular helper reference. This triage
  22559. helper resolves that.
  22560. This would not be typically invoked by directly.
  22561. @private
  22562. @method _triageMustache
  22563. @for Ember.Handlebars.helpers
  22564. @param {String} property Property/helperID to triage
  22565. @param {Object} options hash of template/rendering options
  22566. @return {String} HTML string
  22567. */
  22568. EmberHandlebars.registerHelper('_triageMustache', function(property, options) {
  22569. Ember.assert("You cannot pass more than one argument to the _triageMustache helper", arguments.length <= 2);
  22570. if (helpers[property]) {
  22571. return helpers[property].call(this, options);
  22572. }
  22573. var helper = Ember.Handlebars.resolveHelper(options.data.view.container, property);
  22574. if (helper) {
  22575. return helper.call(this, options);
  22576. }
  22577. return helpers.bind.call(this, property, options);
  22578. });
  22579. Ember.Handlebars.resolveHelper = function(container, name) {
  22580. if (!container || name.indexOf('-') === -1) {
  22581. return;
  22582. }
  22583. var helper = container.lookup('helper:' + name);
  22584. if (!helper) {
  22585. var componentLookup = container.lookup('component-lookup:main');
  22586. Ember.assert("Could not find 'component-lookup:main' on the provided container, which is necessary for performing component lookups", componentLookup);
  22587. var Component = componentLookup.lookupFactory(name, container);
  22588. if (Component) {
  22589. helper = EmberHandlebars.makeViewHelper(Component);
  22590. container.register('helper:' + name, helper);
  22591. }
  22592. }
  22593. return helper;
  22594. };
  22595. /**
  22596. `bind` can be used to display a value, then update that value if it
  22597. changes. For example, if you wanted to print the `title` property of
  22598. `content`:
  22599. ```handlebars
  22600. {{bind "content.title"}}
  22601. ```
  22602. This will return the `title` property as a string, then create a new observer
  22603. at the specified path. If it changes, it will update the value in DOM. Note
  22604. that if you need to support IE7 and IE8 you must modify the model objects
  22605. properties using `Ember.get()` and `Ember.set()` for this to work as it
  22606. relies on Ember's KVO system. For all other browsers this will be handled for
  22607. you automatically.
  22608. @private
  22609. @method bind
  22610. @for Ember.Handlebars.helpers
  22611. @param {String} property Property to bind
  22612. @param {Function} fn Context to provide for rendering
  22613. @return {String} HTML string
  22614. */
  22615. EmberHandlebars.registerHelper('bind', function bindHelper(property, options) {
  22616. Ember.assert("You cannot pass more than one argument to the bind helper", arguments.length <= 2);
  22617. var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this;
  22618. if (!options.fn) {
  22619. return simpleBind(context, property, options);
  22620. }
  22621. return bind.call(context, property, options, false, exists);
  22622. });
  22623. /**
  22624. Use the `boundIf` helper to create a conditional that re-evaluates
  22625. whenever the truthiness of the bound value changes.
  22626. ```handlebars
  22627. {{#boundIf "content.shouldDisplayTitle"}}
  22628. {{content.title}}
  22629. {{/boundIf}}
  22630. ```
  22631. @private
  22632. @method boundIf
  22633. @for Ember.Handlebars.helpers
  22634. @param {String} property Property to bind
  22635. @param {Function} fn Context to provide for rendering
  22636. @return {String} HTML string
  22637. */
  22638. EmberHandlebars.registerHelper('boundIf', function boundIfHelper(property, fn) {
  22639. var context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this;
  22640. return bind.call(context, property, fn, true, shouldDisplayIfHelperContent, shouldDisplayIfHelperContent, ['isTruthy', 'length']);
  22641. });
  22642. /**
  22643. @private
  22644. Use the `unboundIf` helper to create a conditional that evaluates once.
  22645. ```handlebars
  22646. {{#unboundIf "content.shouldDisplayTitle"}}
  22647. {{content.title}}
  22648. {{/unboundIf}}
  22649. ```
  22650. @method unboundIf
  22651. @for Ember.Handlebars.helpers
  22652. @param {String} property Property to bind
  22653. @param {Function} fn Context to provide for rendering
  22654. @return {String} HTML string
  22655. */
  22656. EmberHandlebars.registerHelper('unboundIf', function unboundIfHelper(property, fn) {
  22657. var context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this,
  22658. data = fn.data,
  22659. template = fn.fn,
  22660. inverse = fn.inverse,
  22661. normalized, propertyValue, result;
  22662. normalized = normalizePath(context, property, data);
  22663. propertyValue = handlebarsGet(context, property, fn);
  22664. if (!shouldDisplayIfHelperContent(propertyValue)) {
  22665. template = inverse;
  22666. }
  22667. template(context, { data: data });
  22668. });
  22669. /**
  22670. Use the `{{with}}` helper when you want to scope context. Take the following code as an example:
  22671. ```handlebars
  22672. <h5>{{user.name}}</h5>
  22673. <div class="role">
  22674. <h6>{{user.role.label}}</h6>
  22675. <span class="role-id">{{user.role.id}}</span>
  22676. <p class="role-desc">{{user.role.description}}</p>
  22677. </div>
  22678. ```
  22679. `{{with}}` can be our best friend in these cases,
  22680. instead of writing `user.role.*` over and over, we use `{{#with user.role}}`.
  22681. Now the context within the `{{#with}} .. {{/with}}` block is `user.role` so you can do the following:
  22682. ```handlebars
  22683. <h5>{{user.name}}</h5>
  22684. <div class="role">
  22685. {{#with user.role}}
  22686. <h6>{{label}}</h6>
  22687. <span class="role-id">{{id}}</span>
  22688. <p class="role-desc">{{description}}</p>
  22689. {{/with}}
  22690. </div>
  22691. ```
  22692. ### `as` operator
  22693. This operator aliases the scope to a new name. It's helpful for semantic clarity and to retain
  22694. default scope or to reference from another `{{with}}` block.
  22695. ```handlebars
  22696. // posts might not be
  22697. {{#with user.posts as blogPosts}}
  22698. <div class="notice">
  22699. There are {{blogPosts.length}} blog posts written by {{user.name}}.
  22700. </div>
  22701. {{#each post in blogPosts}}
  22702. <li>{{post.title}}</li>
  22703. {{/each}}
  22704. {{/with}}
  22705. ```
  22706. Without the `as` operator, it would be impossible to reference `user.name` in the example above.
  22707. ### `controller` option
  22708. Adding `controller='something'` instructs the `{{with}}` helper to create and use an instance of
  22709. the specified controller with the new context as its content.
  22710. This is very similar to using an `itemController` option with the `{{each}}` helper.
  22711. ```handlebars
  22712. {{#with users.posts controller='userBlogPosts'}}
  22713. {{!- The current context is wrapped in our controller instance }}
  22714. {{/with}}
  22715. ```
  22716. In the above example, the template provided to the `{{with}}` block is now wrapped in the
  22717. `userBlogPost` controller, which provides a very elegant way to decorate the context with custom
  22718. functions/properties.
  22719. @method with
  22720. @for Ember.Handlebars.helpers
  22721. @param {Function} context
  22722. @param {Hash} options
  22723. @return {String} HTML string
  22724. */
  22725. EmberHandlebars.registerHelper('with', function withHelper(context, options) {
  22726. if (arguments.length === 4) {
  22727. var keywordName, path, rootPath, normalized, contextPath;
  22728. 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");
  22729. options = arguments[3];
  22730. keywordName = arguments[2];
  22731. path = arguments[0];
  22732. Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop);
  22733. var localizedOptions = o_create(options);
  22734. localizedOptions.data = o_create(options.data);
  22735. localizedOptions.data.keywords = o_create(options.data.keywords || {});
  22736. if (Ember.isGlobalPath(path)) {
  22737. contextPath = path;
  22738. } else {
  22739. normalized = normalizePath(this, path, options.data);
  22740. path = normalized.path;
  22741. rootPath = normalized.root;
  22742. // This is a workaround for the fact that you cannot bind separate objects
  22743. // together. When we implement that functionality, we should use it here.
  22744. var contextKey = Ember.$.expando + Ember.guidFor(rootPath);
  22745. localizedOptions.data.keywords[contextKey] = rootPath;
  22746. // if the path is '' ("this"), just bind directly to the current context
  22747. contextPath = path ? contextKey + '.' + path : contextKey;
  22748. }
  22749. Ember.bind(localizedOptions.data.keywords, keywordName, contextPath);
  22750. return bind.call(this, path, localizedOptions, true, exists);
  22751. } else {
  22752. Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2);
  22753. Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop);
  22754. return helpers.bind.call(options.contexts[0], context, options);
  22755. }
  22756. });
  22757. /**
  22758. See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf)
  22759. and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf)
  22760. @method if
  22761. @for Ember.Handlebars.helpers
  22762. @param {Function} context
  22763. @param {Hash} options
  22764. @return {String} HTML string
  22765. */
  22766. EmberHandlebars.registerHelper('if', function ifHelper(context, options) {
  22767. Ember.assert("You must pass exactly one argument to the if helper", arguments.length === 2);
  22768. Ember.assert("You must pass a block to the if helper", options.fn && options.fn !== Handlebars.VM.noop);
  22769. if (options.data.isUnbound) {
  22770. return helpers.unboundIf.call(options.contexts[0], context, options);
  22771. } else {
  22772. return helpers.boundIf.call(options.contexts[0], context, options);
  22773. }
  22774. });
  22775. /**
  22776. @method unless
  22777. @for Ember.Handlebars.helpers
  22778. @param {Function} context
  22779. @param {Hash} options
  22780. @return {String} HTML string
  22781. */
  22782. EmberHandlebars.registerHelper('unless', function unlessHelper(context, options) {
  22783. Ember.assert("You must pass exactly one argument to the unless helper", arguments.length === 2);
  22784. Ember.assert("You must pass a block to the unless helper", options.fn && options.fn !== Handlebars.VM.noop);
  22785. var fn = options.fn, inverse = options.inverse;
  22786. options.fn = inverse;
  22787. options.inverse = fn;
  22788. if (options.data.isUnbound) {
  22789. return helpers.unboundIf.call(options.contexts[0], context, options);
  22790. } else {
  22791. return helpers.boundIf.call(options.contexts[0], context, options);
  22792. }
  22793. });
  22794. /**
  22795. `bind-attr` allows you to create a binding between DOM element attributes and
  22796. Ember objects. For example:
  22797. ```handlebars
  22798. <img {{bind-attr src="imageUrl" alt="imageTitle"}}>
  22799. ```
  22800. The above handlebars template will fill the `<img>`'s `src` attribute will
  22801. the value of the property referenced with `"imageUrl"` and its `alt`
  22802. attribute with the value of the property referenced with `"imageTitle"`.
  22803. If the rendering context of this template is the following object:
  22804. ```javascript
  22805. {
  22806. imageUrl: 'http://lolcats.info/haz-a-funny',
  22807. imageTitle: 'A humorous image of a cat'
  22808. }
  22809. ```
  22810. The resulting HTML output will be:
  22811. ```html
  22812. <img src="http://lolcats.info/haz-a-funny" alt="A humorous image of a cat">
  22813. ```
  22814. `bind-attr` cannot redeclare existing DOM element attributes. The use of `src`
  22815. in the following `bind-attr` example will be ignored and the hard coded value
  22816. of `src="/failwhale.gif"` will take precedence:
  22817. ```handlebars
  22818. <img src="/failwhale.gif" {{bind-attr src="imageUrl" alt="imageTitle"}}>
  22819. ```
  22820. ### `bind-attr` and the `class` attribute
  22821. `bind-attr` supports a special syntax for handling a number of cases unique
  22822. to the `class` DOM element attribute. The `class` attribute combines
  22823. multiple discrete values into a single attribute as a space-delimited
  22824. list of strings. Each string can be:
  22825. * a string return value of an object's property.
  22826. * a boolean return value of an object's property
  22827. * a hard-coded value
  22828. A string return value works identically to other uses of `bind-attr`. The
  22829. return value of the property will become the value of the attribute. For
  22830. example, the following view and template:
  22831. ```javascript
  22832. AView = Ember.View.extend({
  22833. someProperty: function() {
  22834. return "aValue";
  22835. }.property()
  22836. })
  22837. ```
  22838. ```handlebars
  22839. <img {{bind-attr class="view.someProperty}}>
  22840. ```
  22841. Result in the following rendered output:
  22842. ```html
  22843. <img class="aValue">
  22844. ```
  22845. A boolean return value will insert a specified class name if the property
  22846. returns `true` and remove the class name if the property returns `false`.
  22847. A class name is provided via the syntax
  22848. `somePropertyName:class-name-if-true`.
  22849. ```javascript
  22850. AView = Ember.View.extend({
  22851. someBool: true
  22852. })
  22853. ```
  22854. ```handlebars
  22855. <img {{bind-attr class="view.someBool:class-name-if-true"}}>
  22856. ```
  22857. Result in the following rendered output:
  22858. ```html
  22859. <img class="class-name-if-true">
  22860. ```
  22861. An additional section of the binding can be provided if you want to
  22862. replace the existing class instead of removing it when the boolean
  22863. value changes:
  22864. ```handlebars
  22865. <img {{bind-attr class="view.someBool:class-name-if-true:class-name-if-false"}}>
  22866. ```
  22867. A hard-coded value can be used by prepending `:` to the desired
  22868. class name: `:class-name-to-always-apply`.
  22869. ```handlebars
  22870. <img {{bind-attr class=":class-name-to-always-apply"}}>
  22871. ```
  22872. Results in the following rendered output:
  22873. ```html
  22874. <img class="class-name-to-always-apply">
  22875. ```
  22876. All three strategies - string return value, boolean return value, and
  22877. hard-coded value – can be combined in a single declaration:
  22878. ```handlebars
  22879. <img {{bind-attr class=":class-name-to-always-apply view.someBool:class-name-if-true view.someProperty"}}>
  22880. ```
  22881. @method bind-attr
  22882. @for Ember.Handlebars.helpers
  22883. @param {Hash} options
  22884. @return {String} HTML string
  22885. */
  22886. EmberHandlebars.registerHelper('bind-attr', function bindAttrHelper(options) {
  22887. var attrs = options.hash;
  22888. Ember.assert("You must specify at least one hash argument to bind-attr", !!Ember.keys(attrs).length);
  22889. var view = options.data.view;
  22890. var ret = [];
  22891. var ctx = this;
  22892. // Generate a unique id for this element. This will be added as a
  22893. // data attribute to the element so it can be looked up when
  22894. // the bound property changes.
  22895. var dataId = ++Ember.uuid;
  22896. // Handle classes differently, as we can bind multiple classes
  22897. var classBindings = attrs['class'];
  22898. if (classBindings != null) {
  22899. var classResults = EmberHandlebars.bindClasses(this, classBindings, view, dataId, options);
  22900. ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"');
  22901. delete attrs['class'];
  22902. }
  22903. var attrKeys = Ember.keys(attrs);
  22904. // For each attribute passed, create an observer and emit the
  22905. // current value of the property as an attribute.
  22906. forEach.call(attrKeys, function(attr) {
  22907. var path = attrs[attr],
  22908. normalized;
  22909. Ember.assert(fmt("You must provide an expression as the value of bound attribute. You specified: %@=%@", [attr, path]), typeof path === 'string');
  22910. normalized = normalizePath(ctx, path, options.data);
  22911. var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options),
  22912. type = Ember.typeOf(value);
  22913. Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean');
  22914. var observer, invoker;
  22915. observer = function observer() {
  22916. var result = handlebarsGet(ctx, path, options);
  22917. Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]),
  22918. result === null || result === undefined || typeof result === 'number' ||
  22919. typeof result === 'string' || typeof result === 'boolean');
  22920. var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']");
  22921. // If we aren't able to find the element, it means the element
  22922. // to which we were bound has been removed from the view.
  22923. // In that case, we can assume the template has been re-rendered
  22924. // and we need to clean up the observer.
  22925. if (!elem || elem.length === 0) {
  22926. Ember.removeObserver(normalized.root, normalized.path, invoker);
  22927. return;
  22928. }
  22929. Ember.View.applyAttributeBindings(elem, attr, result);
  22930. };
  22931. // Add an observer to the view for when the property changes.
  22932. // When the observer fires, find the element using the
  22933. // unique data id and update the attribute to the new value.
  22934. // Note: don't add observer when path is 'this' or path
  22935. // is whole keyword e.g. {{#each x in list}} ... {{bind-attr attr="x"}}
  22936. if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) {
  22937. view.registerObserver(normalized.root, normalized.path, observer);
  22938. }
  22939. // if this changes, also change the logic in ember-views/lib/views/view.js
  22940. if ((type === 'string' || (type === 'number' && !isNaN(value)))) {
  22941. ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"');
  22942. } else if (value && type === 'boolean') {
  22943. // The developer controls the attr name, so it should always be safe
  22944. ret.push(attr + '="' + attr + '"');
  22945. }
  22946. }, this);
  22947. // Add the unique identifier
  22948. // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG
  22949. ret.push('data-bindattr-' + dataId + '="' + dataId + '"');
  22950. return new EmberHandlebars.SafeString(ret.join(' '));
  22951. });
  22952. /**
  22953. See `bind-attr`
  22954. @method bindAttr
  22955. @for Ember.Handlebars.helpers
  22956. @deprecated
  22957. @param {Function} context
  22958. @param {Hash} options
  22959. @return {String} HTML string
  22960. */
  22961. EmberHandlebars.registerHelper('bindAttr', function bindAttrHelper() {
  22962. Ember.warn("The 'bindAttr' view helper is deprecated in favor of 'bind-attr'");
  22963. return EmberHandlebars.helpers['bind-attr'].apply(this, arguments);
  22964. });
  22965. /**
  22966. Helper that, given a space-separated string of property paths and a context,
  22967. returns an array of class names. Calling this method also has the side
  22968. effect of setting up observers at those property paths, such that if they
  22969. change, the correct class name will be reapplied to the DOM element.
  22970. For example, if you pass the string "fooBar", it will first look up the
  22971. "fooBar" value of the context. If that value is true, it will add the
  22972. "foo-bar" class to the current element (i.e., the dasherized form of
  22973. "fooBar"). If the value is a string, it will add that string as the class.
  22974. Otherwise, it will not add any new class name.
  22975. @private
  22976. @method bindClasses
  22977. @for Ember.Handlebars
  22978. @param {Ember.Object} context The context from which to lookup properties
  22979. @param {String} classBindings A string, space-separated, of class bindings
  22980. to use
  22981. @param {Ember.View} view The view in which observers should look for the
  22982. element to update
  22983. @param {Srting} bindAttrId Optional bindAttr id used to lookup elements
  22984. @return {Array} An array of class names to add
  22985. */
  22986. EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId, options) {
  22987. var ret = [], newClass, value, elem;
  22988. // Helper method to retrieve the property from the context and
  22989. // determine which class string to return, based on whether it is
  22990. // a Boolean or not.
  22991. var classStringForPath = function(root, parsedPath, options) {
  22992. var val,
  22993. path = parsedPath.path;
  22994. if (path === 'this') {
  22995. val = root;
  22996. } else if (path === '') {
  22997. val = true;
  22998. } else {
  22999. val = handlebarsGet(root, path, options);
  23000. }
  23001. return Ember.View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName);
  23002. };
  23003. // For each property passed, loop through and setup
  23004. // an observer.
  23005. forEach.call(classBindings.split(' '), function(binding) {
  23006. // Variable in which the old class value is saved. The observer function
  23007. // closes over this variable, so it knows which string to remove when
  23008. // the property changes.
  23009. var oldClass;
  23010. var observer, invoker;
  23011. var parsedPath = Ember.View._parsePropertyPath(binding),
  23012. path = parsedPath.path,
  23013. pathRoot = context,
  23014. normalized;
  23015. if (path !== '' && path !== 'this') {
  23016. normalized = normalizePath(context, path, options.data);
  23017. pathRoot = normalized.root;
  23018. path = normalized.path;
  23019. }
  23020. // Set up an observer on the context. If the property changes, toggle the
  23021. // class name.
  23022. observer = function() {
  23023. // Get the current value of the property
  23024. newClass = classStringForPath(context, parsedPath, options);
  23025. elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$();
  23026. // If we can't find the element anymore, a parent template has been
  23027. // re-rendered and we've been nuked. Remove the observer.
  23028. if (!elem || elem.length === 0) {
  23029. Ember.removeObserver(pathRoot, path, invoker);
  23030. } else {
  23031. // If we had previously added a class to the element, remove it.
  23032. if (oldClass) {
  23033. elem.removeClass(oldClass);
  23034. }
  23035. // If necessary, add a new class. Make sure we keep track of it so
  23036. // it can be removed in the future.
  23037. if (newClass) {
  23038. elem.addClass(newClass);
  23039. oldClass = newClass;
  23040. } else {
  23041. oldClass = null;
  23042. }
  23043. }
  23044. };
  23045. if (path !== '' && path !== 'this') {
  23046. view.registerObserver(pathRoot, path, observer);
  23047. }
  23048. // We've already setup the observer; now we just need to figure out the
  23049. // correct behavior right now on the first pass through.
  23050. value = classStringForPath(context, parsedPath, options);
  23051. if (value) {
  23052. ret.push(value);
  23053. // Make sure we save the current value so that it can be removed if the
  23054. // observer fires.
  23055. oldClass = value;
  23056. }
  23057. });
  23058. return ret;
  23059. };
  23060. })();
  23061. (function() {
  23062. /*globals Handlebars */
  23063. // TODO: Don't require the entire module
  23064. /**
  23065. @module ember
  23066. @submodule ember-handlebars
  23067. */
  23068. var get = Ember.get, set = Ember.set;
  23069. var EmberHandlebars = Ember.Handlebars;
  23070. var LOWERCASE_A_Z = /^[a-z]/;
  23071. var VIEW_PREFIX = /^view\./;
  23072. function makeBindings(thisContext, options) {
  23073. var hash = options.hash,
  23074. hashType = options.hashTypes;
  23075. for (var prop in hash) {
  23076. if (hashType[prop] === 'ID') {
  23077. var value = hash[prop];
  23078. if (Ember.IS_BINDING.test(prop)) {
  23079. Ember.warn("You're attempting to render a view by passing " + prop + "=" + value + " to a view helper, but this syntax is ambiguous. You should either surround " + value + " in quotes or remove `Binding` from " + prop + ".");
  23080. } else {
  23081. hash[prop + 'Binding'] = value;
  23082. hashType[prop + 'Binding'] = 'STRING';
  23083. delete hash[prop];
  23084. delete hashType[prop];
  23085. }
  23086. }
  23087. }
  23088. if (hash.hasOwnProperty('idBinding')) {
  23089. // id can't be bound, so just perform one-time lookup.
  23090. hash.id = EmberHandlebars.get(thisContext, hash.idBinding, options);
  23091. hashType.id = 'STRING';
  23092. delete hash.idBinding;
  23093. delete hashType.idBinding;
  23094. }
  23095. }
  23096. EmberHandlebars.ViewHelper = Ember.Object.create({
  23097. propertiesFromHTMLOptions: function(options) {
  23098. var hash = options.hash, data = options.data;
  23099. var extensions = {},
  23100. classes = hash['class'],
  23101. dup = false;
  23102. if (hash.id) {
  23103. extensions.elementId = hash.id;
  23104. dup = true;
  23105. }
  23106. if (hash.tag) {
  23107. extensions.tagName = hash.tag;
  23108. dup = true;
  23109. }
  23110. if (classes) {
  23111. classes = classes.split(' ');
  23112. extensions.classNames = classes;
  23113. dup = true;
  23114. }
  23115. if (hash.classBinding) {
  23116. extensions.classNameBindings = hash.classBinding.split(' ');
  23117. dup = true;
  23118. }
  23119. if (hash.classNameBindings) {
  23120. if (extensions.classNameBindings === undefined) extensions.classNameBindings = [];
  23121. extensions.classNameBindings = extensions.classNameBindings.concat(hash.classNameBindings.split(' '));
  23122. dup = true;
  23123. }
  23124. if (hash.attributeBindings) {
  23125. Ember.assert("Setting 'attributeBindings' via Handlebars is not allowed. Please subclass Ember.View and set it there instead.");
  23126. extensions.attributeBindings = null;
  23127. dup = true;
  23128. }
  23129. if (dup) {
  23130. hash = Ember.$.extend({}, hash);
  23131. delete hash.id;
  23132. delete hash.tag;
  23133. delete hash['class'];
  23134. delete hash.classBinding;
  23135. }
  23136. // Set the proper context for all bindings passed to the helper. This applies to regular attribute bindings
  23137. // as well as class name bindings. If the bindings are local, make them relative to the current context
  23138. // instead of the view.
  23139. var path;
  23140. // Evaluate the context of regular attribute bindings:
  23141. for (var prop in hash) {
  23142. if (!hash.hasOwnProperty(prop)) { continue; }
  23143. // Test if the property ends in "Binding"
  23144. if (Ember.IS_BINDING.test(prop) && typeof hash[prop] === 'string') {
  23145. path = this.contextualizeBindingPath(hash[prop], data);
  23146. if (path) { hash[prop] = path; }
  23147. }
  23148. }
  23149. // Evaluate the context of class name bindings:
  23150. if (extensions.classNameBindings) {
  23151. for (var b in extensions.classNameBindings) {
  23152. var full = extensions.classNameBindings[b];
  23153. if (typeof full === 'string') {
  23154. // Contextualize the path of classNameBinding so this:
  23155. //
  23156. // classNameBinding="isGreen:green"
  23157. //
  23158. // is converted to this:
  23159. //
  23160. // classNameBinding="_parentView.context.isGreen:green"
  23161. var parsedPath = Ember.View._parsePropertyPath(full);
  23162. path = this.contextualizeBindingPath(parsedPath.path, data);
  23163. if (path) { extensions.classNameBindings[b] = path + parsedPath.classNames; }
  23164. }
  23165. }
  23166. }
  23167. return Ember.$.extend(hash, extensions);
  23168. },
  23169. // Transform bindings from the current context to a context that can be evaluated within the view.
  23170. // Returns null if the path shouldn't be changed.
  23171. //
  23172. // TODO: consider the addition of a prefix that would allow this method to return `path`.
  23173. contextualizeBindingPath: function(path, data) {
  23174. var normalized = Ember.Handlebars.normalizePath(null, path, data);
  23175. if (normalized.isKeyword) {
  23176. return 'templateData.keywords.' + path;
  23177. } else if (Ember.isGlobalPath(path)) {
  23178. return null;
  23179. } else if (path === 'this' || path === '') {
  23180. return '_parentView.context';
  23181. } else {
  23182. return '_parentView.context.' + path;
  23183. }
  23184. },
  23185. helper: function(thisContext, path, options) {
  23186. var data = options.data,
  23187. fn = options.fn,
  23188. newView;
  23189. makeBindings(thisContext, options);
  23190. if ('string' === typeof path) {
  23191. // TODO: this is a lame conditional, this should likely change
  23192. // but something along these lines will likely need to be added
  23193. // as deprecation warnings
  23194. //
  23195. if (options.types[0] === 'STRING' && LOWERCASE_A_Z.test(path) && !VIEW_PREFIX.test(path)) {
  23196. Ember.assert("View requires a container", !!data.view.container);
  23197. newView = data.view.container.lookupFactory('view:' + path);
  23198. } else {
  23199. newView = EmberHandlebars.get(thisContext, path, options);
  23200. }
  23201. Ember.assert("Unable to find view at path '" + path + "'", !!newView);
  23202. } else {
  23203. newView = path;
  23204. }
  23205. 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));
  23206. var viewOptions = this.propertiesFromHTMLOptions(options, thisContext);
  23207. var currentView = data.view;
  23208. viewOptions.templateData = data;
  23209. var newViewProto = newView.proto ? newView.proto() : newView;
  23210. if (fn) {
  23211. Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newViewProto, 'templateName'));
  23212. viewOptions.template = fn;
  23213. }
  23214. // We only want to override the `_context` computed property if there is
  23215. // no specified controller. See View#_context for more information.
  23216. if (!newViewProto.controller && !newViewProto.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) {
  23217. viewOptions._context = thisContext;
  23218. }
  23219. currentView.appendChild(newView, viewOptions);
  23220. }
  23221. });
  23222. /**
  23223. `{{view}}` inserts a new instance of `Ember.View` into a template passing its
  23224. options to the `Ember.View`'s `create` method and using the supplied block as
  23225. the view's own template.
  23226. An empty `<body>` and the following template:
  23227. ```handlebars
  23228. A span:
  23229. {{#view tagName="span"}}
  23230. hello.
  23231. {{/view}}
  23232. ```
  23233. Will result in HTML structure:
  23234. ```html
  23235. <body>
  23236. <!-- Note: the handlebars template script
  23237. also results in a rendered Ember.View
  23238. which is the outer <div> here -->
  23239. <div class="ember-view">
  23240. A span:
  23241. <span id="ember1" class="ember-view">
  23242. Hello.
  23243. </span>
  23244. </div>
  23245. </body>
  23246. ```
  23247. ### `parentView` setting
  23248. The `parentView` property of the new `Ember.View` instance created through
  23249. `{{view}}` will be set to the `Ember.View` instance of the template where
  23250. `{{view}}` was called.
  23251. ```javascript
  23252. aView = Ember.View.create({
  23253. template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}")
  23254. });
  23255. aView.appendTo('body');
  23256. ```
  23257. Will result in HTML structure:
  23258. ```html
  23259. <div id="ember1" class="ember-view">
  23260. <div id="ember2" class="ember-view">
  23261. my parent: ember1
  23262. </div>
  23263. </div>
  23264. ```
  23265. ### Setting CSS id and class attributes
  23266. The HTML `id` attribute can be set on the `{{view}}`'s resulting element with
  23267. the `id` option. This option will _not_ be passed to `Ember.View.create`.
  23268. ```handlebars
  23269. {{#view tagName="span" id="a-custom-id"}}
  23270. hello.
  23271. {{/view}}
  23272. ```
  23273. Results in the following HTML structure:
  23274. ```html
  23275. <div class="ember-view">
  23276. <span id="a-custom-id" class="ember-view">
  23277. hello.
  23278. </span>
  23279. </div>
  23280. ```
  23281. The HTML `class` attribute can be set on the `{{view}}`'s resulting element
  23282. with the `class` or `classNameBindings` options. The `class` option will
  23283. directly set the CSS `class` attribute and will not be passed to
  23284. `Ember.View.create`. `classNameBindings` will be passed to `create` and use
  23285. `Ember.View`'s class name binding functionality:
  23286. ```handlebars
  23287. {{#view tagName="span" class="a-custom-class"}}
  23288. hello.
  23289. {{/view}}
  23290. ```
  23291. Results in the following HTML structure:
  23292. ```html
  23293. <div class="ember-view">
  23294. <span id="ember2" class="ember-view a-custom-class">
  23295. hello.
  23296. </span>
  23297. </div>
  23298. ```
  23299. ### Supplying a different view class
  23300. `{{view}}` can take an optional first argument before its supplied options to
  23301. specify a path to a custom view class.
  23302. ```handlebars
  23303. {{#view "MyApp.CustomView"}}
  23304. hello.
  23305. {{/view}}
  23306. ```
  23307. The first argument can also be a relative path accessible from the current
  23308. context.
  23309. ```javascript
  23310. MyApp = Ember.Application.create({});
  23311. MyApp.OuterView = Ember.View.extend({
  23312. innerViewClass: Ember.View.extend({
  23313. classNames: ['a-custom-view-class-as-property']
  23314. }),
  23315. template: Ember.Handlebars.compile('{{#view "view.innerViewClass"}} hi {{/view}}')
  23316. });
  23317. MyApp.OuterView.create().appendTo('body');
  23318. ```
  23319. Will result in the following HTML:
  23320. ```html
  23321. <div id="ember1" class="ember-view">
  23322. <div id="ember2" class="ember-view a-custom-view-class-as-property">
  23323. hi
  23324. </div>
  23325. </div>
  23326. ```
  23327. ### Blockless use
  23328. If you supply a custom `Ember.View` subclass that specifies its own template
  23329. or provide a `templateName` option to `{{view}}` it can be used without
  23330. supplying a block. Attempts to use both a `templateName` option and supply a
  23331. block will throw an error.
  23332. ```handlebars
  23333. {{view "MyApp.ViewWithATemplateDefined"}}
  23334. ```
  23335. ### `viewName` property
  23336. You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance
  23337. will be referenced as a property of its parent view by this name.
  23338. ```javascript
  23339. aView = Ember.View.create({
  23340. template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}')
  23341. });
  23342. aView.appendTo('body');
  23343. aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper
  23344. ```
  23345. @method view
  23346. @for Ember.Handlebars.helpers
  23347. @param {String} path
  23348. @param {Hash} options
  23349. @return {String} HTML string
  23350. */
  23351. EmberHandlebars.registerHelper('view', function viewHelper(path, options) {
  23352. Ember.assert("The view helper only takes a single argument", arguments.length <= 2);
  23353. // If no path is provided, treat path param as options.
  23354. if (path && path.data && path.data.isRenderData) {
  23355. options = path;
  23356. path = "Ember.View";
  23357. }
  23358. return EmberHandlebars.ViewHelper.helper(this, path, options);
  23359. });
  23360. })();
  23361. (function() {
  23362. // TODO: Don't require all of this module
  23363. /**
  23364. @module ember
  23365. @submodule ember-handlebars
  23366. */
  23367. var get = Ember.get, handlebarsGet = Ember.Handlebars.get, fmt = Ember.String.fmt;
  23368. /**
  23369. `{{collection}}` is a `Ember.Handlebars` helper for adding instances of
  23370. `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html)
  23371. for additional information on how a `CollectionView` functions.
  23372. `{{collection}}`'s primary use is as a block helper with a `contentBinding`
  23373. option pointing towards an `Ember.Array`-compatible object. An `Ember.View`
  23374. instance will be created for each item in its `content` property. Each view
  23375. will have its own `content` property set to the appropriate item in the
  23376. collection.
  23377. The provided block will be applied as the template for each item's view.
  23378. Given an empty `<body>` the following template:
  23379. ```handlebars
  23380. {{#collection contentBinding="App.items"}}
  23381. Hi {{view.content.name}}
  23382. {{/collection}}
  23383. ```
  23384. And the following application code
  23385. ```javascript
  23386. App = Ember.Application.create()
  23387. App.items = [
  23388. Ember.Object.create({name: 'Dave'}),
  23389. Ember.Object.create({name: 'Mary'}),
  23390. Ember.Object.create({name: 'Sara'})
  23391. ]
  23392. ```
  23393. Will result in the HTML structure below
  23394. ```html
  23395. <div class="ember-view">
  23396. <div class="ember-view">Hi Dave</div>
  23397. <div class="ember-view">Hi Mary</div>
  23398. <div class="ember-view">Hi Sara</div>
  23399. </div>
  23400. ```
  23401. ### Blockless use in a collection
  23402. If you provide an `itemViewClass` option that has its own `template` you can
  23403. omit the block.
  23404. The following template:
  23405. ```handlebars
  23406. {{collection contentBinding="App.items" itemViewClass="App.AnItemView"}}
  23407. ```
  23408. And application code
  23409. ```javascript
  23410. App = Ember.Application.create();
  23411. App.items = [
  23412. Ember.Object.create({name: 'Dave'}),
  23413. Ember.Object.create({name: 'Mary'}),
  23414. Ember.Object.create({name: 'Sara'})
  23415. ];
  23416. App.AnItemView = Ember.View.extend({
  23417. template: Ember.Handlebars.compile("Greetings {{view.content.name}}")
  23418. });
  23419. ```
  23420. Will result in the HTML structure below
  23421. ```html
  23422. <div class="ember-view">
  23423. <div class="ember-view">Greetings Dave</div>
  23424. <div class="ember-view">Greetings Mary</div>
  23425. <div class="ember-view">Greetings Sara</div>
  23426. </div>
  23427. ```
  23428. ### Specifying a CollectionView subclass
  23429. By default the `{{collection}}` helper will create an instance of
  23430. `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to
  23431. the helper by passing it as the first argument:
  23432. ```handlebars
  23433. {{#collection App.MyCustomCollectionClass contentBinding="App.items"}}
  23434. Hi {{view.content.name}}
  23435. {{/collection}}
  23436. ```
  23437. ### Forwarded `item.*`-named Options
  23438. As with the `{{view}}`, helper options passed to the `{{collection}}` will be
  23439. set on the resulting `Ember.CollectionView` as properties. Additionally,
  23440. options prefixed with `item` will be applied to the views rendered for each
  23441. item (note the camelcasing):
  23442. ```handlebars
  23443. {{#collection contentBinding="App.items"
  23444. itemTagName="p"
  23445. itemClassNames="greeting"}}
  23446. Howdy {{view.content.name}}
  23447. {{/collection}}
  23448. ```
  23449. Will result in the following HTML structure:
  23450. ```html
  23451. <div class="ember-view">
  23452. <p class="ember-view greeting">Howdy Dave</p>
  23453. <p class="ember-view greeting">Howdy Mary</p>
  23454. <p class="ember-view greeting">Howdy Sara</p>
  23455. </div>
  23456. ```
  23457. @method collection
  23458. @for Ember.Handlebars.helpers
  23459. @param {String} path
  23460. @param {Hash} options
  23461. @return {String} HTML string
  23462. @deprecated Use `{{each}}` helper instead.
  23463. */
  23464. Ember.Handlebars.registerHelper('collection', function collectionHelper(path, options) {
  23465. Ember.deprecate("Using the {{collection}} helper without specifying a class has been deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection');
  23466. // If no path is provided, treat path param as options.
  23467. if (path && path.data && path.data.isRenderData) {
  23468. options = path;
  23469. path = undefined;
  23470. Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1);
  23471. } else {
  23472. Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2);
  23473. }
  23474. var fn = options.fn;
  23475. var data = options.data;
  23476. var inverse = options.inverse;
  23477. var view = options.data.view;
  23478. var controller, container;
  23479. // If passed a path string, convert that into an object.
  23480. // Otherwise, just default to the standard class.
  23481. var collectionClass;
  23482. if (path) {
  23483. controller = data.keywords.controller;
  23484. container = controller && controller.container;
  23485. collectionClass = handlebarsGet(this, path, options) || container.lookupFactory('view:' + path);
  23486. Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass);
  23487. }
  23488. else {
  23489. collectionClass = Ember.CollectionView;
  23490. }
  23491. var hash = options.hash, itemHash = {}, match;
  23492. // Extract item view class if provided else default to the standard class
  23493. var collectionPrototype = collectionClass.proto(),
  23494. itemViewClass;
  23495. if (hash.itemView) {
  23496. controller = data.keywords.controller;
  23497. Ember.assert('You specified an itemView, but the current context has no ' +
  23498. 'container to look the itemView up in. This probably means ' +
  23499. 'that you created a view manually, instead of through the ' +
  23500. 'container. Instead, use container.lookup("view:viewName"), ' +
  23501. 'which will properly instantiate your view.',
  23502. controller && controller.container);
  23503. container = controller.container;
  23504. itemViewClass = container.lookupFactory('view:' + hash.itemView);
  23505. Ember.assert('You specified the itemView ' + hash.itemView + ", but it was " +
  23506. "not found at " + container.describe("view:" + hash.itemView) +
  23507. " (and it was not registered in the container)", !!itemViewClass);
  23508. } else if (hash.itemViewClass) {
  23509. itemViewClass = handlebarsGet(collectionPrototype, hash.itemViewClass, options);
  23510. } else {
  23511. itemViewClass = collectionPrototype.itemViewClass;
  23512. }
  23513. Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewClass]), !!itemViewClass);
  23514. delete hash.itemViewClass;
  23515. delete hash.itemView;
  23516. // Go through options passed to the {{collection}} helper and extract options
  23517. // that configure item views instead of the collection itself.
  23518. for (var prop in hash) {
  23519. if (hash.hasOwnProperty(prop)) {
  23520. match = prop.match(/^item(.)(.*)$/);
  23521. if (match && prop !== 'itemController') {
  23522. // Convert itemShouldFoo -> shouldFoo
  23523. itemHash[match[1].toLowerCase() + match[2]] = hash[prop];
  23524. // Delete from hash as this will end up getting passed to the
  23525. // {{view}} helper method.
  23526. delete hash[prop];
  23527. }
  23528. }
  23529. }
  23530. if (fn) {
  23531. itemHash.template = fn;
  23532. delete options.fn;
  23533. }
  23534. var emptyViewClass;
  23535. if (inverse && inverse !== Ember.Handlebars.VM.noop) {
  23536. emptyViewClass = get(collectionPrototype, 'emptyViewClass');
  23537. emptyViewClass = emptyViewClass.extend({
  23538. template: inverse,
  23539. tagName: itemHash.tagName
  23540. });
  23541. } else if (hash.emptyViewClass) {
  23542. emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options);
  23543. }
  23544. if (emptyViewClass) { hash.emptyView = emptyViewClass; }
  23545. if (!hash.keyword) {
  23546. itemHash._context = Ember.computed.alias('content');
  23547. }
  23548. var viewOptions = Ember.Handlebars.ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this);
  23549. hash.itemViewClass = itemViewClass.extend(viewOptions);
  23550. return Ember.Handlebars.helpers.view.call(this, collectionClass, options);
  23551. });
  23552. })();
  23553. (function() {
  23554. /*globals Handlebars */
  23555. /**
  23556. @module ember
  23557. @submodule ember-handlebars
  23558. */
  23559. var handlebarsGet = Ember.Handlebars.get;
  23560. /**
  23561. `unbound` allows you to output a property without binding. *Important:* The
  23562. output will not be updated if the property changes. Use with caution.
  23563. ```handlebars
  23564. <div>{{unbound somePropertyThatDoesntChange}}</div>
  23565. ```
  23566. `unbound` can also be used in conjunction with a bound helper to
  23567. render it in its unbound form:
  23568. ```handlebars
  23569. <div>{{unbound helperName somePropertyThatDoesntChange}}</div>
  23570. ```
  23571. @method unbound
  23572. @for Ember.Handlebars.helpers
  23573. @param {String} property
  23574. @return {String} HTML string
  23575. */
  23576. Ember.Handlebars.registerHelper('unbound', function unboundHelper(property, fn) {
  23577. var options = arguments[arguments.length - 1], helper, context, out;
  23578. if (arguments.length > 2) {
  23579. // Unbound helper call.
  23580. options.data.isUnbound = true;
  23581. helper = Ember.Handlebars.helpers[arguments[0]] || Ember.Handlebars.helpers.helperMissing;
  23582. out = helper.apply(this, Array.prototype.slice.call(arguments, 1));
  23583. delete options.data.isUnbound;
  23584. return out;
  23585. }
  23586. context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this;
  23587. return handlebarsGet(context, property, fn);
  23588. });
  23589. })();
  23590. (function() {
  23591. /*jshint debug:true*/
  23592. /**
  23593. @module ember
  23594. @submodule ember-handlebars
  23595. */
  23596. var get = Ember.get, handlebarsGet = Ember.Handlebars.get, normalizePath = Ember.Handlebars.normalizePath;
  23597. /**
  23598. `log` allows you to output the value of a variable in the current rendering
  23599. context.
  23600. ```handlebars
  23601. {{log myVariable}}
  23602. ```
  23603. @method log
  23604. @for Ember.Handlebars.helpers
  23605. @param {String} property
  23606. */
  23607. Ember.Handlebars.registerHelper('log', function logHelper(property, options) {
  23608. var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this,
  23609. normalized = normalizePath(context, property, options.data),
  23610. pathRoot = normalized.root,
  23611. path = normalized.path,
  23612. value = (path === 'this') ? pathRoot : handlebarsGet(pathRoot, path, options);
  23613. Ember.Logger.log(value);
  23614. });
  23615. /**
  23616. Execute the `debugger` statement in the current context.
  23617. ```handlebars
  23618. {{debugger}}
  23619. ```
  23620. Before invoking the `debugger` statement, there
  23621. are a few helpful variables defined in the
  23622. body of this helper that you can inspect while
  23623. debugging that describe how and where this
  23624. helper was invoked:
  23625. - templateContext: this is most likely a controller
  23626. from which this template looks up / displays properties
  23627. - typeOfTemplateContext: a string description of
  23628. what the templateContext is
  23629. For example, if you're wondering why a value `{{foo}}`
  23630. isn't rendering as expected within a template, you
  23631. could place a `{{debugger}}` statement, and when
  23632. the `debugger;` breakpoint is hit, you can inspect
  23633. `templateContext`, determine if it's the object you
  23634. expect, and/or evaluate expressions in the console
  23635. to perform property lookups on the `templateContext`:
  23636. ```
  23637. > templateContext.get('foo') // -> "<value of {{foo}}>"
  23638. ```
  23639. @method debugger
  23640. @for Ember.Handlebars.helpers
  23641. @param {String} property
  23642. */
  23643. Ember.Handlebars.registerHelper('debugger', function debuggerHelper(options) {
  23644. // These are helpful values you can inspect while debugging.
  23645. var templateContext = this;
  23646. var typeOfTemplateContext = Ember.inspect(templateContext);
  23647. debugger;
  23648. });
  23649. })();
  23650. (function() {
  23651. /**
  23652. @module ember
  23653. @submodule ember-handlebars
  23654. */
  23655. var get = Ember.get, set = Ember.set;
  23656. var fmt = Ember.String.fmt;
  23657. Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
  23658. init: function() {
  23659. var itemController = get(this, 'itemController');
  23660. var binding;
  23661. if (itemController) {
  23662. var controller = get(this, 'controller.container').lookupFactory('controller:array').create({
  23663. _isVirtual: true,
  23664. parentController: get(this, 'controller'),
  23665. itemController: itemController,
  23666. target: get(this, 'controller'),
  23667. _eachView: this
  23668. });
  23669. this.disableContentObservers(function() {
  23670. set(this, 'content', controller);
  23671. binding = new Ember.Binding('content', '_eachView.dataSource').oneWay();
  23672. binding.connect(controller);
  23673. });
  23674. set(this, '_arrayController', controller);
  23675. } else {
  23676. this.disableContentObservers(function() {
  23677. binding = new Ember.Binding('content', 'dataSource').oneWay();
  23678. binding.connect(this);
  23679. });
  23680. }
  23681. return this._super();
  23682. },
  23683. _assertArrayLike: function(content) {
  23684. Ember.assert(fmt("The value that #each loops over must be an Array. You " +
  23685. "passed %@, but it should have been an ArrayController",
  23686. [content.constructor]),
  23687. !Ember.ControllerMixin.detect(content) ||
  23688. (content && content.isGenerated) ||
  23689. content instanceof Ember.ArrayController);
  23690. Ember.assert(fmt("The value that #each loops over must be an Array. You passed %@", [(Ember.ControllerMixin.detect(content) && content.get('model') !== undefined) ? fmt("'%@' (wrapped in %@)", [content.get('model'), content]) : content]), Ember.Array.detect(content));
  23691. },
  23692. disableContentObservers: function(callback) {
  23693. Ember.removeBeforeObserver(this, 'content', null, '_contentWillChange');
  23694. Ember.removeObserver(this, 'content', null, '_contentDidChange');
  23695. callback.call(this);
  23696. Ember.addBeforeObserver(this, 'content', null, '_contentWillChange');
  23697. Ember.addObserver(this, 'content', null, '_contentDidChange');
  23698. },
  23699. itemViewClass: Ember._MetamorphView,
  23700. emptyViewClass: Ember._MetamorphView,
  23701. createChildView: function(view, attrs) {
  23702. view = this._super(view, attrs);
  23703. // At the moment, if a container view subclass wants
  23704. // to insert keywords, it is responsible for cloning
  23705. // the keywords hash. This will be fixed momentarily.
  23706. var keyword = get(this, 'keyword');
  23707. var content = get(view, 'content');
  23708. if (keyword) {
  23709. var data = get(view, 'templateData');
  23710. data = Ember.copy(data);
  23711. data.keywords = view.cloneKeywords();
  23712. set(view, 'templateData', data);
  23713. // In this case, we do not bind, because the `content` of
  23714. // a #each item cannot change.
  23715. data.keywords[keyword] = content;
  23716. }
  23717. // If {{#each}} is looping over an array of controllers,
  23718. // point each child view at their respective controller.
  23719. if (content && get(content, 'isController')) {
  23720. set(view, 'controller', content);
  23721. }
  23722. return view;
  23723. },
  23724. destroy: function() {
  23725. if (!this._super()) { return; }
  23726. var arrayController = get(this, '_arrayController');
  23727. if (arrayController) {
  23728. arrayController.destroy();
  23729. }
  23730. return this;
  23731. }
  23732. });
  23733. var GroupedEach = Ember.Handlebars.GroupedEach = function(context, path, options) {
  23734. var self = this,
  23735. normalized = Ember.Handlebars.normalizePath(context, path, options.data);
  23736. this.context = context;
  23737. this.path = path;
  23738. this.options = options;
  23739. this.template = options.fn;
  23740. this.containingView = options.data.view;
  23741. this.normalizedRoot = normalized.root;
  23742. this.normalizedPath = normalized.path;
  23743. this.content = this.lookupContent();
  23744. this.addContentObservers();
  23745. this.addArrayObservers();
  23746. this.containingView.on('willClearRender', function() {
  23747. self.destroy();
  23748. });
  23749. };
  23750. GroupedEach.prototype = {
  23751. contentWillChange: function() {
  23752. this.removeArrayObservers();
  23753. },
  23754. contentDidChange: function() {
  23755. this.content = this.lookupContent();
  23756. this.addArrayObservers();
  23757. this.rerenderContainingView();
  23758. },
  23759. contentArrayWillChange: Ember.K,
  23760. contentArrayDidChange: function() {
  23761. this.rerenderContainingView();
  23762. },
  23763. lookupContent: function() {
  23764. return Ember.Handlebars.get(this.normalizedRoot, this.normalizedPath, this.options);
  23765. },
  23766. addArrayObservers: function() {
  23767. if (!this.content) { return; }
  23768. this.content.addArrayObserver(this, {
  23769. willChange: 'contentArrayWillChange',
  23770. didChange: 'contentArrayDidChange'
  23771. });
  23772. },
  23773. removeArrayObservers: function() {
  23774. if (!this.content) { return; }
  23775. this.content.removeArrayObserver(this, {
  23776. willChange: 'contentArrayWillChange',
  23777. didChange: 'contentArrayDidChange'
  23778. });
  23779. },
  23780. addContentObservers: function() {
  23781. Ember.addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange);
  23782. Ember.addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange);
  23783. },
  23784. removeContentObservers: function() {
  23785. Ember.removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange);
  23786. Ember.removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange);
  23787. },
  23788. render: function() {
  23789. if (!this.content) { return; }
  23790. var content = this.content,
  23791. contentLength = get(content, 'length'),
  23792. data = this.options.data,
  23793. template = this.template;
  23794. data.insideEach = true;
  23795. for (var i = 0; i < contentLength; i++) {
  23796. template(content.objectAt(i), { data: data });
  23797. }
  23798. },
  23799. rerenderContainingView: function() {
  23800. var self = this;
  23801. Ember.run.scheduleOnce('render', this, function() {
  23802. // It's possible it's been destroyed after we enqueued a re-render call.
  23803. if (!self.destroyed) {
  23804. self.containingView.rerender();
  23805. }
  23806. });
  23807. },
  23808. destroy: function() {
  23809. this.removeContentObservers();
  23810. if (this.content) {
  23811. this.removeArrayObservers();
  23812. }
  23813. this.destroyed = true;
  23814. }
  23815. };
  23816. /**
  23817. The `{{#each}}` helper loops over elements in a collection, rendering its
  23818. block once for each item. It is an extension of the base Handlebars `{{#each}}`
  23819. helper:
  23820. ```javascript
  23821. Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}];
  23822. ```
  23823. ```handlebars
  23824. {{#each Developers}}
  23825. {{name}}
  23826. {{/each}}
  23827. ```
  23828. `{{each}}` supports an alternative syntax with element naming:
  23829. ```handlebars
  23830. {{#each person in Developers}}
  23831. {{person.name}}
  23832. {{/each}}
  23833. ```
  23834. When looping over objects that do not have properties, `{{this}}` can be used
  23835. to render the object:
  23836. ```javascript
  23837. DeveloperNames = ['Yehuda', 'Tom', 'Paul']
  23838. ```
  23839. ```handlebars
  23840. {{#each DeveloperNames}}
  23841. {{this}}
  23842. {{/each}}
  23843. ```
  23844. ### {{else}} condition
  23845. `{{#each}}` can have a matching `{{else}}`. The contents of this block will render
  23846. if the collection is empty.
  23847. ```
  23848. {{#each person in Developers}}
  23849. {{person.name}}
  23850. {{else}}
  23851. <p>Sorry, nobody is available for this task.</p>
  23852. {{/each}}
  23853. ```
  23854. ### Specifying a View class for items
  23855. If you provide an `itemViewClass` option that references a view class
  23856. with its own `template` you can omit the block.
  23857. The following template:
  23858. ```handlebars
  23859. {{#view App.MyView }}
  23860. {{each view.items itemViewClass="App.AnItemView"}}
  23861. {{/view}}
  23862. ```
  23863. And application code
  23864. ```javascript
  23865. App = Ember.Application.create({
  23866. MyView: Ember.View.extend({
  23867. items: [
  23868. Ember.Object.create({name: 'Dave'}),
  23869. Ember.Object.create({name: 'Mary'}),
  23870. Ember.Object.create({name: 'Sara'})
  23871. ]
  23872. })
  23873. });
  23874. App.AnItemView = Ember.View.extend({
  23875. template: Ember.Handlebars.compile("Greetings {{name}}")
  23876. });
  23877. ```
  23878. Will result in the HTML structure below
  23879. ```html
  23880. <div class="ember-view">
  23881. <div class="ember-view">Greetings Dave</div>
  23882. <div class="ember-view">Greetings Mary</div>
  23883. <div class="ember-view">Greetings Sara</div>
  23884. </div>
  23885. ```
  23886. If an `itemViewClass` is defined on the helper, and therefore the helper is not
  23887. being used as a block, an `emptyViewClass` can also be provided optionally.
  23888. The `emptyViewClass` will match the behavior of the `{{else}}` condition
  23889. described above. That is, the `emptyViewClass` will render if the collection
  23890. is empty.
  23891. ### Representing each item with a Controller.
  23892. By default the controller lookup within an `{{#each}}` block will be
  23893. the controller of the template where the `{{#each}}` was used. If each
  23894. item needs to be presented by a custom controller you can provide a
  23895. `itemController` option which references a controller by lookup name.
  23896. Each item in the loop will be wrapped in an instance of this controller
  23897. and the item itself will be set to the `content` property of that controller.
  23898. This is useful in cases where properties of model objects need transformation
  23899. or synthesis for display:
  23900. ```javascript
  23901. App.DeveloperController = Ember.ObjectController.extend({
  23902. isAvailableForHire: function() {
  23903. return !this.get('content.isEmployed') && this.get('content.isSeekingWork');
  23904. }.property('isEmployed', 'isSeekingWork')
  23905. })
  23906. ```
  23907. ```handlebars
  23908. {{#each person in developers itemController="developer"}}
  23909. {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}}
  23910. {{/each}}
  23911. ```
  23912. Each itemController will receive a reference to the current controller as
  23913. a `parentController` property.
  23914. ### (Experimental) Grouped Each
  23915. When used in conjunction with the experimental [group helper](https://github.com/emberjs/group-helper),
  23916. you can inform Handlebars to re-render an entire group of items instead of
  23917. re-rendering them one at a time (in the event that they are changed en masse
  23918. or an item is added/removed).
  23919. ```handlebars
  23920. {{#group}}
  23921. {{#each people}}
  23922. {{firstName}} {{lastName}}
  23923. {{/each}}
  23924. {{/group}}
  23925. ```
  23926. This can be faster than the normal way that Handlebars re-renders items
  23927. in some cases.
  23928. If for some reason you have a group with more than one `#each`, you can make
  23929. one of the collections be updated in normal (non-grouped) fashion by setting
  23930. the option `groupedRows=true` (counter-intuitive, I know).
  23931. For example,
  23932. ```handlebars
  23933. {{dealershipName}}
  23934. {{#group}}
  23935. {{#each dealers}}
  23936. {{firstName}} {{lastName}}
  23937. {{/each}}
  23938. {{#each car in cars groupedRows=true}}
  23939. {{car.make}} {{car.model}} {{car.color}}
  23940. {{/each}}
  23941. {{/group}}
  23942. ```
  23943. Any change to `dealershipName` or the `dealers` collection will cause the
  23944. entire group to be re-rendered. However, changes to the `cars` collection
  23945. will be re-rendered individually (as normal).
  23946. Note that `group` behavior is also disabled by specifying an `itemViewClass`.
  23947. @method each
  23948. @for Ember.Handlebars.helpers
  23949. @param [name] {String} name for item (used with `in`)
  23950. @param [path] {String} path
  23951. @param [options] {Object} Handlebars key/value pairs of options
  23952. @param [options.itemViewClass] {String} a path to a view class used for each item
  23953. @param [options.itemController] {String} name of a controller to be created for each item
  23954. @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper
  23955. */
  23956. Ember.Handlebars.registerHelper('each', function eachHelper(path, options) {
  23957. if (arguments.length === 4) {
  23958. 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");
  23959. var keywordName = arguments[0];
  23960. options = arguments[3];
  23961. path = arguments[2];
  23962. if (path === '') { path = "this"; }
  23963. options.hash.keyword = keywordName;
  23964. }
  23965. if (arguments.length === 1) {
  23966. options = path;
  23967. path = 'this';
  23968. }
  23969. options.hash.dataSourceBinding = path;
  23970. // Set up emptyView as a metamorph with no tag
  23971. //options.hash.emptyViewClass = Ember._MetamorphView;
  23972. if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) {
  23973. new Ember.Handlebars.GroupedEach(this, path, options).render();
  23974. } else {
  23975. return Ember.Handlebars.helpers.collection.call(this, 'Ember.Handlebars.EachView', options);
  23976. }
  23977. });
  23978. })();
  23979. (function() {
  23980. /**
  23981. @module ember
  23982. @submodule ember-handlebars
  23983. */
  23984. /**
  23985. `template` allows you to render a template from inside another template.
  23986. This allows you to re-use the same template in multiple places. For example:
  23987. ```html
  23988. <script type="text/x-handlebars" data-template-name="logged_in_user">
  23989. {{#with loggedInUser}}
  23990. Last Login: {{lastLogin}}
  23991. User Info: {{template "user_info"}}
  23992. {{/with}}
  23993. </script>
  23994. ```
  23995. ```html
  23996. <script type="text/x-handlebars" data-template-name="user_info">
  23997. Name: <em>{{name}}</em>
  23998. Karma: <em>{{karma}}</em>
  23999. </script>
  24000. ```
  24001. ```handlebars
  24002. {{#if isUser}}
  24003. {{template "user_info"}}
  24004. {{else}}
  24005. {{template "unlogged_user_info"}}
  24006. {{/if}}
  24007. ```
  24008. This helper looks for templates in the global `Ember.TEMPLATES` hash. If you
  24009. add `<script>` tags to your page with the `data-template-name` attribute set,
  24010. they will be compiled and placed in this hash automatically.
  24011. You can also manually register templates by adding them to the hash:
  24012. ```javascript
  24013. Ember.TEMPLATES["my_cool_template"] = Ember.Handlebars.compile('<b>{{user}}</b>');
  24014. ```
  24015. @deprecated
  24016. @method template
  24017. @for Ember.Handlebars.helpers
  24018. @param {String} templateName the template to render
  24019. */
  24020. Ember.Handlebars.registerHelper('template', function(name, options) {
  24021. Ember.deprecate("The `template` helper has been deprecated in favor of the `partial` helper. Please use `partial` instead, which will work the same way.");
  24022. return Ember.Handlebars.helpers.partial.apply(this, arguments);
  24023. });
  24024. })();
  24025. (function() {
  24026. /**
  24027. @module ember
  24028. @submodule ember-handlebars
  24029. */
  24030. /**
  24031. The `partial` helper renders another template without
  24032. changing the template context:
  24033. ```handlebars
  24034. {{foo}}
  24035. {{partial "nav"}}
  24036. ```
  24037. The above example template will render a template named
  24038. "_nav", which has the same context as the parent template
  24039. it's rendered into, so if the "_nav" template also referenced
  24040. `{{foo}}`, it would print the same thing as the `{{foo}}`
  24041. in the above example.
  24042. If a "_nav" template isn't found, the `partial` helper will
  24043. fall back to a template named "nav".
  24044. ## Bound template names
  24045. The parameter supplied to `partial` can also be a path
  24046. to a property containing a template name, e.g.:
  24047. ```handlebars
  24048. {{partial someTemplateName}}
  24049. ```
  24050. The above example will look up the value of `someTemplateName`
  24051. on the template context (e.g. a controller) and use that
  24052. value as the name of the template to render. If the resolved
  24053. value is falsy, nothing will be rendered. If `someTemplateName`
  24054. changes, the partial will be re-rendered using the new template
  24055. name.
  24056. ## Setting the partial's context with `with`
  24057. The `partial` helper can be used in conjunction with the `with`
  24058. helper to set a context that will be used by the partial:
  24059. ```handlebars
  24060. {{#with currentUser}}
  24061. {{partial "user_info"}}
  24062. {{/with}}
  24063. ```
  24064. @method partial
  24065. @for Ember.Handlebars.helpers
  24066. @param {String} partialName the name of the template to render minus the leading underscore
  24067. */
  24068. Ember.Handlebars.registerHelper('partial', function partialHelper(name, options) {
  24069. var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this;
  24070. if (options.types[0] === "ID") {
  24071. // Helper was passed a property path; we need to
  24072. // create a binding that will re-render whenever
  24073. // this property changes.
  24074. options.fn = function(context, fnOptions) {
  24075. var partialName = Ember.Handlebars.get(context, name, fnOptions);
  24076. renderPartial(context, partialName, fnOptions);
  24077. };
  24078. return Ember.Handlebars.bind.call(context, name, options, true, exists);
  24079. } else {
  24080. // Render the partial right into parent template.
  24081. renderPartial(context, name, options);
  24082. }
  24083. });
  24084. function exists(value) {
  24085. return !Ember.isNone(value);
  24086. }
  24087. function renderPartial(context, name, options) {
  24088. var nameParts = name.split("/"),
  24089. lastPart = nameParts[nameParts.length - 1];
  24090. nameParts[nameParts.length - 1] = "_" + lastPart;
  24091. var view = options.data.view,
  24092. underscoredName = nameParts.join("/"),
  24093. template = view.templateForName(underscoredName),
  24094. deprecatedTemplate = !template && view.templateForName(name);
  24095. Ember.assert("Unable to find partial with name '"+name+"'.", template || deprecatedTemplate);
  24096. template = template || deprecatedTemplate;
  24097. template(context, { data: options.data });
  24098. }
  24099. })();
  24100. (function() {
  24101. /**
  24102. @module ember
  24103. @submodule ember-handlebars
  24104. */
  24105. var get = Ember.get, set = Ember.set;
  24106. /**
  24107. `{{yield}}` denotes an area of a template that will be rendered inside
  24108. of another template. It has two main uses:
  24109. ### Use with `layout`
  24110. When used in a Handlebars template that is assigned to an `Ember.View`
  24111. instance's `layout` property Ember will render the layout template first,
  24112. inserting the view's own rendered output at the `{{yield}}` location.
  24113. An empty `<body>` and the following application code:
  24114. ```javascript
  24115. AView = Ember.View.extend({
  24116. classNames: ['a-view-with-layout'],
  24117. layout: Ember.Handlebars.compile('<div class="wrapper">{{yield}}</div>'),
  24118. template: Ember.Handlebars.compile('<span>I am wrapped</span>')
  24119. });
  24120. aView = AView.create();
  24121. aView.appendTo('body');
  24122. ```
  24123. Will result in the following HTML output:
  24124. ```html
  24125. <body>
  24126. <div class='ember-view a-view-with-layout'>
  24127. <div class="wrapper">
  24128. <span>I am wrapped</span>
  24129. </div>
  24130. </div>
  24131. </body>
  24132. ```
  24133. The `yield` helper cannot be used outside of a template assigned to an
  24134. `Ember.View`'s `layout` property and will throw an error if attempted.
  24135. ```javascript
  24136. BView = Ember.View.extend({
  24137. classNames: ['a-view-with-layout'],
  24138. template: Ember.Handlebars.compile('{{yield}}')
  24139. });
  24140. bView = BView.create();
  24141. bView.appendTo('body');
  24142. // throws
  24143. // Uncaught Error: assertion failed:
  24144. // You called yield in a template that was not a layout
  24145. ```
  24146. ### Use with Ember.Component
  24147. When designing components `{{yield}}` is used to denote where, inside the component's
  24148. template, an optional block passed to the component should render:
  24149. ```handlebars
  24150. <!-- application.hbs -->
  24151. {{#labeled-textfield value=someProperty}}
  24152. First name:
  24153. {{/labeled-textfield}}
  24154. ```
  24155. ```handlebars
  24156. <!-- components/labeled-textfield.hbs -->
  24157. <label>
  24158. {{yield}} {{input value=value}}
  24159. </label>
  24160. ```
  24161. Result:
  24162. ```html
  24163. <label>
  24164. First name: <input type="text" />
  24165. <label>
  24166. ```
  24167. @method yield
  24168. @for Ember.Handlebars.helpers
  24169. @param {Hash} options
  24170. @return {String} HTML string
  24171. */
  24172. Ember.Handlebars.registerHelper('yield', function yieldHelper(options) {
  24173. var view = options.data.view;
  24174. while (view && !get(view, 'layout')) {
  24175. if (view._contextView) {
  24176. view = view._contextView;
  24177. } else {
  24178. view = get(view, 'parentView');
  24179. }
  24180. }
  24181. Ember.assert("You called yield in a template that was not a layout", !!view);
  24182. view._yield(this, options);
  24183. });
  24184. })();
  24185. (function() {
  24186. /**
  24187. @module ember
  24188. @submodule ember-handlebars
  24189. */
  24190. /**
  24191. `loc` looks up the string in the localized strings hash.
  24192. This is a convenient way to localize text. For example:
  24193. ```html
  24194. <script type="text/x-handlebars" data-template-name="home">
  24195. {{loc "welcome"}}
  24196. </script>
  24197. ```
  24198. Take note that `"welcome"` is a string and not an object
  24199. reference.
  24200. @method loc
  24201. @for Ember.Handlebars.helpers
  24202. @param {String} str The string to format
  24203. */
  24204. Ember.Handlebars.registerHelper('loc', function locHelper(str) {
  24205. return Ember.String.loc(str);
  24206. });
  24207. })();
  24208. (function() {
  24209. })();
  24210. (function() {
  24211. })();
  24212. (function() {
  24213. /**
  24214. @module ember
  24215. @submodule ember-handlebars
  24216. */
  24217. var set = Ember.set, get = Ember.get;
  24218. /**
  24219. The internal class used to create text inputs when the `{{input}}`
  24220. helper is used with `type` of `checkbox`.
  24221. See [handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details.
  24222. ## Direct manipulation of `checked`
  24223. The `checked` attribute of an `Ember.Checkbox` object should always be set
  24224. through the Ember object or by interacting with its rendered element
  24225. representation via the mouse, keyboard, or touch. Updating the value of the
  24226. checkbox via jQuery will result in the checked value of the object and its
  24227. element losing synchronization.
  24228. ## Layout and LayoutName properties
  24229. Because HTML `input` elements are self closing `layout` and `layoutName`
  24230. properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s
  24231. layout section for more information.
  24232. @class Checkbox
  24233. @namespace Ember
  24234. @extends Ember.View
  24235. */
  24236. Ember.Checkbox = Ember.View.extend({
  24237. classNames: ['ember-checkbox'],
  24238. tagName: 'input',
  24239. attributeBindings: ['type', 'checked', 'indeterminate', 'disabled', 'tabindex', 'name'],
  24240. type: "checkbox",
  24241. checked: false,
  24242. disabled: false,
  24243. indeterminate: false,
  24244. init: function() {
  24245. this._super();
  24246. this.on("change", this, this._updateElementValue);
  24247. },
  24248. didInsertElement: function() {
  24249. this._super();
  24250. this.get('element').indeterminate = !!this.get('indeterminate');
  24251. },
  24252. _updateElementValue: function() {
  24253. set(this, 'checked', this.$().prop('checked'));
  24254. }
  24255. });
  24256. })();
  24257. (function() {
  24258. /**
  24259. @module ember
  24260. @submodule ember-handlebars
  24261. */
  24262. var get = Ember.get, set = Ember.set;
  24263. /**
  24264. Shared mixin used by `Ember.TextField` and `Ember.TextArea`.
  24265. @class TextSupport
  24266. @namespace Ember
  24267. @private
  24268. */
  24269. Ember.TextSupport = Ember.Mixin.create({
  24270. value: "",
  24271. attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex', 'readonly'],
  24272. placeholder: null,
  24273. disabled: false,
  24274. maxlength: null,
  24275. init: function() {
  24276. this._super();
  24277. this.on("focusOut", this, this._elementValueDidChange);
  24278. this.on("change", this, this._elementValueDidChange);
  24279. this.on("paste", this, this._elementValueDidChange);
  24280. this.on("cut", this, this._elementValueDidChange);
  24281. this.on("input", this, this._elementValueDidChange);
  24282. this.on("keyUp", this, this.interpretKeyEvents);
  24283. },
  24284. /**
  24285. The action to be sent when the user presses the return key.
  24286. This is similar to the `{{action}}` helper, but is fired when
  24287. the user presses the return key when editing a text field, and sends
  24288. the value of the field as the context.
  24289. @property action
  24290. @type String
  24291. @default null
  24292. */
  24293. action: null,
  24294. /**
  24295. The event that should send the action.
  24296. Options are:
  24297. * `enter`: the user pressed enter
  24298. * `keyPress`: the user pressed a key
  24299. @property onEvent
  24300. @type String
  24301. @default enter
  24302. */
  24303. onEvent: 'enter',
  24304. /**
  24305. Whether they `keyUp` event that triggers an `action` to be sent continues
  24306. propagating to other views.
  24307. By default, when the user presses the return key on their keyboard and
  24308. the text field has an `action` set, the action will be sent to the view's
  24309. controller and the key event will stop propagating.
  24310. If you would like parent views to receive the `keyUp` event even after an
  24311. action has been dispatched, set `bubbles` to true.
  24312. @property bubbles
  24313. @type Boolean
  24314. @default false
  24315. */
  24316. bubbles: false,
  24317. interpretKeyEvents: function(event) {
  24318. var map = Ember.TextSupport.KEY_EVENTS;
  24319. var method = map[event.keyCode];
  24320. this._elementValueDidChange();
  24321. if (method) { return this[method](event); }
  24322. },
  24323. _elementValueDidChange: function() {
  24324. set(this, 'value', this.$().val());
  24325. },
  24326. /**
  24327. The action to be sent when the user inserts a new line.
  24328. Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13.
  24329. Uses sendAction to send the `enter` action to the controller.
  24330. @method insertNewline
  24331. @param {Event} event
  24332. */
  24333. insertNewline: function(event) {
  24334. sendAction('enter', this, event);
  24335. sendAction('insert-newline', this, event);
  24336. },
  24337. /**
  24338. Called when the user hits escape.
  24339. Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27.
  24340. Uses sendAction to send the `escape-press` action to the controller.
  24341. @method cancel
  24342. @param {Event} event
  24343. */
  24344. cancel: function(event) {
  24345. sendAction('escape-press', this, event);
  24346. },
  24347. /**
  24348. Called when the text area is focused.
  24349. @method focusIn
  24350. @param {Event} event
  24351. */
  24352. focusIn: function(event) {
  24353. sendAction('focus-in', this, event);
  24354. },
  24355. /**
  24356. Called when the text area is blurred.
  24357. @method focusOut
  24358. @param {Event} event
  24359. */
  24360. focusOut: function(event) {
  24361. sendAction('focus-out', this, event);
  24362. },
  24363. /**
  24364. The action to be sent when the user presses a key. Enabled by setting
  24365. the `onEvent` property to `keyPress`.
  24366. Uses sendAction to send the `keyPress` action to the controller.
  24367. @method keyPress
  24368. @param {Event} event
  24369. */
  24370. keyPress: function(event) {
  24371. sendAction('key-press', this, event);
  24372. }
  24373. });
  24374. Ember.TextSupport.KEY_EVENTS = {
  24375. 13: 'insertNewline',
  24376. 27: 'cancel'
  24377. };
  24378. // In principle, this shouldn't be necessary, but the legacy
  24379. // sectionAction semantics for TextField are different from
  24380. // the component semantics so this method normalizes them.
  24381. function sendAction(eventName, view, event) {
  24382. var action = get(view, eventName),
  24383. on = get(view, 'onEvent'),
  24384. value = get(view, 'value');
  24385. // back-compat support for keyPress as an event name even though
  24386. // it's also a method name that consumes the event (and therefore
  24387. // incompatible with sendAction semantics).
  24388. if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) {
  24389. view.sendAction('action', value);
  24390. }
  24391. view.sendAction(eventName, value);
  24392. if (action || on === eventName) {
  24393. if(!get(view, 'bubbles')) {
  24394. event.stopPropagation();
  24395. }
  24396. }
  24397. }
  24398. })();
  24399. (function() {
  24400. /**
  24401. @module ember
  24402. @submodule ember-handlebars
  24403. */
  24404. var get = Ember.get, set = Ember.set;
  24405. /**
  24406. The internal class used to create text inputs when the `{{input}}`
  24407. helper is used with `type` of `text`.
  24408. See [Handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details.
  24409. ## Layout and LayoutName properties
  24410. Because HTML `input` elements are self closing `layout` and `layoutName`
  24411. properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s
  24412. layout section for more information.
  24413. @class TextField
  24414. @namespace Ember
  24415. @extends Ember.Component
  24416. @uses Ember.TextSupport
  24417. */
  24418. Ember.TextField = Ember.Component.extend(Ember.TextSupport, {
  24419. classNames: ['ember-text-field'],
  24420. tagName: "input",
  24421. attributeBindings: ['type', 'value', 'size', 'pattern', 'name', 'min', 'max'],
  24422. /**
  24423. The `value` attribute of the input element. As the user inputs text, this
  24424. property is updated live.
  24425. @property value
  24426. @type String
  24427. @default ""
  24428. */
  24429. value: "",
  24430. /**
  24431. The `type` attribute of the input element.
  24432. @property type
  24433. @type String
  24434. @default "text"
  24435. */
  24436. type: "text",
  24437. /**
  24438. The `size` of the text field in characters.
  24439. @property size
  24440. @type String
  24441. @default null
  24442. */
  24443. size: null,
  24444. /**
  24445. The `pattern` attribute of input element.
  24446. @property pattern
  24447. @type String
  24448. @default null
  24449. */
  24450. pattern: null,
  24451. /**
  24452. The `min` attribute of input element used with `type="number"` or `type="range"`.
  24453. @property min
  24454. @type String
  24455. @default null
  24456. */
  24457. min: null,
  24458. /**
  24459. The `max` attribute of input element used with `type="number"` or `type="range"`.
  24460. @property max
  24461. @type String
  24462. @default null
  24463. */
  24464. max: null
  24465. });
  24466. })();
  24467. (function() {
  24468. /**
  24469. @module ember
  24470. @submodule ember-handlebars
  24471. */
  24472. var get = Ember.get, set = Ember.set;
  24473. /**
  24474. The internal class used to create textarea element when the `{{textarea}}`
  24475. helper is used.
  24476. See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details.
  24477. ## Layout and LayoutName properties
  24478. Because HTML `textarea` elements do not contain inner HTML the `layout` and
  24479. `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s
  24480. layout section for more information.
  24481. @class TextArea
  24482. @namespace Ember
  24483. @extends Ember.Component
  24484. @uses Ember.TextSupport
  24485. */
  24486. Ember.TextArea = Ember.Component.extend(Ember.TextSupport, {
  24487. classNames: ['ember-text-area'],
  24488. tagName: "textarea",
  24489. attributeBindings: ['rows', 'cols', 'name'],
  24490. rows: null,
  24491. cols: null,
  24492. _updateElementValue: Ember.observer('value', function() {
  24493. // We do this check so cursor position doesn't get affected in IE
  24494. var value = get(this, 'value'),
  24495. $el = this.$();
  24496. if ($el && value !== $el.val()) {
  24497. $el.val(value);
  24498. }
  24499. }),
  24500. init: function() {
  24501. this._super();
  24502. this.on("didInsertElement", this, this._updateElementValue);
  24503. }
  24504. });
  24505. })();
  24506. (function() {
  24507. /*jshint eqeqeq:false */
  24508. /**
  24509. @module ember
  24510. @submodule ember-handlebars
  24511. */
  24512. var set = Ember.set,
  24513. get = Ember.get,
  24514. indexOf = Ember.EnumerableUtils.indexOf,
  24515. indexesOf = Ember.EnumerableUtils.indexesOf,
  24516. forEach = Ember.EnumerableUtils.forEach,
  24517. replace = Ember.EnumerableUtils.replace,
  24518. isArray = Ember.isArray,
  24519. precompileTemplate = Ember.Handlebars.compile;
  24520. Ember.SelectOption = Ember.View.extend({
  24521. tagName: 'option',
  24522. attributeBindings: ['value', 'selected'],
  24523. defaultTemplate: function(context, options) {
  24524. options = { data: options.data, hash: {} };
  24525. Ember.Handlebars.helpers.bind.call(context, "view.label", options);
  24526. },
  24527. init: function() {
  24528. this.labelPathDidChange();
  24529. this.valuePathDidChange();
  24530. this._super();
  24531. },
  24532. selected: Ember.computed(function() {
  24533. var content = get(this, 'content'),
  24534. selection = get(this, 'parentView.selection');
  24535. if (get(this, 'parentView.multiple')) {
  24536. return selection && indexOf(selection, content.valueOf()) > -1;
  24537. } else {
  24538. // Primitives get passed through bindings as objects... since
  24539. // `new Number(4) !== 4`, we use `==` below
  24540. return content == selection;
  24541. }
  24542. }).property('content', 'parentView.selection'),
  24543. labelPathDidChange: Ember.observer('parentView.optionLabelPath', function() {
  24544. var labelPath = get(this, 'parentView.optionLabelPath');
  24545. if (!labelPath) { return; }
  24546. Ember.defineProperty(this, 'label', Ember.computed(function() {
  24547. return get(this, labelPath);
  24548. }).property(labelPath));
  24549. }),
  24550. valuePathDidChange: Ember.observer('parentView.optionValuePath', function() {
  24551. var valuePath = get(this, 'parentView.optionValuePath');
  24552. if (!valuePath) { return; }
  24553. Ember.defineProperty(this, 'value', Ember.computed(function() {
  24554. return get(this, valuePath);
  24555. }).property(valuePath));
  24556. })
  24557. });
  24558. Ember.SelectOptgroup = Ember.CollectionView.extend({
  24559. tagName: 'optgroup',
  24560. attributeBindings: ['label'],
  24561. selectionBinding: 'parentView.selection',
  24562. multipleBinding: 'parentView.multiple',
  24563. optionLabelPathBinding: 'parentView.optionLabelPath',
  24564. optionValuePathBinding: 'parentView.optionValuePath',
  24565. itemViewClassBinding: 'parentView.optionView'
  24566. });
  24567. /**
  24568. The `Ember.Select` view class renders a
  24569. [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element,
  24570. allowing the user to choose from a list of options.
  24571. The text and `value` property of each `<option>` element within the
  24572. `<select>` element are populated from the objects in the `Element.Select`'s
  24573. `content` property. The underlying data object of the selected `<option>` is
  24574. stored in the `Element.Select`'s `value` property.
  24575. ## The Content Property (array of strings)
  24576. The simplest version of an `Ember.Select` takes an array of strings as its
  24577. `content` property. The string will be used as both the `value` property and
  24578. the inner text of each `<option>` element inside the rendered `<select>`.
  24579. Example:
  24580. ```javascript
  24581. App.ApplicationController = Ember.Controller.extend({
  24582. names: ["Yehuda", "Tom"]
  24583. });
  24584. ```
  24585. ```handlebars
  24586. {{view Ember.Select content=names}}
  24587. ```
  24588. Would result in the following HTML:
  24589. ```html
  24590. <select class="ember-select">
  24591. <option value="Yehuda">Yehuda</option>
  24592. <option value="Tom">Tom</option>
  24593. </select>
  24594. ```
  24595. You can control which `<option>` is selected through the `Ember.Select`'s
  24596. `value` property:
  24597. ```javascript
  24598. App.ApplicationController = Ember.Controller.extend({
  24599. selectedName: 'Tom',
  24600. names: ["Yehuda", "Tom"]
  24601. });
  24602. ```
  24603. ```handlebars
  24604. {{view Ember.Select
  24605. content=names
  24606. value=selectedName
  24607. }}
  24608. ```
  24609. Would result in the following HTML with the `<option>` for 'Tom' selected:
  24610. ```html
  24611. <select class="ember-select">
  24612. <option value="Yehuda">Yehuda</option>
  24613. <option value="Tom" selected="selected">Tom</option>
  24614. </select>
  24615. ```
  24616. A user interacting with the rendered `<select>` to choose "Yehuda" would
  24617. update the value of `selectedName` to "Yehuda".
  24618. ## The Content Property (array of Objects)
  24619. An `Ember.Select` can also take an array of JavaScript or Ember objects as
  24620. its `content` property.
  24621. When using objects you need to tell the `Ember.Select` which property should
  24622. be accessed on each object to supply the `value` attribute of the `<option>`
  24623. and which property should be used to supply the element text.
  24624. The `optionValuePath` option is used to specify the path on each object to
  24625. the desired property for the `value` attribute. The `optionLabelPath`
  24626. specifies the path on each object to the desired property for the
  24627. element's text. Both paths must reference each object itself as `content`:
  24628. ```javascript
  24629. App.ApplicationController = Ember.Controller.extend({
  24630. programmers: [
  24631. {firstName: "Yehuda", id: 1},
  24632. {firstName: "Tom", id: 2}
  24633. ]
  24634. });
  24635. ```
  24636. ```handlebars
  24637. {{view Ember.Select
  24638. content=programmers
  24639. optionValuePath="content.id"
  24640. optionLabelPath="content.firstName"}}
  24641. ```
  24642. Would result in the following HTML:
  24643. ```html
  24644. <select class="ember-select">
  24645. <option value="1">Yehuda</option>
  24646. <option value="2">Tom</option>
  24647. </select>
  24648. ```
  24649. The `value` attribute of the selected `<option>` within an `Ember.Select`
  24650. can be bound to a property on another object:
  24651. ```javascript
  24652. App.ApplicationController = Ember.Controller.extend({
  24653. programmers: [
  24654. {firstName: "Yehuda", id: 1},
  24655. {firstName: "Tom", id: 2}
  24656. ],
  24657. currentProgrammer: {
  24658. id: 2
  24659. }
  24660. });
  24661. ```
  24662. ```handlebars
  24663. {{view Ember.Select
  24664. content=programmers
  24665. optionValuePath="content.id"
  24666. optionLabelPath="content.firstName"
  24667. value=currentProgrammer.id}}
  24668. ```
  24669. Would result in the following HTML with a selected option:
  24670. ```html
  24671. <select class="ember-select">
  24672. <option value="1">Yehuda</option>
  24673. <option value="2" selected="selected">Tom</option>
  24674. </select>
  24675. ```
  24676. Interacting with the rendered element by selecting the first option
  24677. ('Yehuda') will update the `id` of `currentProgrammer`
  24678. to match the `value` property of the newly selected `<option>`.
  24679. Alternatively, you can control selection through the underlying objects
  24680. used to render each object by binding the `selection` option. When the selected
  24681. `<option>` is changed, the property path provided to `selection`
  24682. will be updated to match the content object of the rendered `<option>`
  24683. element:
  24684. ```javascript
  24685. App.ApplicationController = Ember.Controller.extend({
  24686. selectedPerson: null,
  24687. programmers: [
  24688. {firstName: "Yehuda", id: 1},
  24689. {firstName: "Tom", id: 2}
  24690. ]
  24691. });
  24692. ```
  24693. ```handlebars
  24694. {{view Ember.Select
  24695. content=programmers
  24696. optionValuePath="content.id"
  24697. optionLabelPath="content.firstName"
  24698. selection=selectedPerson}}
  24699. ```
  24700. Would result in the following HTML with a selected option:
  24701. ```html
  24702. <select class="ember-select">
  24703. <option value="1">Yehuda</option>
  24704. <option value="2" selected="selected">Tom</option>
  24705. </select>
  24706. ```
  24707. Interacting with the rendered element by selecting the first option
  24708. ('Yehuda') will update the `selectedPerson` to match the object of
  24709. the newly selected `<option>`. In this case it is the first object
  24710. in the `programmers`
  24711. ## Supplying a Prompt
  24712. A `null` value for the `Ember.Select`'s `value` or `selection` property
  24713. results in there being no `<option>` with a `selected` attribute:
  24714. ```javascript
  24715. App.ApplicationController = Ember.Controller.extend({
  24716. selectedProgrammer: null,
  24717. programmers: [
  24718. "Yehuda",
  24719. "Tom"
  24720. ]
  24721. });
  24722. ```
  24723. ``` handlebars
  24724. {{view Ember.Select
  24725. content=programmers
  24726. value=selectedProgrammer
  24727. }}
  24728. ```
  24729. Would result in the following HTML:
  24730. ```html
  24731. <select class="ember-select">
  24732. <option value="Yehuda">Yehuda</option>
  24733. <option value="Tom">Tom</option>
  24734. </select>
  24735. ```
  24736. Although `selectedProgrammer` is `null` and no `<option>`
  24737. has a `selected` attribute the rendered HTML will display the
  24738. first item as though it were selected. You can supply a string
  24739. value for the `Ember.Select` to display when there is no selection
  24740. with the `prompt` option:
  24741. ```javascript
  24742. App.ApplicationController = Ember.Controller.extend({
  24743. selectedProgrammer: null,
  24744. programmers: [
  24745. "Yehuda",
  24746. "Tom"
  24747. ]
  24748. });
  24749. ```
  24750. ```handlebars
  24751. {{view Ember.Select
  24752. content=programmers
  24753. value=selectedProgrammer
  24754. prompt="Please select a name"
  24755. }}
  24756. ```
  24757. Would result in the following HTML:
  24758. ```html
  24759. <select class="ember-select">
  24760. <option>Please select a name</option>
  24761. <option value="Yehuda">Yehuda</option>
  24762. <option value="Tom">Tom</option>
  24763. </select>
  24764. ```
  24765. @class Select
  24766. @namespace Ember
  24767. @extends Ember.View
  24768. */
  24769. Ember.Select = Ember.View.extend({
  24770. tagName: 'select',
  24771. classNames: ['ember-select'],
  24772. defaultTemplate: Ember.Handlebars.template(function anonymous(Handlebars,depth0,helpers,partials,data) {
  24773. this.compilerInfo = [4,'>= 1.0.0'];
  24774. helpers = this.merge(helpers, Ember.Handlebars.helpers); data = data || {};
  24775. var buffer = '', stack1, escapeExpression=this.escapeExpression, self=this;
  24776. function program1(depth0,data) {
  24777. var buffer = '', stack1;
  24778. data.buffer.push("<option value=\"\">");
  24779. stack1 = helpers._triageMustache.call(depth0, "view.prompt", {hash:{},hashTypes:{},hashContexts:{},contexts:[depth0],types:["ID"],data:data});
  24780. if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
  24781. data.buffer.push("</option>");
  24782. return buffer;
  24783. }
  24784. function program3(depth0,data) {
  24785. var stack1;
  24786. stack1 = helpers.each.call(depth0, "view.groupedContent", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(4, program4, data),contexts:[depth0],types:["ID"],data:data});
  24787. if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
  24788. else { data.buffer.push(''); }
  24789. }
  24790. function program4(depth0,data) {
  24791. data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {hash:{
  24792. 'content': ("content"),
  24793. 'label': ("label")
  24794. },hashTypes:{'content': "ID",'label': "ID"},hashContexts:{'content': depth0,'label': depth0},contexts:[depth0],types:["ID"],data:data})));
  24795. }
  24796. function program6(depth0,data) {
  24797. var stack1;
  24798. stack1 = helpers.each.call(depth0, "view.content", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(7, program7, data),contexts:[depth0],types:["ID"],data:data});
  24799. if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
  24800. else { data.buffer.push(''); }
  24801. }
  24802. function program7(depth0,data) {
  24803. data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {hash:{
  24804. 'content': ("")
  24805. },hashTypes:{'content': "ID"},hashContexts:{'content': depth0},contexts:[depth0],types:["ID"],data:data})));
  24806. }
  24807. stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],data:data});
  24808. if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
  24809. stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {hash:{},hashTypes:{},hashContexts:{},inverse:self.program(6, program6, data),fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],data:data});
  24810. if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
  24811. return buffer;
  24812. }),
  24813. attributeBindings: ['multiple', 'disabled', 'tabindex', 'name'],
  24814. /**
  24815. The `multiple` attribute of the select element. Indicates whether multiple
  24816. options can be selected.
  24817. @property multiple
  24818. @type Boolean
  24819. @default false
  24820. */
  24821. multiple: false,
  24822. /**
  24823. The `disabled` attribute of the select element. Indicates whether
  24824. the element is disabled from interactions.
  24825. @property disabled
  24826. @type Boolean
  24827. @default false
  24828. */
  24829. disabled: false,
  24830. /**
  24831. The list of options.
  24832. If `optionLabelPath` and `optionValuePath` are not overridden, this should
  24833. be a list of strings, which will serve simultaneously as labels and values.
  24834. Otherwise, this should be a list of objects. For instance:
  24835. ```javascript
  24836. Ember.Select.create({
  24837. content: Ember.A([
  24838. { id: 1, firstName: 'Yehuda' },
  24839. { id: 2, firstName: 'Tom' }
  24840. ]),
  24841. optionLabelPath: 'content.firstName',
  24842. optionValuePath: 'content.id'
  24843. });
  24844. ```
  24845. @property content
  24846. @type Array
  24847. @default null
  24848. */
  24849. content: null,
  24850. /**
  24851. When `multiple` is `false`, the element of `content` that is currently
  24852. selected, if any.
  24853. When `multiple` is `true`, an array of such elements.
  24854. @property selection
  24855. @type Object or Array
  24856. @default null
  24857. */
  24858. selection: null,
  24859. /**
  24860. In single selection mode (when `multiple` is `false`), value can be used to
  24861. get the current selection's value or set the selection by it's value.
  24862. It is not currently supported in multiple selection mode.
  24863. @property value
  24864. @type String
  24865. @default null
  24866. */
  24867. value: Ember.computed(function(key, value) {
  24868. if (arguments.length === 2) { return value; }
  24869. var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, '');
  24870. return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection');
  24871. }).property('selection'),
  24872. /**
  24873. If given, a top-most dummy option will be rendered to serve as a user
  24874. prompt.
  24875. @property prompt
  24876. @type String
  24877. @default null
  24878. */
  24879. prompt: null,
  24880. /**
  24881. The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content).
  24882. @property optionLabelPath
  24883. @type String
  24884. @default 'content'
  24885. */
  24886. optionLabelPath: 'content',
  24887. /**
  24888. The path of the option values. See [content](/api/classes/Ember.Select.html#property_content).
  24889. @property optionValuePath
  24890. @type String
  24891. @default 'content'
  24892. */
  24893. optionValuePath: 'content',
  24894. /**
  24895. The path of the option group.
  24896. When this property is used, `content` should be sorted by `optionGroupPath`.
  24897. @property optionGroupPath
  24898. @type String
  24899. @default null
  24900. */
  24901. optionGroupPath: null,
  24902. /**
  24903. The view class for optgroup.
  24904. @property groupView
  24905. @type Ember.View
  24906. @default Ember.SelectOptgroup
  24907. */
  24908. groupView: Ember.SelectOptgroup,
  24909. groupedContent: Ember.computed(function() {
  24910. var groupPath = get(this, 'optionGroupPath');
  24911. var groupedContent = Ember.A();
  24912. var content = get(this, 'content') || [];
  24913. forEach(content, function(item) {
  24914. var label = get(item, groupPath);
  24915. if (get(groupedContent, 'lastObject.label') !== label) {
  24916. groupedContent.pushObject({
  24917. label: label,
  24918. content: Ember.A()
  24919. });
  24920. }
  24921. get(groupedContent, 'lastObject.content').push(item);
  24922. });
  24923. return groupedContent;
  24924. }).property('optionGroupPath', 'content.@each'),
  24925. /**
  24926. The view class for option.
  24927. @property optionView
  24928. @type Ember.View
  24929. @default Ember.SelectOption
  24930. */
  24931. optionView: Ember.SelectOption,
  24932. _change: function() {
  24933. if (get(this, 'multiple')) {
  24934. this._changeMultiple();
  24935. } else {
  24936. this._changeSingle();
  24937. }
  24938. },
  24939. selectionDidChange: Ember.observer('selection.@each', function() {
  24940. var selection = get(this, 'selection');
  24941. if (get(this, 'multiple')) {
  24942. if (!isArray(selection)) {
  24943. set(this, 'selection', Ember.A([selection]));
  24944. return;
  24945. }
  24946. this._selectionDidChangeMultiple();
  24947. } else {
  24948. this._selectionDidChangeSingle();
  24949. }
  24950. }),
  24951. valueDidChange: Ember.observer('value', function() {
  24952. var content = get(this, 'content'),
  24953. value = get(this, 'value'),
  24954. valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''),
  24955. selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')),
  24956. selection;
  24957. if (value !== selectedValue) {
  24958. selection = content ? content.find(function(obj) {
  24959. return value === (valuePath ? get(obj, valuePath) : obj);
  24960. }) : null;
  24961. this.set('selection', selection);
  24962. }
  24963. }),
  24964. _triggerChange: function() {
  24965. var selection = get(this, 'selection');
  24966. var value = get(this, 'value');
  24967. if (!Ember.isNone(selection)) { this.selectionDidChange(); }
  24968. if (!Ember.isNone(value)) { this.valueDidChange(); }
  24969. this._change();
  24970. },
  24971. _changeSingle: function() {
  24972. var selectedIndex = this.$()[0].selectedIndex,
  24973. content = get(this, 'content'),
  24974. prompt = get(this, 'prompt');
  24975. if (!content || !get(content, 'length')) { return; }
  24976. if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; }
  24977. if (prompt) { selectedIndex -= 1; }
  24978. set(this, 'selection', content.objectAt(selectedIndex));
  24979. },
  24980. _changeMultiple: function() {
  24981. var options = this.$('option:selected'),
  24982. prompt = get(this, 'prompt'),
  24983. offset = prompt ? 1 : 0,
  24984. content = get(this, 'content'),
  24985. selection = get(this, 'selection');
  24986. if (!content) { return; }
  24987. if (options) {
  24988. var selectedIndexes = options.map(function() {
  24989. return this.index - offset;
  24990. }).toArray();
  24991. var newSelection = content.objectsAt(selectedIndexes);
  24992. if (isArray(selection)) {
  24993. replace(selection, 0, get(selection, 'length'), newSelection);
  24994. } else {
  24995. set(this, 'selection', newSelection);
  24996. }
  24997. }
  24998. },
  24999. _selectionDidChangeSingle: function() {
  25000. var el = this.get('element');
  25001. if (!el) { return; }
  25002. var content = get(this, 'content'),
  25003. selection = get(this, 'selection'),
  25004. selectionIndex = content ? indexOf(content, selection) : -1,
  25005. prompt = get(this, 'prompt');
  25006. if (prompt) { selectionIndex += 1; }
  25007. if (el) { el.selectedIndex = selectionIndex; }
  25008. },
  25009. _selectionDidChangeMultiple: function() {
  25010. var content = get(this, 'content'),
  25011. selection = get(this, 'selection'),
  25012. selectedIndexes = content ? indexesOf(content, selection) : [-1],
  25013. prompt = get(this, 'prompt'),
  25014. offset = prompt ? 1 : 0,
  25015. options = this.$('option'),
  25016. adjusted;
  25017. if (options) {
  25018. options.each(function() {
  25019. adjusted = this.index > -1 ? this.index - offset : -1;
  25020. this.selected = indexOf(selectedIndexes, adjusted) > -1;
  25021. });
  25022. }
  25023. },
  25024. init: function() {
  25025. this._super();
  25026. this.on("didInsertElement", this, this._triggerChange);
  25027. this.on("change", this, this._change);
  25028. }
  25029. });
  25030. })();
  25031. (function() {
  25032. /**
  25033. @module ember
  25034. @submodule ember-handlebars-compiler
  25035. */
  25036. /**
  25037. The `{{input}}` helper inserts an HTML `<input>` tag into the template,
  25038. with a `type` value of either `text` or `checkbox`. If no `type` is provided,
  25039. `text` will be the default value applied. The attributes of `{{input}}`
  25040. match those of the native HTML tag as closely as possible for these two types.
  25041. ## Use as text field
  25042. An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input.
  25043. The following HTML attributes can be set via the helper:
  25044. * `value`
  25045. * `size`
  25046. * `name`
  25047. * `pattern`
  25048. * `placeholder`
  25049. * `disabled`
  25050. * `maxlength`
  25051. * `tabindex`
  25052. When set to a quoted string, these values will be directly applied to the HTML
  25053. element. When left unquoted, these values will be bound to a property on the
  25054. template's current rendering context (most typically a controller instance).
  25055. ## Unbound:
  25056. ```handlebars
  25057. {{input value="http://www.facebook.com"}}
  25058. ```
  25059. ```html
  25060. <input type="text" value="http://www.facebook.com"/>
  25061. ```
  25062. ## Bound:
  25063. ```javascript
  25064. App.ApplicationController = Ember.Controller.extend({
  25065. firstName: "Stanley",
  25066. entryNotAllowed: true
  25067. });
  25068. ```
  25069. ```handlebars
  25070. {{input type="text" value=firstName disabled=entryNotAllowed size="50"}}
  25071. ```
  25072. ```html
  25073. <input type="text" value="Stanley" disabled="disabled" size="50"/>
  25074. ```
  25075. ## Extension
  25076. Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing
  25077. arguments from the helper to `Ember.TextField`'s `create` method. You can extend the
  25078. capablilties of text inputs in your applications by reopening this class. For example,
  25079. if you are deploying to browsers where the `required` attribute is used, you
  25080. can add this to the `TextField`'s `attributeBindings` property:
  25081. ```javascript
  25082. Ember.TextField.reopen({
  25083. attributeBindings: ['required']
  25084. });
  25085. ```
  25086. Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField`
  25087. itself extends `Ember.Component`, meaning that it does NOT inherit
  25088. the `controller` of the parent view.
  25089. See more about [Ember components](api/classes/Ember.Component.html)
  25090. ## Use as checkbox
  25091. An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input.
  25092. The following HTML attributes can be set via the helper:
  25093. * `checked`
  25094. * `disabled`
  25095. * `tabindex`
  25096. * `indeterminate`
  25097. * `name`
  25098. When set to a quoted string, these values will be directly applied to the HTML
  25099. element. When left unquoted, these values will be bound to a property on the
  25100. template's current rendering context (most typically a controller instance).
  25101. ## Unbound:
  25102. ```handlebars
  25103. {{input type="checkbox" name="isAdmin"}}
  25104. ```
  25105. ```html
  25106. <input type="checkbox" name="isAdmin" />
  25107. ```
  25108. ## Bound:
  25109. ```javascript
  25110. App.ApplicationController = Ember.Controller.extend({
  25111. isAdmin: true
  25112. });
  25113. ```
  25114. ```handlebars
  25115. {{input type="checkbox" checked=isAdmin }}
  25116. ```
  25117. ```html
  25118. <input type="checkbox" checked="checked" />
  25119. ```
  25120. ## Extension
  25121. Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing
  25122. arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the
  25123. capablilties of checkbox inputs in your applications by reopening this class. For example,
  25124. if you wanted to add a css class to all checkboxes in your application:
  25125. ```javascript
  25126. Ember.Checkbox.reopen({
  25127. classNames: ['my-app-checkbox']
  25128. });
  25129. ```
  25130. @method input
  25131. @for Ember.Handlebars.helpers
  25132. @param {Hash} options
  25133. */
  25134. Ember.Handlebars.registerHelper('input', function(options) {
  25135. Ember.assert('You can only pass attributes to the `input` helper, not arguments', arguments.length < 2);
  25136. var hash = options.hash,
  25137. types = options.hashTypes,
  25138. inputType = hash.type,
  25139. onEvent = hash.on;
  25140. delete hash.type;
  25141. delete hash.on;
  25142. if (inputType === 'checkbox') {
  25143. Ember.assert("{{input type='checkbox'}} does not support setting `value=someBooleanValue`; you must use `checked=someBooleanValue` instead.", options.hashTypes.value !== 'ID');
  25144. return Ember.Handlebars.helpers.view.call(this, Ember.Checkbox, options);
  25145. } else {
  25146. if (inputType) { hash.type = inputType; }
  25147. hash.onEvent = onEvent || 'enter';
  25148. return Ember.Handlebars.helpers.view.call(this, Ember.TextField, options);
  25149. }
  25150. });
  25151. /**
  25152. `{{textarea}}` inserts a new instance of `<textarea>` tag into the template.
  25153. The attributes of `{{textarea}}` match those of the native HTML tags as
  25154. closely as possible.
  25155. The following HTML attributes can be set:
  25156. * `value`
  25157. * `name`
  25158. * `rows`
  25159. * `cols`
  25160. * `placeholder`
  25161. * `disabled`
  25162. * `maxlength`
  25163. * `tabindex`
  25164. When set to a quoted string, these value will be directly applied to the HTML
  25165. element. When left unquoted, these values will be bound to a property on the
  25166. template's current rendering context (most typically a controller instance).
  25167. Unbound:
  25168. ```handlebars
  25169. {{textarea value="Lots of static text that ISN'T bound"}}
  25170. ```
  25171. Would result in the following HTML:
  25172. ```html
  25173. <textarea class="ember-text-area">
  25174. Lots of static text that ISN'T bound
  25175. </textarea>
  25176. ```
  25177. Bound:
  25178. In the following example, the `writtenWords` property on `App.ApplicationController`
  25179. will be updated live as the user types 'Lots of text that IS bound' into
  25180. the text area of their browser's window.
  25181. ```javascript
  25182. App.ApplicationController = Ember.Controller.extend({
  25183. writtenWords: "Lots of text that IS bound"
  25184. });
  25185. ```
  25186. ```handlebars
  25187. {{textarea value=writtenWords}}
  25188. ```
  25189. Would result in the following HTML:
  25190. ```html
  25191. <textarea class="ember-text-area">
  25192. Lots of text that IS bound
  25193. </textarea>
  25194. ```
  25195. If you wanted a one way binding between the text area and a div tag
  25196. somewhere else on your screen, you could use `Ember.computed.oneWay`:
  25197. ```javascript
  25198. App.ApplicationController = Ember.Controller.extend({
  25199. writtenWords: "Lots of text that IS bound",
  25200. outputWrittenWords: Ember.computed.oneWay("writtenWords")
  25201. });
  25202. ```
  25203. ```handlebars
  25204. {{textarea value=writtenWords}}
  25205. <div>
  25206. {{outputWrittenWords}}
  25207. </div>
  25208. ```
  25209. Would result in the following HTML:
  25210. ```html
  25211. <textarea class="ember-text-area">
  25212. Lots of text that IS bound
  25213. </textarea>
  25214. <-- the following div will be updated in real time as you type -->
  25215. <div>
  25216. Lots of text that IS bound
  25217. </div>
  25218. ```
  25219. Finally, this example really shows the power and ease of Ember when two
  25220. properties are bound to eachother via `Ember.computed.alias`. Type into
  25221. either text area box and they'll both stay in sync. Note that
  25222. `Ember.computed.alias` costs more in terms of performance, so only use it when
  25223. your really binding in both directions:
  25224. ```javascript
  25225. App.ApplicationController = Ember.Controller.extend({
  25226. writtenWords: "Lots of text that IS bound",
  25227. twoWayWrittenWords: Ember.computed.alias("writtenWords")
  25228. });
  25229. ```
  25230. ```handlebars
  25231. {{textarea value=writtenWords}}
  25232. {{textarea value=twoWayWrittenWords}}
  25233. ```
  25234. ```html
  25235. <textarea id="ember1" class="ember-text-area">
  25236. Lots of text that IS bound
  25237. </textarea>
  25238. <-- both updated in real time -->
  25239. <textarea id="ember2" class="ember-text-area">
  25240. Lots of text that IS bound
  25241. </textarea>
  25242. ```
  25243. ## Extension
  25244. Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing
  25245. arguments from the helper to `Ember.TextArea`'s `create` method. You can
  25246. extend the capabilities of text areas in your application by reopening this
  25247. class. For example, if you are deploying to browsers where the `required`
  25248. attribute is used, you can globally add support for the `required` attribute
  25249. on all `{{textarea}}`s' in your app by reopening `Ember.TextArea` or
  25250. `Ember.TextSupport` and adding it to the `attributeBindings` concatenated
  25251. property:
  25252. ```javascript
  25253. Ember.TextArea.reopen({
  25254. attributeBindings: ['required']
  25255. });
  25256. ```
  25257. Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea`
  25258. itself extends `Ember.Component`, meaning that it does NOT inherit
  25259. the `controller` of the parent view.
  25260. See more about [Ember components](api/classes/Ember.Component.html)
  25261. @method textarea
  25262. @for Ember.Handlebars.helpers
  25263. @param {Hash} options
  25264. */
  25265. Ember.Handlebars.registerHelper('textarea', function(options) {
  25266. Ember.assert('You can only pass attributes to the `textarea` helper, not arguments', arguments.length < 2);
  25267. var hash = options.hash,
  25268. types = options.hashTypes;
  25269. return Ember.Handlebars.helpers.view.call(this, Ember.TextArea, options);
  25270. });
  25271. })();
  25272. (function() {
  25273. Ember.ComponentLookup = Ember.Object.extend({
  25274. lookupFactory: function(name, container) {
  25275. container = container || this.container;
  25276. var fullName = 'component:' + name,
  25277. templateFullName = 'template:components/' + name,
  25278. templateRegistered = container && container.has(templateFullName);
  25279. if (templateRegistered) {
  25280. container.injection(fullName, 'layout', templateFullName);
  25281. }
  25282. var Component = container.lookupFactory(fullName);
  25283. // Only treat as a component if either the component
  25284. // or a template has been registered.
  25285. if (templateRegistered || Component) {
  25286. if (!Component) {
  25287. container.register(fullName, Ember.Component);
  25288. Component = container.lookupFactory(fullName);
  25289. }
  25290. return Component;
  25291. }
  25292. }
  25293. });
  25294. })();
  25295. (function() {
  25296. /*globals Handlebars */
  25297. /**
  25298. @module ember
  25299. @submodule ember-handlebars
  25300. */
  25301. /**
  25302. Find templates stored in the head tag as script tags and make them available
  25303. to `Ember.CoreView` in the global `Ember.TEMPLATES` object. This will be run
  25304. as as jQuery DOM-ready callback.
  25305. Script tags with `text/x-handlebars` will be compiled
  25306. with Ember's Handlebars and are suitable for use as a view's template.
  25307. Those with type `text/x-raw-handlebars` will be compiled with regular
  25308. Handlebars and are suitable for use in views' computed properties.
  25309. @private
  25310. @method bootstrap
  25311. @for Ember.Handlebars
  25312. @static
  25313. @param ctx
  25314. */
  25315. Ember.Handlebars.bootstrap = function(ctx) {
  25316. var selectors = 'script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]';
  25317. Ember.$(selectors, ctx)
  25318. .each(function() {
  25319. // Get a reference to the script tag
  25320. var script = Ember.$(this);
  25321. var compile = (script.attr('type') === 'text/x-raw-handlebars') ?
  25322. Ember.$.proxy(Handlebars.compile, Handlebars) :
  25323. Ember.$.proxy(Ember.Handlebars.compile, Ember.Handlebars),
  25324. // Get the name of the script, used by Ember.View's templateName property.
  25325. // First look for data-template-name attribute, then fall back to its
  25326. // id if no name is found.
  25327. templateName = script.attr('data-template-name') || script.attr('id') || 'application',
  25328. template = compile(script.html());
  25329. // Check if template of same name already exists
  25330. if (Ember.TEMPLATES[templateName] !== undefined) {
  25331. throw new Ember.Error('Template named "' + templateName + '" already exists.');
  25332. }
  25333. // For templates which have a name, we save them and then remove them from the DOM
  25334. Ember.TEMPLATES[templateName] = template;
  25335. // Remove script tag from DOM
  25336. script.remove();
  25337. });
  25338. };
  25339. function bootstrap() {
  25340. Ember.Handlebars.bootstrap( Ember.$(document) );
  25341. }
  25342. function registerComponentLookup(container) {
  25343. container.register('component-lookup:main', Ember.ComponentLookup);
  25344. }
  25345. /*
  25346. We tie this to application.load to ensure that we've at least
  25347. attempted to bootstrap at the point that the application is loaded.
  25348. We also tie this to document ready since we're guaranteed that all
  25349. the inline templates are present at this point.
  25350. There's no harm to running this twice, since we remove the templates
  25351. from the DOM after processing.
  25352. */
  25353. Ember.onLoad('Ember.Application', function(Application) {
  25354. Application.initializer({
  25355. name: 'domTemplates',
  25356. initialize: bootstrap
  25357. });
  25358. Application.initializer({
  25359. name: 'registerComponentLookup',
  25360. after: 'domTemplates',
  25361. initialize: registerComponentLookup
  25362. });
  25363. });
  25364. })();
  25365. (function() {
  25366. /**
  25367. Ember Handlebars
  25368. @module ember
  25369. @submodule ember-handlebars
  25370. @requires ember-views
  25371. */
  25372. Ember.runLoadHooks('Ember.Handlebars', Ember.Handlebars);
  25373. })();
  25374. (function() {
  25375. define("route-recognizer",
  25376. ["exports"],
  25377. function(__exports__) {
  25378. "use strict";
  25379. var specials = [
  25380. '/', '.', '*', '+', '?', '|',
  25381. '(', ')', '[', ']', '{', '}', '\\'
  25382. ];
  25383. var escapeRegex = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
  25384. // A Segment represents a segment in the original route description.
  25385. // Each Segment type provides an `eachChar` and `regex` method.
  25386. //
  25387. // The `eachChar` method invokes the callback with one or more character
  25388. // specifications. A character specification consumes one or more input
  25389. // characters.
  25390. //
  25391. // The `regex` method returns a regex fragment for the segment. If the
  25392. // segment is a dynamic of star segment, the regex fragment also includes
  25393. // a capture.
  25394. //
  25395. // A character specification contains:
  25396. //
  25397. // * `validChars`: a String with a list of all valid characters, or
  25398. // * `invalidChars`: a String with a list of all invalid characters
  25399. // * `repeat`: true if the character specification can repeat
  25400. function StaticSegment(string) { this.string = string; }
  25401. StaticSegment.prototype = {
  25402. eachChar: function(callback) {
  25403. var string = this.string, ch;
  25404. for (var i=0, l=string.length; i<l; i++) {
  25405. ch = string.charAt(i);
  25406. callback({ validChars: ch });
  25407. }
  25408. },
  25409. regex: function() {
  25410. return this.string.replace(escapeRegex, '\\$1');
  25411. },
  25412. generate: function() {
  25413. return this.string;
  25414. }
  25415. };
  25416. function DynamicSegment(name) { this.name = name; }
  25417. DynamicSegment.prototype = {
  25418. eachChar: function(callback) {
  25419. callback({ invalidChars: "/", repeat: true });
  25420. },
  25421. regex: function() {
  25422. return "([^/]+)";
  25423. },
  25424. generate: function(params) {
  25425. return params[this.name];
  25426. }
  25427. };
  25428. function StarSegment(name) { this.name = name; }
  25429. StarSegment.prototype = {
  25430. eachChar: function(callback) {
  25431. callback({ invalidChars: "", repeat: true });
  25432. },
  25433. regex: function() {
  25434. return "(.+)";
  25435. },
  25436. generate: function(params) {
  25437. return params[this.name];
  25438. }
  25439. };
  25440. function EpsilonSegment() {}
  25441. EpsilonSegment.prototype = {
  25442. eachChar: function() {},
  25443. regex: function() { return ""; },
  25444. generate: function() { return ""; }
  25445. };
  25446. function parse(route, names, types) {
  25447. // normalize route as not starting with a "/". Recognition will
  25448. // also normalize.
  25449. if (route.charAt(0) === "/") { route = route.substr(1); }
  25450. var segments = route.split("/"), results = [];
  25451. for (var i=0, l=segments.length; i<l; i++) {
  25452. var segment = segments[i], match;
  25453. if (match = segment.match(/^:([^\/]+)$/)) {
  25454. results.push(new DynamicSegment(match[1]));
  25455. names.push(match[1]);
  25456. types.dynamics++;
  25457. } else if (match = segment.match(/^\*([^\/]+)$/)) {
  25458. results.push(new StarSegment(match[1]));
  25459. names.push(match[1]);
  25460. types.stars++;
  25461. } else if(segment === "") {
  25462. results.push(new EpsilonSegment());
  25463. } else {
  25464. results.push(new StaticSegment(segment));
  25465. types.statics++;
  25466. }
  25467. }
  25468. return results;
  25469. }
  25470. // A State has a character specification and (`charSpec`) and a list of possible
  25471. // subsequent states (`nextStates`).
  25472. //
  25473. // If a State is an accepting state, it will also have several additional
  25474. // properties:
  25475. //
  25476. // * `regex`: A regular expression that is used to extract parameters from paths
  25477. // that reached this accepting state.
  25478. // * `handlers`: Information on how to convert the list of captures into calls
  25479. // to registered handlers with the specified parameters
  25480. // * `types`: How many static, dynamic or star segments in this route. Used to
  25481. // decide which route to use if multiple registered routes match a path.
  25482. //
  25483. // Currently, State is implemented naively by looping over `nextStates` and
  25484. // comparing a character specification against a character. A more efficient
  25485. // implementation would use a hash of keys pointing at one or more next states.
  25486. function State(charSpec) {
  25487. this.charSpec = charSpec;
  25488. this.nextStates = [];
  25489. }
  25490. State.prototype = {
  25491. get: function(charSpec) {
  25492. var nextStates = this.nextStates;
  25493. for (var i=0, l=nextStates.length; i<l; i++) {
  25494. var child = nextStates[i];
  25495. var isEqual = child.charSpec.validChars === charSpec.validChars;
  25496. isEqual = isEqual && child.charSpec.invalidChars === charSpec.invalidChars;
  25497. if (isEqual) { return child; }
  25498. }
  25499. },
  25500. put: function(charSpec) {
  25501. var state;
  25502. // If the character specification already exists in a child of the current
  25503. // state, just return that state.
  25504. if (state = this.get(charSpec)) { return state; }
  25505. // Make a new state for the character spec
  25506. state = new State(charSpec);
  25507. // Insert the new state as a child of the current state
  25508. this.nextStates.push(state);
  25509. // If this character specification repeats, insert the new state as a child
  25510. // of itself. Note that this will not trigger an infinite loop because each
  25511. // transition during recognition consumes a character.
  25512. if (charSpec.repeat) {
  25513. state.nextStates.push(state);
  25514. }
  25515. // Return the new state
  25516. return state;
  25517. },
  25518. // Find a list of child states matching the next character
  25519. match: function(ch) {
  25520. // DEBUG "Processing `" + ch + "`:"
  25521. var nextStates = this.nextStates,
  25522. child, charSpec, chars;
  25523. // DEBUG " " + debugState(this)
  25524. var returned = [];
  25525. for (var i=0, l=nextStates.length; i<l; i++) {
  25526. child = nextStates[i];
  25527. charSpec = child.charSpec;
  25528. if (typeof (chars = charSpec.validChars) !== 'undefined') {
  25529. if (chars.indexOf(ch) !== -1) { returned.push(child); }
  25530. } else if (typeof (chars = charSpec.invalidChars) !== 'undefined') {
  25531. if (chars.indexOf(ch) === -1) { returned.push(child); }
  25532. }
  25533. }
  25534. return returned;
  25535. }
  25536. /** IF DEBUG
  25537. , debug: function() {
  25538. var charSpec = this.charSpec,
  25539. debug = "[",
  25540. chars = charSpec.validChars || charSpec.invalidChars;
  25541. if (charSpec.invalidChars) { debug += "^"; }
  25542. debug += chars;
  25543. debug += "]";
  25544. if (charSpec.repeat) { debug += "+"; }
  25545. return debug;
  25546. }
  25547. END IF **/
  25548. };
  25549. /** IF DEBUG
  25550. function debug(log) {
  25551. console.log(log);
  25552. }
  25553. function debugState(state) {
  25554. return state.nextStates.map(function(n) {
  25555. if (n.nextStates.length === 0) { return "( " + n.debug() + " [accepting] )"; }
  25556. return "( " + n.debug() + " <then> " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )";
  25557. }).join(", ")
  25558. }
  25559. END IF **/
  25560. // This is a somewhat naive strategy, but should work in a lot of cases
  25561. // A better strategy would properly resolve /posts/:id/new and /posts/edit/:id
  25562. function sortSolutions(states) {
  25563. return states.sort(function(a, b) {
  25564. if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; }
  25565. if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; }
  25566. if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; }
  25567. return 0;
  25568. });
  25569. }
  25570. function recognizeChar(states, ch) {
  25571. var nextStates = [];
  25572. for (var i=0, l=states.length; i<l; i++) {
  25573. var state = states[i];
  25574. nextStates = nextStates.concat(state.match(ch));
  25575. }
  25576. return nextStates;
  25577. }
  25578. var oCreate = Object.create || function(proto) {
  25579. function F() {}
  25580. F.prototype = proto;
  25581. return new F();
  25582. };
  25583. function RecognizeResults(queryParams) {
  25584. this.queryParams = queryParams || {};
  25585. }
  25586. RecognizeResults.prototype = oCreate({
  25587. splice: Array.prototype.splice,
  25588. slice: Array.prototype.slice,
  25589. push: Array.prototype.push,
  25590. length: 0,
  25591. queryParams: null
  25592. });
  25593. function findHandler(state, path, queryParams) {
  25594. var handlers = state.handlers, regex = state.regex;
  25595. var captures = path.match(regex), currentCapture = 1;
  25596. var result = new RecognizeResults(queryParams);
  25597. for (var i=0, l=handlers.length; i<l; i++) {
  25598. var handler = handlers[i], names = handler.names, params = {};
  25599. for (var j=0, m=names.length; j<m; j++) {
  25600. params[names[j]] = captures[currentCapture++];
  25601. }
  25602. result.push({ handler: handler.handler, params: params, isDynamic: !!names.length });
  25603. }
  25604. return result;
  25605. }
  25606. function addSegment(currentState, segment) {
  25607. segment.eachChar(function(ch) {
  25608. var state;
  25609. currentState = currentState.put(ch);
  25610. });
  25611. return currentState;
  25612. }
  25613. // The main interface
  25614. var RouteRecognizer = function() {
  25615. this.rootState = new State();
  25616. this.names = {};
  25617. };
  25618. RouteRecognizer.prototype = {
  25619. add: function(routes, options) {
  25620. var currentState = this.rootState, regex = "^",
  25621. types = { statics: 0, dynamics: 0, stars: 0 },
  25622. handlers = [], allSegments = [], name;
  25623. var isEmpty = true;
  25624. for (var i=0, l=routes.length; i<l; i++) {
  25625. var route = routes[i], names = [];
  25626. var segments = parse(route.path, names, types);
  25627. allSegments = allSegments.concat(segments);
  25628. for (var j=0, m=segments.length; j<m; j++) {
  25629. var segment = segments[j];
  25630. if (segment instanceof EpsilonSegment) { continue; }
  25631. isEmpty = false;
  25632. // Add a "/" for the new segment
  25633. currentState = currentState.put({ validChars: "/" });
  25634. regex += "/";
  25635. // Add a representation of the segment to the NFA and regex
  25636. currentState = addSegment(currentState, segment);
  25637. regex += segment.regex();
  25638. }
  25639. var handler = { handler: route.handler, names: names };
  25640. handlers.push(handler);
  25641. }
  25642. if (isEmpty) {
  25643. currentState = currentState.put({ validChars: "/" });
  25644. regex += "/";
  25645. }
  25646. currentState.handlers = handlers;
  25647. currentState.regex = new RegExp(regex + "$");
  25648. currentState.types = types;
  25649. if (name = options && options.as) {
  25650. this.names[name] = {
  25651. segments: allSegments,
  25652. handlers: handlers
  25653. };
  25654. }
  25655. },
  25656. handlersFor: function(name) {
  25657. var route = this.names[name], result = [];
  25658. if (!route) { throw new Error("There is no route named " + name); }
  25659. for (var i=0, l=route.handlers.length; i<l; i++) {
  25660. result.push(route.handlers[i]);
  25661. }
  25662. return result;
  25663. },
  25664. hasRoute: function(name) {
  25665. return !!this.names[name];
  25666. },
  25667. generate: function(name, params) {
  25668. var route = this.names[name], output = "";
  25669. if (!route) { throw new Error("There is no route named " + name); }
  25670. var segments = route.segments;
  25671. for (var i=0, l=segments.length; i<l; i++) {
  25672. var segment = segments[i];
  25673. if (segment instanceof EpsilonSegment) { continue; }
  25674. output += "/";
  25675. output += segment.generate(params);
  25676. }
  25677. if (output.charAt(0) !== '/') { output = '/' + output; }
  25678. if (params && params.queryParams) {
  25679. output += this.generateQueryString(params.queryParams, route.handlers);
  25680. }
  25681. return output;
  25682. },
  25683. generateQueryString: function(params, handlers) {
  25684. var pairs = [];
  25685. for(var key in params) {
  25686. if (params.hasOwnProperty(key)) {
  25687. var value = params[key];
  25688. if (value === false || value == null) {
  25689. continue;
  25690. }
  25691. var pair = key;
  25692. if (Array.isArray(value)) {
  25693. for (var i = 0, l = value.length; i < l; i++) {
  25694. var arrayPair = key + '[]' + '=' + encodeURIComponent(value[i]);
  25695. pairs.push(arrayPair);
  25696. }
  25697. }
  25698. else if (value !== true) {
  25699. pair += "=" + encodeURIComponent(value);
  25700. pairs.push(pair);
  25701. } else {
  25702. pairs.push(pair);
  25703. }
  25704. }
  25705. }
  25706. if (pairs.length === 0) { return ''; }
  25707. return "?" + pairs.join("&");
  25708. },
  25709. parseQueryString: function(queryString) {
  25710. var pairs = queryString.split("&"), queryParams = {};
  25711. for(var i=0; i < pairs.length; i++) {
  25712. var pair = pairs[i].split('='),
  25713. key = decodeURIComponent(pair[0]),
  25714. keyLength = key.length,
  25715. isArray = false,
  25716. value;
  25717. if (pair.length === 1) {
  25718. value = true;
  25719. } else {
  25720. //Handle arrays
  25721. if (keyLength > 2 && key.slice(keyLength -2) === '[]') {
  25722. isArray = true;
  25723. key = key.slice(0, keyLength - 2);
  25724. if(!queryParams[key]) {
  25725. queryParams[key] = [];
  25726. }
  25727. }
  25728. value = pair[1] ? decodeURIComponent(pair[1]) : '';
  25729. }
  25730. if (isArray) {
  25731. queryParams[key].push(value);
  25732. } else {
  25733. queryParams[key] = value;
  25734. }
  25735. }
  25736. return queryParams;
  25737. },
  25738. recognize: function(path) {
  25739. var states = [ this.rootState ],
  25740. pathLen, i, l, queryStart, queryParams = {},
  25741. isSlashDropped = false;
  25742. queryStart = path.indexOf('?');
  25743. if (queryStart !== -1) {
  25744. var queryString = path.substr(queryStart + 1, path.length);
  25745. path = path.substr(0, queryStart);
  25746. queryParams = this.parseQueryString(queryString);
  25747. }
  25748. // DEBUG GROUP path
  25749. if (path.charAt(0) !== "/") { path = "/" + path; }
  25750. pathLen = path.length;
  25751. if (pathLen > 1 && path.charAt(pathLen - 1) === "/") {
  25752. path = path.substr(0, pathLen - 1);
  25753. isSlashDropped = true;
  25754. }
  25755. for (i=0, l=path.length; i<l; i++) {
  25756. states = recognizeChar(states, path.charAt(i));
  25757. if (!states.length) { break; }
  25758. }
  25759. // END DEBUG GROUP
  25760. var solutions = [];
  25761. for (i=0, l=states.length; i<l; i++) {
  25762. if (states[i].handlers) { solutions.push(states[i]); }
  25763. }
  25764. states = sortSolutions(solutions);
  25765. var state = solutions[0];
  25766. if (state && state.handlers) {
  25767. // if a trailing slash was dropped and a star segment is the last segment
  25768. // specified, put the trailing slash back
  25769. if (isSlashDropped && state.regex.source.slice(-5) === "(.+)$") {
  25770. path = path + "/";
  25771. }
  25772. return findHandler(state, path, queryParams);
  25773. }
  25774. }
  25775. };
  25776. __exports__["default"] = RouteRecognizer;
  25777. function Target(path, matcher, delegate) {
  25778. this.path = path;
  25779. this.matcher = matcher;
  25780. this.delegate = delegate;
  25781. }
  25782. Target.prototype = {
  25783. to: function(target, callback) {
  25784. var delegate = this.delegate;
  25785. if (delegate && delegate.willAddRoute) {
  25786. target = delegate.willAddRoute(this.matcher.target, target);
  25787. }
  25788. this.matcher.add(this.path, target);
  25789. if (callback) {
  25790. if (callback.length === 0) { throw new Error("You must have an argument in the function passed to `to`"); }
  25791. this.matcher.addChild(this.path, target, callback, this.delegate);
  25792. }
  25793. return this;
  25794. }
  25795. };
  25796. function Matcher(target) {
  25797. this.routes = {};
  25798. this.children = {};
  25799. this.target = target;
  25800. }
  25801. Matcher.prototype = {
  25802. add: function(path, handler) {
  25803. this.routes[path] = handler;
  25804. },
  25805. addChild: function(path, target, callback, delegate) {
  25806. var matcher = new Matcher(target);
  25807. this.children[path] = matcher;
  25808. var match = generateMatch(path, matcher, delegate);
  25809. if (delegate && delegate.contextEntered) {
  25810. delegate.contextEntered(target, match);
  25811. }
  25812. callback(match);
  25813. }
  25814. };
  25815. function generateMatch(startingPath, matcher, delegate) {
  25816. return function(path, nestedCallback) {
  25817. var fullPath = startingPath + path;
  25818. if (nestedCallback) {
  25819. nestedCallback(generateMatch(fullPath, matcher, delegate));
  25820. } else {
  25821. return new Target(startingPath + path, matcher, delegate);
  25822. }
  25823. };
  25824. }
  25825. function addRoute(routeArray, path, handler) {
  25826. var len = 0;
  25827. for (var i=0, l=routeArray.length; i<l; i++) {
  25828. len += routeArray[i].path.length;
  25829. }
  25830. path = path.substr(len);
  25831. var route = { path: path, handler: handler };
  25832. routeArray.push(route);
  25833. }
  25834. function eachRoute(baseRoute, matcher, callback, binding) {
  25835. var routes = matcher.routes;
  25836. for (var path in routes) {
  25837. if (routes.hasOwnProperty(path)) {
  25838. var routeArray = baseRoute.slice();
  25839. addRoute(routeArray, path, routes[path]);
  25840. if (matcher.children[path]) {
  25841. eachRoute(routeArray, matcher.children[path], callback, binding);
  25842. } else {
  25843. callback.call(binding, routeArray);
  25844. }
  25845. }
  25846. }
  25847. }
  25848. RouteRecognizer.prototype.map = function(callback, addRouteCallback) {
  25849. var matcher = new Matcher();
  25850. callback(generateMatch("", matcher, this.delegate));
  25851. eachRoute([], matcher, function(route) {
  25852. if (addRouteCallback) { addRouteCallback(this, route); }
  25853. else { this.add(route); }
  25854. }, this);
  25855. };
  25856. });
  25857. })();
  25858. (function() {
  25859. define("router/handler-info",
  25860. ["./utils","rsvp","exports"],
  25861. function(__dependency1__, __dependency2__, __exports__) {
  25862. "use strict";
  25863. var bind = __dependency1__.bind;
  25864. var merge = __dependency1__.merge;
  25865. var oCreate = __dependency1__.oCreate;
  25866. var serialize = __dependency1__.serialize;
  25867. var resolve = __dependency2__.resolve;
  25868. function HandlerInfo(props) {
  25869. if (props) {
  25870. merge(this, props);
  25871. }
  25872. }
  25873. HandlerInfo.prototype = {
  25874. name: null,
  25875. handler: null,
  25876. params: null,
  25877. context: null,
  25878. log: function(payload, message) {
  25879. if (payload.log) {
  25880. payload.log(this.name + ': ' + message);
  25881. }
  25882. },
  25883. resolve: function(async, shouldContinue, payload) {
  25884. var checkForAbort = bind(this.checkForAbort, this, shouldContinue),
  25885. beforeModel = bind(this.runBeforeModelHook, this, async, payload),
  25886. model = bind(this.getModel, this, async, payload),
  25887. afterModel = bind(this.runAfterModelHook, this, async, payload),
  25888. becomeResolved = bind(this.becomeResolved, this, payload);
  25889. return resolve().then(checkForAbort)
  25890. .then(beforeModel)
  25891. .then(checkForAbort)
  25892. .then(model)
  25893. .then(checkForAbort)
  25894. .then(afterModel)
  25895. .then(checkForAbort)
  25896. .then(becomeResolved);
  25897. },
  25898. runBeforeModelHook: function(async, payload) {
  25899. if (payload.trigger) {
  25900. payload.trigger(true, 'willResolveModel', payload, this.handler);
  25901. }
  25902. return this.runSharedModelHook(async, payload, 'beforeModel', []);
  25903. },
  25904. runAfterModelHook: function(async, payload, resolvedModel) {
  25905. // Stash the resolved model on the payload.
  25906. // This makes it possible for users to swap out
  25907. // the resolved model in afterModel.
  25908. var name = this.name;
  25909. this.stashResolvedModel(payload, resolvedModel);
  25910. return this.runSharedModelHook(async, payload, 'afterModel', [resolvedModel])
  25911. .then(function() {
  25912. // Ignore the fulfilled value returned from afterModel.
  25913. // Return the value stashed in resolvedModels, which
  25914. // might have been swapped out in afterModel.
  25915. return payload.resolvedModels[name];
  25916. });
  25917. },
  25918. runSharedModelHook: function(async, payload, hookName, args) {
  25919. this.log(payload, "calling " + hookName + " hook");
  25920. if (this.queryParams) {
  25921. args.push(this.queryParams);
  25922. }
  25923. args.push(payload);
  25924. var handler = this.handler;
  25925. return async(function() {
  25926. return handler[hookName] && handler[hookName].apply(handler, args);
  25927. });
  25928. },
  25929. getModel: function(payload) {
  25930. throw new Error("This should be overridden by a subclass of HandlerInfo");
  25931. },
  25932. checkForAbort: function(shouldContinue, promiseValue) {
  25933. return resolve(shouldContinue()).then(function() {
  25934. // We don't care about shouldContinue's resolve value;
  25935. // pass along the original value passed to this fn.
  25936. return promiseValue;
  25937. });
  25938. },
  25939. stashResolvedModel: function(payload, resolvedModel) {
  25940. payload.resolvedModels = payload.resolvedModels || {};
  25941. payload.resolvedModels[this.name] = resolvedModel;
  25942. },
  25943. becomeResolved: function(payload, resolvedContext) {
  25944. var params = this.params || serialize(this.handler, resolvedContext, this.names);
  25945. if (payload) {
  25946. this.stashResolvedModel(payload, resolvedContext);
  25947. payload.params = payload.params || {};
  25948. payload.params[this.name] = params;
  25949. }
  25950. return new ResolvedHandlerInfo({
  25951. context: resolvedContext,
  25952. name: this.name,
  25953. handler: this.handler,
  25954. params: params
  25955. });
  25956. },
  25957. shouldSupercede: function(other) {
  25958. // Prefer this newer handlerInfo over `other` if:
  25959. // 1) The other one doesn't exist
  25960. // 2) The names don't match
  25961. // 3) This handler has a context that doesn't match
  25962. // the other one (or the other one doesn't have one).
  25963. // 4) This handler has parameters that don't match the other.
  25964. if (!other) { return true; }
  25965. var contextsMatch = (other.context === this.context);
  25966. return other.name !== this.name ||
  25967. (this.hasOwnProperty('context') && !contextsMatch) ||
  25968. (this.hasOwnProperty('params') && !paramsMatch(this.params, other.params));
  25969. }
  25970. };
  25971. function ResolvedHandlerInfo(props) {
  25972. HandlerInfo.call(this, props);
  25973. }
  25974. ResolvedHandlerInfo.prototype = oCreate(HandlerInfo.prototype);
  25975. ResolvedHandlerInfo.prototype.resolve = function(async, shouldContinue, payload) {
  25976. // A ResolvedHandlerInfo just resolved with itself.
  25977. if (payload && payload.resolvedModels) {
  25978. payload.resolvedModels[this.name] = this.context;
  25979. }
  25980. return resolve(this);
  25981. };
  25982. // These are generated by URL transitions and
  25983. // named transitions for non-dynamic route segments.
  25984. function UnresolvedHandlerInfoByParam(props) {
  25985. HandlerInfo.call(this, props);
  25986. this.params = this.params || {};
  25987. }
  25988. UnresolvedHandlerInfoByParam.prototype = oCreate(HandlerInfo.prototype);
  25989. UnresolvedHandlerInfoByParam.prototype.getModel = function(async, payload) {
  25990. var fullParams = this.params;
  25991. if (payload && payload.queryParams) {
  25992. fullParams = {};
  25993. merge(fullParams, this.params);
  25994. fullParams.queryParams = payload.queryParams;
  25995. }
  25996. var hookName = typeof this.handler.deserialize === 'function' ?
  25997. 'deserialize' : 'model';
  25998. return this.runSharedModelHook(async, payload, hookName, [fullParams]);
  25999. };
  26000. // These are generated only for named transitions
  26001. // with dynamic route segments.
  26002. function UnresolvedHandlerInfoByObject(props) {
  26003. HandlerInfo.call(this, props);
  26004. }
  26005. UnresolvedHandlerInfoByObject.prototype = oCreate(HandlerInfo.prototype);
  26006. UnresolvedHandlerInfoByObject.prototype.getModel = function(async, payload) {
  26007. this.log(payload, this.name + ": resolving provided model");
  26008. return resolve(this.context);
  26009. };
  26010. function paramsMatch(a, b) {
  26011. if ((!a) ^ (!b)) {
  26012. // Only one is null.
  26013. return false;
  26014. }
  26015. if (!a) {
  26016. // Both must be null.
  26017. return true;
  26018. }
  26019. // Note: this assumes that both params have the same
  26020. // number of keys, but since we're comparing the
  26021. // same handlers, they should.
  26022. for (var k in a) {
  26023. if (a.hasOwnProperty(k) && a[k] !== b[k]) {
  26024. return false;
  26025. }
  26026. }
  26027. return true;
  26028. }
  26029. __exports__.HandlerInfo = HandlerInfo;
  26030. __exports__.ResolvedHandlerInfo = ResolvedHandlerInfo;
  26031. __exports__.UnresolvedHandlerInfoByParam = UnresolvedHandlerInfoByParam;
  26032. __exports__.UnresolvedHandlerInfoByObject = UnresolvedHandlerInfoByObject;
  26033. });
  26034. define("router/router",
  26035. ["route-recognizer","rsvp","./utils","./transition-state","./transition","./transition-intent/named-transition-intent","./transition-intent/url-transition-intent","exports"],
  26036. function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) {
  26037. "use strict";
  26038. var RouteRecognizer = __dependency1__["default"];
  26039. var resolve = __dependency2__.resolve;
  26040. var reject = __dependency2__.reject;
  26041. var async = __dependency2__.async;
  26042. var Promise = __dependency2__.Promise;
  26043. var trigger = __dependency3__.trigger;
  26044. var log = __dependency3__.log;
  26045. var slice = __dependency3__.slice;
  26046. var forEach = __dependency3__.forEach;
  26047. var merge = __dependency3__.merge;
  26048. var serialize = __dependency3__.serialize;
  26049. var extractQueryParams = __dependency3__.extractQueryParams;
  26050. var getChangelist = __dependency3__.getChangelist;
  26051. var TransitionState = __dependency4__.TransitionState;
  26052. var logAbort = __dependency5__.logAbort;
  26053. var Transition = __dependency5__.Transition;
  26054. var TransitionAborted = __dependency5__.TransitionAborted;
  26055. var NamedTransitionIntent = __dependency6__.NamedTransitionIntent;
  26056. var URLTransitionIntent = __dependency7__.URLTransitionIntent;
  26057. var pop = Array.prototype.pop;
  26058. function Router() {
  26059. this.recognizer = new RouteRecognizer();
  26060. this.reset();
  26061. }
  26062. Router.prototype = {
  26063. /**
  26064. The main entry point into the router. The API is essentially
  26065. the same as the `map` method in `route-recognizer`.
  26066. This method extracts the String handler at the last `.to()`
  26067. call and uses it as the name of the whole route.
  26068. @param {Function} callback
  26069. */
  26070. map: function(callback) {
  26071. this.recognizer.delegate = this.delegate;
  26072. this.recognizer.map(callback, function(recognizer, route) {
  26073. var lastHandler = route[route.length - 1].handler;
  26074. var args = [route, { as: lastHandler }];
  26075. recognizer.add.apply(recognizer, args);
  26076. });
  26077. },
  26078. hasRoute: function(route) {
  26079. return this.recognizer.hasRoute(route);
  26080. },
  26081. // NOTE: this doesn't really belong here, but here
  26082. // it shall remain until our ES6 transpiler can
  26083. // handle cyclical deps.
  26084. transitionByIntent: function(intent, isIntermediate) {
  26085. var wasTransitioning = !!this.activeTransition;
  26086. var oldState = wasTransitioning ? this.activeTransition.state : this.state;
  26087. var newTransition;
  26088. var router = this;
  26089. try {
  26090. var newState = intent.applyToState(oldState, this.recognizer, this.getHandler, isIntermediate);
  26091. if (handlerInfosEqual(newState.handlerInfos, oldState.handlerInfos)) {
  26092. // This is a no-op transition. See if query params changed.
  26093. var queryParamChangelist = getChangelist(oldState.queryParams, newState.queryParams);
  26094. if (queryParamChangelist) {
  26095. // This is a little hacky but we need some way of storing
  26096. // changed query params given that no activeTransition
  26097. // is guaranteed to have occurred.
  26098. this._changedQueryParams = queryParamChangelist.changed;
  26099. trigger(this, newState.handlerInfos, true, ['queryParamsDidChange', queryParamChangelist.changed, queryParamChangelist.all, queryParamChangelist.removed]);
  26100. this._changedQueryParams = null;
  26101. if (!wasTransitioning && this.activeTransition) {
  26102. // One of the handlers in queryParamsDidChange
  26103. // caused a transition. Just return that transition.
  26104. return this.activeTransition;
  26105. } else {
  26106. // Running queryParamsDidChange didn't change anything.
  26107. // Just update query params and be on our way.
  26108. oldState.queryParams = finalizeQueryParamChange(this, newState.handlerInfos, newState.queryParams);
  26109. // We have to return a noop transition that will
  26110. // perform a URL update at the end. This gives
  26111. // the user the ability to set the url update
  26112. // method (default is replaceState).
  26113. newTransition = new Transition(this);
  26114. newTransition.urlMethod = 'replace';
  26115. newTransition.promise = newTransition.promise.then(function(result) {
  26116. updateURL(newTransition, oldState, true);
  26117. if (router.didTransition) {
  26118. router.didTransition(router.currentHandlerInfos);
  26119. }
  26120. return result;
  26121. });
  26122. return newTransition;
  26123. }
  26124. }
  26125. // No-op. No need to create a new transition.
  26126. return new Transition(this);
  26127. }
  26128. if (isIntermediate) {
  26129. setupContexts(this, newState);
  26130. return;
  26131. }
  26132. // Create a new transition to the destination route.
  26133. newTransition = new Transition(this, intent, newState);
  26134. // Abort and usurp any previously active transition.
  26135. if (this.activeTransition) {
  26136. this.activeTransition.abort();
  26137. }
  26138. this.activeTransition = newTransition;
  26139. // Transition promises by default resolve with resolved state.
  26140. // For our purposes, swap out the promise to resolve
  26141. // after the transition has been finalized.
  26142. newTransition.promise = newTransition.promise.then(function(result) {
  26143. return router.async(function() {
  26144. return finalizeTransition(newTransition, result.state);
  26145. });
  26146. });
  26147. if (!wasTransitioning) {
  26148. trigger(this, this.state.handlerInfos, true, ['willTransition', newTransition]);
  26149. }
  26150. return newTransition;
  26151. } catch(e) {
  26152. return new Transition(this, intent, null, e);
  26153. }
  26154. },
  26155. /**
  26156. Clears the current and target route handlers and triggers exit
  26157. on each of them starting at the leaf and traversing up through
  26158. its ancestors.
  26159. */
  26160. reset: function() {
  26161. if (this.state) {
  26162. forEach(this.state.handlerInfos, function(handlerInfo) {
  26163. var handler = handlerInfo.handler;
  26164. if (handler.exit) {
  26165. handler.exit();
  26166. }
  26167. });
  26168. }
  26169. this.state = new TransitionState();
  26170. this.currentHandlerInfos = null;
  26171. },
  26172. activeTransition: null,
  26173. /**
  26174. var handler = handlerInfo.handler;
  26175. The entry point for handling a change to the URL (usually
  26176. via the back and forward button).
  26177. Returns an Array of handlers and the parameters associated
  26178. with those parameters.
  26179. @param {String} url a URL to process
  26180. @return {Array} an Array of `[handler, parameter]` tuples
  26181. */
  26182. handleURL: function(url) {
  26183. // Perform a URL-based transition, but don't change
  26184. // the URL afterward, since it already happened.
  26185. var args = slice.call(arguments);
  26186. if (url.charAt(0) !== '/') { args[0] = '/' + url; }
  26187. return doTransition(this, args).method('replaceQuery');
  26188. },
  26189. /**
  26190. Hook point for updating the URL.
  26191. @param {String} url a URL to update to
  26192. */
  26193. updateURL: function() {
  26194. throw new Error("updateURL is not implemented");
  26195. },
  26196. /**
  26197. Hook point for replacing the current URL, i.e. with replaceState
  26198. By default this behaves the same as `updateURL`
  26199. @param {String} url a URL to update to
  26200. */
  26201. replaceURL: function(url) {
  26202. this.updateURL(url);
  26203. },
  26204. /**
  26205. Transition into the specified named route.
  26206. If necessary, trigger the exit callback on any handlers
  26207. that are no longer represented by the target route.
  26208. @param {String} name the name of the route
  26209. */
  26210. transitionTo: function(name) {
  26211. return doTransition(this, arguments);
  26212. },
  26213. intermediateTransitionTo: function(name) {
  26214. doTransition(this, arguments, true);
  26215. },
  26216. refresh: function(pivotHandler) {
  26217. var state = this.activeTransition ? this.activeTransition.state : this.state;
  26218. var handlerInfos = state.handlerInfos;
  26219. var params = {};
  26220. for (var i = 0, len = handlerInfos.length; i < len; ++i) {
  26221. var handlerInfo = handlerInfos[i];
  26222. params[handlerInfo.name] = handlerInfo.params || {};
  26223. }
  26224. log(this, "Starting a refresh transition");
  26225. var intent = new NamedTransitionIntent({
  26226. name: handlerInfos[handlerInfos.length - 1].name,
  26227. pivotHandler: pivotHandler || handlerInfos[0].handler,
  26228. contexts: [], // TODO collect contexts...?
  26229. queryParams: this._changedQueryParams || state.queryParams || {}
  26230. });
  26231. return this.transitionByIntent(intent, false);
  26232. },
  26233. /**
  26234. Identical to `transitionTo` except that the current URL will be replaced
  26235. if possible.
  26236. This method is intended primarily for use with `replaceState`.
  26237. @param {String} name the name of the route
  26238. */
  26239. replaceWith: function(name) {
  26240. return doTransition(this, arguments).method('replace');
  26241. },
  26242. /**
  26243. Take a named route and context objects and generate a
  26244. URL.
  26245. @param {String} name the name of the route to generate
  26246. a URL for
  26247. @param {...Object} objects a list of objects to serialize
  26248. @return {String} a URL
  26249. */
  26250. generate: function(handlerName) {
  26251. var partitionedArgs = extractQueryParams(slice.call(arguments, 1)),
  26252. suppliedParams = partitionedArgs[0],
  26253. queryParams = partitionedArgs[1];
  26254. // Construct a TransitionIntent with the provided params
  26255. // and apply it to the present state of the router.
  26256. var intent = new NamedTransitionIntent({ name: handlerName, contexts: suppliedParams });
  26257. var state = intent.applyToState(this.state, this.recognizer, this.getHandler);
  26258. var params = {};
  26259. for (var i = 0, len = state.handlerInfos.length; i < len; ++i) {
  26260. var handlerInfo = state.handlerInfos[i];
  26261. var handlerParams = handlerInfo.params ||
  26262. serialize(handlerInfo.handler, handlerInfo.context, handlerInfo.names);
  26263. merge(params, handlerParams);
  26264. }
  26265. params.queryParams = queryParams;
  26266. return this.recognizer.generate(handlerName, params);
  26267. },
  26268. isActive: function(handlerName) {
  26269. var partitionedArgs = extractQueryParams(slice.call(arguments, 1)),
  26270. contexts = partitionedArgs[0],
  26271. queryParams = partitionedArgs[1],
  26272. activeQueryParams = this.state.queryParams;
  26273. var targetHandlerInfos = this.state.handlerInfos,
  26274. found = false, names, object, handlerInfo, handlerObj, i, len;
  26275. if (!targetHandlerInfos.length) { return false; }
  26276. var targetHandler = targetHandlerInfos[targetHandlerInfos.length - 1].name;
  26277. var recogHandlers = this.recognizer.handlersFor(targetHandler);
  26278. var index = 0;
  26279. for (len = recogHandlers.length; index < len; ++index) {
  26280. handlerInfo = targetHandlerInfos[index];
  26281. if (handlerInfo.name === handlerName) { break; }
  26282. }
  26283. if (index === recogHandlers.length) {
  26284. // The provided route name isn't even in the route hierarchy.
  26285. return false;
  26286. }
  26287. var state = new TransitionState();
  26288. state.handlerInfos = targetHandlerInfos.slice(0, index + 1);
  26289. recogHandlers = recogHandlers.slice(0, index + 1);
  26290. var intent = new NamedTransitionIntent({
  26291. name: targetHandler,
  26292. contexts: contexts
  26293. });
  26294. var newState = intent.applyToHandlers(state, recogHandlers, this.getHandler, targetHandler, true, true);
  26295. return handlerInfosEqual(newState.handlerInfos, state.handlerInfos) &&
  26296. !getChangelist(activeQueryParams, queryParams);
  26297. },
  26298. trigger: function(name) {
  26299. var args = slice.call(arguments);
  26300. trigger(this, this.currentHandlerInfos, false, args);
  26301. },
  26302. /**
  26303. @private
  26304. Pluggable hook for possibly running route hooks
  26305. in a try-catch escaping manner.
  26306. @param {Function} callback the callback that will
  26307. be asynchronously called
  26308. @return {Promise} a promise that fulfills with the
  26309. value returned from the callback
  26310. */
  26311. async: function(callback) {
  26312. return new Promise(function(resolve) {
  26313. resolve(callback());
  26314. });
  26315. },
  26316. /**
  26317. Hook point for logging transition status updates.
  26318. @param {String} message The message to log.
  26319. */
  26320. log: null
  26321. };
  26322. /**
  26323. @private
  26324. Takes an Array of `HandlerInfo`s, figures out which ones are
  26325. exiting, entering, or changing contexts, and calls the
  26326. proper handler hooks.
  26327. For example, consider the following tree of handlers. Each handler is
  26328. followed by the URL segment it handles.
  26329. ```
  26330. |~index ("/")
  26331. | |~posts ("/posts")
  26332. | | |-showPost ("/:id")
  26333. | | |-newPost ("/new")
  26334. | | |-editPost ("/edit")
  26335. | |~about ("/about/:id")
  26336. ```
  26337. Consider the following transitions:
  26338. 1. A URL transition to `/posts/1`.
  26339. 1. Triggers the `*model` callbacks on the
  26340. `index`, `posts`, and `showPost` handlers
  26341. 2. Triggers the `enter` callback on the same
  26342. 3. Triggers the `setup` callback on the same
  26343. 2. A direct transition to `newPost`
  26344. 1. Triggers the `exit` callback on `showPost`
  26345. 2. Triggers the `enter` callback on `newPost`
  26346. 3. Triggers the `setup` callback on `newPost`
  26347. 3. A direct transition to `about` with a specified
  26348. context object
  26349. 1. Triggers the `exit` callback on `newPost`
  26350. and `posts`
  26351. 2. Triggers the `serialize` callback on `about`
  26352. 3. Triggers the `enter` callback on `about`
  26353. 4. Triggers the `setup` callback on `about`
  26354. @param {Router} transition
  26355. @param {TransitionState} newState
  26356. */
  26357. function setupContexts(router, newState, transition) {
  26358. var partition = partitionHandlers(router.state, newState);
  26359. forEach(partition.exited, function(handlerInfo) {
  26360. var handler = handlerInfo.handler;
  26361. delete handler.context;
  26362. if (handler.exit) { handler.exit(); }
  26363. });
  26364. var oldState = router.oldState = router.state;
  26365. router.state = newState;
  26366. var currentHandlerInfos = router.currentHandlerInfos = partition.unchanged.slice();
  26367. try {
  26368. forEach(partition.updatedContext, function(handlerInfo) {
  26369. return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, false, transition);
  26370. });
  26371. forEach(partition.entered, function(handlerInfo) {
  26372. return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, true, transition);
  26373. });
  26374. } catch(e) {
  26375. router.state = oldState;
  26376. router.currentHandlerInfos = oldState.handlerInfos;
  26377. throw e;
  26378. }
  26379. router.state.queryParams = finalizeQueryParamChange(router, currentHandlerInfos, newState.queryParams);
  26380. }
  26381. /**
  26382. @private
  26383. Helper method used by setupContexts. Handles errors or redirects
  26384. that may happen in enter/setup.
  26385. */
  26386. function handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, enter, transition) {
  26387. var handler = handlerInfo.handler,
  26388. context = handlerInfo.context;
  26389. if (enter && handler.enter) { handler.enter(transition); }
  26390. if (transition && transition.isAborted) {
  26391. throw new TransitionAborted();
  26392. }
  26393. handler.context = context;
  26394. if (handler.contextDidChange) { handler.contextDidChange(); }
  26395. if (handler.setup) { handler.setup(context, transition); }
  26396. if (transition && transition.isAborted) {
  26397. throw new TransitionAborted();
  26398. }
  26399. currentHandlerInfos.push(handlerInfo);
  26400. return true;
  26401. }
  26402. /**
  26403. @private
  26404. This function is called when transitioning from one URL to
  26405. another to determine which handlers are no longer active,
  26406. which handlers are newly active, and which handlers remain
  26407. active but have their context changed.
  26408. Take a list of old handlers and new handlers and partition
  26409. them into four buckets:
  26410. * unchanged: the handler was active in both the old and
  26411. new URL, and its context remains the same
  26412. * updated context: the handler was active in both the
  26413. old and new URL, but its context changed. The handler's
  26414. `setup` method, if any, will be called with the new
  26415. context.
  26416. * exited: the handler was active in the old URL, but is
  26417. no longer active.
  26418. * entered: the handler was not active in the old URL, but
  26419. is now active.
  26420. The PartitionedHandlers structure has four fields:
  26421. * `updatedContext`: a list of `HandlerInfo` objects that
  26422. represent handlers that remain active but have a changed
  26423. context
  26424. * `entered`: a list of `HandlerInfo` objects that represent
  26425. handlers that are newly active
  26426. * `exited`: a list of `HandlerInfo` objects that are no
  26427. longer active.
  26428. * `unchanged`: a list of `HanderInfo` objects that remain active.
  26429. @param {Array[HandlerInfo]} oldHandlers a list of the handler
  26430. information for the previous URL (or `[]` if this is the
  26431. first handled transition)
  26432. @param {Array[HandlerInfo]} newHandlers a list of the handler
  26433. information for the new URL
  26434. @return {Partition}
  26435. */
  26436. function partitionHandlers(oldState, newState) {
  26437. var oldHandlers = oldState.handlerInfos;
  26438. var newHandlers = newState.handlerInfos;
  26439. var handlers = {
  26440. updatedContext: [],
  26441. exited: [],
  26442. entered: [],
  26443. unchanged: []
  26444. };
  26445. var handlerChanged, contextChanged, queryParamsChanged, i, l;
  26446. for (i=0, l=newHandlers.length; i<l; i++) {
  26447. var oldHandler = oldHandlers[i], newHandler = newHandlers[i];
  26448. if (!oldHandler || oldHandler.handler !== newHandler.handler) {
  26449. handlerChanged = true;
  26450. }
  26451. if (handlerChanged) {
  26452. handlers.entered.push(newHandler);
  26453. if (oldHandler) { handlers.exited.unshift(oldHandler); }
  26454. } else if (contextChanged || oldHandler.context !== newHandler.context || queryParamsChanged) {
  26455. contextChanged = true;
  26456. handlers.updatedContext.push(newHandler);
  26457. } else {
  26458. handlers.unchanged.push(oldHandler);
  26459. }
  26460. }
  26461. for (i=newHandlers.length, l=oldHandlers.length; i<l; i++) {
  26462. handlers.exited.unshift(oldHandlers[i]);
  26463. }
  26464. return handlers;
  26465. }
  26466. function updateURL(transition, state, inputUrl) {
  26467. var urlMethod = transition.urlMethod;
  26468. if (!urlMethod) {
  26469. return;
  26470. }
  26471. var router = transition.router,
  26472. handlerInfos = state.handlerInfos,
  26473. handlerName = handlerInfos[handlerInfos.length - 1].name,
  26474. params = {};
  26475. for (var i = handlerInfos.length - 1; i >= 0; --i) {
  26476. var handlerInfo = handlerInfos[i];
  26477. merge(params, handlerInfo.params);
  26478. if (handlerInfo.handler.inaccessibleByURL) {
  26479. urlMethod = null;
  26480. }
  26481. }
  26482. if (urlMethod) {
  26483. params.queryParams = state.queryParams;
  26484. var url = router.recognizer.generate(handlerName, params);
  26485. if (urlMethod === 'replaceQuery') {
  26486. if (url !== inputUrl) {
  26487. router.replaceURL(url);
  26488. }
  26489. } else if (urlMethod === 'replace') {
  26490. router.replaceURL(url);
  26491. } else {
  26492. router.updateURL(url);
  26493. }
  26494. }
  26495. }
  26496. /**
  26497. @private
  26498. Updates the URL (if necessary) and calls `setupContexts`
  26499. to update the router's array of `currentHandlerInfos`.
  26500. */
  26501. function finalizeTransition(transition, newState) {
  26502. try {
  26503. log(transition.router, transition.sequence, "Resolved all models on destination route; finalizing transition.");
  26504. var router = transition.router,
  26505. handlerInfos = newState.handlerInfos,
  26506. seq = transition.sequence;
  26507. // Run all the necessary enter/setup/exit hooks
  26508. setupContexts(router, newState, transition);
  26509. // Check if a redirect occurred in enter/setup
  26510. if (transition.isAborted) {
  26511. // TODO: cleaner way? distinguish b/w targetHandlerInfos?
  26512. router.state.handlerInfos = router.currentHandlerInfos;
  26513. return reject(logAbort(transition));
  26514. }
  26515. updateURL(transition, newState, transition.intent.url);
  26516. transition.isActive = false;
  26517. router.activeTransition = null;
  26518. trigger(router, router.currentHandlerInfos, true, ['didTransition']);
  26519. if (router.didTransition) {
  26520. router.didTransition(router.currentHandlerInfos);
  26521. }
  26522. log(router, transition.sequence, "TRANSITION COMPLETE.");
  26523. // Resolve with the final handler.
  26524. return handlerInfos[handlerInfos.length - 1].handler;
  26525. } catch(e) {
  26526. if (!(e instanceof TransitionAborted)) {
  26527. //var erroneousHandler = handlerInfos.pop();
  26528. var infos = transition.state.handlerInfos;
  26529. transition.trigger(true, 'error', e, transition, infos[infos.length-1]);
  26530. transition.abort();
  26531. }
  26532. throw e;
  26533. }
  26534. }
  26535. /**
  26536. @private
  26537. Begins and returns a Transition based on the provided
  26538. arguments. Accepts arguments in the form of both URL
  26539. transitions and named transitions.
  26540. @param {Router} router
  26541. @param {Array[Object]} args arguments passed to transitionTo,
  26542. replaceWith, or handleURL
  26543. */
  26544. function doTransition(router, args, isIntermediate) {
  26545. // Normalize blank transitions to root URL transitions.
  26546. var name = args[0] || '/';
  26547. var lastArg = args[args.length-1];
  26548. var queryParams = {};
  26549. if (lastArg && lastArg.hasOwnProperty('queryParams')) {
  26550. queryParams = pop.call(args).queryParams;
  26551. }
  26552. var intent;
  26553. if (args.length === 0) {
  26554. log(router, "Updating query params");
  26555. // A query param update is really just a transition
  26556. // into the route you're already on.
  26557. var handlerInfos = router.state.handlerInfos;
  26558. intent = new NamedTransitionIntent({
  26559. name: handlerInfos[handlerInfos.length - 1].name,
  26560. contexts: [],
  26561. queryParams: queryParams
  26562. });
  26563. } else if (name.charAt(0) === '/') {
  26564. log(router, "Attempting URL transition to " + name);
  26565. intent = new URLTransitionIntent({ url: name });
  26566. } else {
  26567. log(router, "Attempting transition to " + name);
  26568. intent = new NamedTransitionIntent({
  26569. name: args[0],
  26570. contexts: slice.call(args, 1),
  26571. queryParams: queryParams
  26572. });
  26573. }
  26574. return router.transitionByIntent(intent, isIntermediate);
  26575. }
  26576. function handlerInfosEqual(handlerInfos, otherHandlerInfos) {
  26577. if (handlerInfos.length !== otherHandlerInfos.length) {
  26578. return false;
  26579. }
  26580. for (var i = 0, len = handlerInfos.length; i < len; ++i) {
  26581. if (handlerInfos[i] !== otherHandlerInfos[i]) {
  26582. return false;
  26583. }
  26584. }
  26585. return true;
  26586. }
  26587. function finalizeQueryParamChange(router, resolvedHandlers, newQueryParams) {
  26588. // We fire a finalizeQueryParamChange event which
  26589. // gives the new route hierarchy a chance to tell
  26590. // us which query params it's consuming and what
  26591. // their final values are. If a query param is
  26592. // no longer consumed in the final route hierarchy,
  26593. // its serialized segment will be removed
  26594. // from the URL.
  26595. var finalQueryParamsArray = [];
  26596. trigger(router, resolvedHandlers, true, ['finalizeQueryParamChange', newQueryParams, finalQueryParamsArray]);
  26597. var finalQueryParams = {};
  26598. for (var i = 0, len = finalQueryParamsArray.length; i < len; ++i) {
  26599. var qp = finalQueryParamsArray[i];
  26600. finalQueryParams[qp.key] = qp.value;
  26601. }
  26602. return finalQueryParams;
  26603. }
  26604. __exports__.Router = Router;
  26605. });
  26606. define("router/transition-intent",
  26607. ["./utils","exports"],
  26608. function(__dependency1__, __exports__) {
  26609. "use strict";
  26610. var merge = __dependency1__.merge;
  26611. function TransitionIntent(props) {
  26612. if (props) {
  26613. merge(this, props);
  26614. }
  26615. this.data = this.data || {};
  26616. }
  26617. TransitionIntent.prototype.applyToState = function(oldState) {
  26618. // Default TransitionIntent is a no-op.
  26619. return oldState;
  26620. };
  26621. __exports__.TransitionIntent = TransitionIntent;
  26622. });
  26623. define("router/transition-intent/named-transition-intent",
  26624. ["../transition-intent","../transition-state","../handler-info","../utils","exports"],
  26625. function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) {
  26626. "use strict";
  26627. var TransitionIntent = __dependency1__.TransitionIntent;
  26628. var TransitionState = __dependency2__.TransitionState;
  26629. var UnresolvedHandlerInfoByParam = __dependency3__.UnresolvedHandlerInfoByParam;
  26630. var UnresolvedHandlerInfoByObject = __dependency3__.UnresolvedHandlerInfoByObject;
  26631. var isParam = __dependency4__.isParam;
  26632. var forEach = __dependency4__.forEach;
  26633. var extractQueryParams = __dependency4__.extractQueryParams;
  26634. var oCreate = __dependency4__.oCreate;
  26635. var merge = __dependency4__.merge;
  26636. function NamedTransitionIntent(props) {
  26637. TransitionIntent.call(this, props);
  26638. }
  26639. NamedTransitionIntent.prototype = oCreate(TransitionIntent.prototype);
  26640. NamedTransitionIntent.prototype.applyToState = function(oldState, recognizer, getHandler, isIntermediate) {
  26641. var partitionedArgs = extractQueryParams([this.name].concat(this.contexts)),
  26642. pureArgs = partitionedArgs[0],
  26643. queryParams = partitionedArgs[1],
  26644. handlers = recognizer.handlersFor(pureArgs[0]);
  26645. var targetRouteName = handlers[handlers.length-1].handler;
  26646. return this.applyToHandlers(oldState, handlers, getHandler, targetRouteName, isIntermediate);
  26647. };
  26648. NamedTransitionIntent.prototype.applyToHandlers = function(oldState, handlers, getHandler, targetRouteName, isIntermediate, checkingIfActive) {
  26649. var i;
  26650. var newState = new TransitionState();
  26651. var objects = this.contexts.slice(0);
  26652. var invalidateIndex = handlers.length;
  26653. var nonDynamicIndexes = [];
  26654. // Pivot handlers are provided for refresh transitions
  26655. if (this.pivotHandler) {
  26656. for (i = 0; i < handlers.length; ++i) {
  26657. if (getHandler(handlers[i].handler) === this.pivotHandler) {
  26658. invalidateIndex = i;
  26659. break;
  26660. }
  26661. }
  26662. }
  26663. var pivotHandlerFound = !this.pivotHandler;
  26664. for (i = handlers.length - 1; i >= 0; --i) {
  26665. var result = handlers[i];
  26666. var name = result.handler;
  26667. var handler = getHandler(name);
  26668. var oldHandlerInfo = oldState.handlerInfos[i];
  26669. var newHandlerInfo = null;
  26670. if (result.names.length > 0) {
  26671. if (i >= invalidateIndex) {
  26672. newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo);
  26673. } else {
  26674. newHandlerInfo = this.getHandlerInfoForDynamicSegment(name, handler, result.names, objects, oldHandlerInfo, targetRouteName);
  26675. }
  26676. } else {
  26677. // This route has no dynamic segment.
  26678. // Therefore treat as a param-based handlerInfo
  26679. // with empty params. This will cause the `model`
  26680. // hook to be called with empty params, which is desirable.
  26681. newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo);
  26682. nonDynamicIndexes.unshift(i);
  26683. }
  26684. if (checkingIfActive) {
  26685. // If we're performing an isActive check, we want to
  26686. // serialize URL params with the provided context, but
  26687. // ignore mismatches between old and new context.
  26688. newHandlerInfo = newHandlerInfo.becomeResolved(null, newHandlerInfo.context);
  26689. var oldContext = oldHandlerInfo && oldHandlerInfo.context;
  26690. if (result.names.length > 0 && newHandlerInfo.context === oldContext) {
  26691. // If contexts match in isActive test, assume params also match.
  26692. // This allows for flexibility in not requiring that every last
  26693. // handler provide a `serialize` method
  26694. newHandlerInfo.params = oldHandlerInfo && oldHandlerInfo.params;
  26695. }
  26696. newHandlerInfo.context = oldContext;
  26697. }
  26698. var handlerToUse = oldHandlerInfo;
  26699. if (i >= invalidateIndex || newHandlerInfo.shouldSupercede(oldHandlerInfo)) {
  26700. invalidateIndex = Math.min(i, invalidateIndex);
  26701. handlerToUse = newHandlerInfo;
  26702. }
  26703. if (isIntermediate && !checkingIfActive) {
  26704. handlerToUse = handlerToUse.becomeResolved(null, handlerToUse.context);
  26705. }
  26706. newState.handlerInfos.unshift(handlerToUse);
  26707. }
  26708. if (objects.length > 0) {
  26709. throw new Error("More context objects were passed than there are dynamic segments for the route: " + targetRouteName);
  26710. }
  26711. if (!isIntermediate) {
  26712. this.invalidateNonDynamicHandlers(newState.handlerInfos, nonDynamicIndexes, invalidateIndex);
  26713. }
  26714. merge(newState.queryParams, oldState.queryParams);
  26715. merge(newState.queryParams, this.queryParams || {});
  26716. return newState;
  26717. };
  26718. NamedTransitionIntent.prototype.invalidateNonDynamicHandlers = function(handlerInfos, indexes, invalidateIndex) {
  26719. forEach(indexes, function(i) {
  26720. if (i >= invalidateIndex) {
  26721. var handlerInfo = handlerInfos[i];
  26722. handlerInfos[i] = new UnresolvedHandlerInfoByParam({
  26723. name: handlerInfo.name,
  26724. handler: handlerInfo.handler,
  26725. params: {}
  26726. });
  26727. }
  26728. });
  26729. };
  26730. NamedTransitionIntent.prototype.getHandlerInfoForDynamicSegment = function(name, handler, names, objects, oldHandlerInfo, targetRouteName) {
  26731. var numNames = names.length;
  26732. var objectToUse;
  26733. if (objects.length > 0) {
  26734. // Use the objects provided for this transition.
  26735. objectToUse = objects[objects.length - 1];
  26736. if (isParam(objectToUse)) {
  26737. return this.createParamHandlerInfo(name, handler, names, objects, oldHandlerInfo);
  26738. } else {
  26739. objects.pop();
  26740. }
  26741. } else if (oldHandlerInfo && oldHandlerInfo.name === name) {
  26742. // Reuse the matching oldHandlerInfo
  26743. return oldHandlerInfo;
  26744. } else {
  26745. // Ideally we should throw this error to provide maximal
  26746. // information to the user that not enough context objects
  26747. // were provided, but this proves too cumbersome in Ember
  26748. // in cases where inner template helpers are evaluated
  26749. // before parent helpers un-render, in which cases this
  26750. // error somewhat prematurely fires.
  26751. //throw new Error("Not enough context objects were provided to complete a transition to " + targetRouteName + ". Specifically, the " + name + " route needs an object that can be serialized into its dynamic URL segments [" + names.join(', ') + "]");
  26752. return oldHandlerInfo;
  26753. }
  26754. return new UnresolvedHandlerInfoByObject({
  26755. name: name,
  26756. handler: handler,
  26757. context: objectToUse,
  26758. names: names
  26759. });
  26760. };
  26761. NamedTransitionIntent.prototype.createParamHandlerInfo = function(name, handler, names, objects, oldHandlerInfo) {
  26762. var params = {};
  26763. // Soak up all the provided string/numbers
  26764. var numNames = names.length;
  26765. while (numNames--) {
  26766. // Only use old params if the names match with the new handler
  26767. var oldParams = (oldHandlerInfo && name === oldHandlerInfo.name && oldHandlerInfo.params) || {};
  26768. var peek = objects[objects.length - 1];
  26769. var paramName = names[numNames];
  26770. if (isParam(peek)) {
  26771. params[paramName] = "" + objects.pop();
  26772. } else {
  26773. // If we're here, this means only some of the params
  26774. // were string/number params, so try and use a param
  26775. // value from a previous handler.
  26776. if (oldParams.hasOwnProperty(paramName)) {
  26777. params[paramName] = oldParams[paramName];
  26778. } else {
  26779. throw new Error("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route " + name);
  26780. }
  26781. }
  26782. }
  26783. return new UnresolvedHandlerInfoByParam({
  26784. name: name,
  26785. handler: handler,
  26786. params: params
  26787. });
  26788. };
  26789. __exports__.NamedTransitionIntent = NamedTransitionIntent;
  26790. });
  26791. define("router/transition-intent/url-transition-intent",
  26792. ["../transition-intent","../transition-state","../handler-info","../utils","exports"],
  26793. function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) {
  26794. "use strict";
  26795. var TransitionIntent = __dependency1__.TransitionIntent;
  26796. var TransitionState = __dependency2__.TransitionState;
  26797. var UnresolvedHandlerInfoByParam = __dependency3__.UnresolvedHandlerInfoByParam;
  26798. var oCreate = __dependency4__.oCreate;
  26799. var merge = __dependency4__.merge;
  26800. function URLTransitionIntent(props) {
  26801. TransitionIntent.call(this, props);
  26802. }
  26803. URLTransitionIntent.prototype = oCreate(TransitionIntent.prototype);
  26804. URLTransitionIntent.prototype.applyToState = function(oldState, recognizer, getHandler) {
  26805. var newState = new TransitionState();
  26806. var results = recognizer.recognize(this.url),
  26807. queryParams = {},
  26808. i, len;
  26809. if (!results) {
  26810. throw new UnrecognizedURLError(this.url);
  26811. }
  26812. var statesDiffer = false;
  26813. for (i = 0, len = results.length; i < len; ++i) {
  26814. var result = results[i];
  26815. var name = result.handler;
  26816. var handler = getHandler(name);
  26817. if (handler.inaccessibleByURL) {
  26818. throw new UnrecognizedURLError(this.url);
  26819. }
  26820. var newHandlerInfo = new UnresolvedHandlerInfoByParam({
  26821. name: name,
  26822. handler: handler,
  26823. params: result.params
  26824. });
  26825. var oldHandlerInfo = oldState.handlerInfos[i];
  26826. if (statesDiffer || newHandlerInfo.shouldSupercede(oldHandlerInfo)) {
  26827. statesDiffer = true;
  26828. newState.handlerInfos[i] = newHandlerInfo;
  26829. } else {
  26830. newState.handlerInfos[i] = oldHandlerInfo;
  26831. }
  26832. }
  26833. merge(newState.queryParams, results.queryParams);
  26834. return newState;
  26835. };
  26836. /**
  26837. Promise reject reasons passed to promise rejection
  26838. handlers for failed transitions.
  26839. */
  26840. function UnrecognizedURLError(message) {
  26841. this.message = (message || "UnrecognizedURLError");
  26842. this.name = "UnrecognizedURLError";
  26843. }
  26844. __exports__.URLTransitionIntent = URLTransitionIntent;
  26845. });
  26846. define("router/transition-state",
  26847. ["./handler-info","./utils","rsvp","exports"],
  26848. function(__dependency1__, __dependency2__, __dependency3__, __exports__) {
  26849. "use strict";
  26850. var ResolvedHandlerInfo = __dependency1__.ResolvedHandlerInfo;
  26851. var forEach = __dependency2__.forEach;
  26852. var resolve = __dependency3__.resolve;
  26853. function TransitionState(other) {
  26854. this.handlerInfos = [];
  26855. this.queryParams = {};
  26856. this.params = {};
  26857. }
  26858. TransitionState.prototype = {
  26859. handlerInfos: null,
  26860. queryParams: null,
  26861. params: null,
  26862. resolve: function(async, shouldContinue, payload) {
  26863. // First, calculate params for this state. This is useful
  26864. // information to provide to the various route hooks.
  26865. var params = this.params;
  26866. forEach(this.handlerInfos, function(handlerInfo) {
  26867. params[handlerInfo.name] = handlerInfo.params || {};
  26868. });
  26869. payload = payload || {};
  26870. payload.resolveIndex = 0;
  26871. var currentState = this;
  26872. var wasAborted = false;
  26873. // The prelude RSVP.resolve() asyncs us into the promise land.
  26874. return resolve().then(resolveOneHandlerInfo)['catch'](handleError);
  26875. function innerShouldContinue() {
  26876. return resolve(shouldContinue())['catch'](function(reason) {
  26877. // We distinguish between errors that occurred
  26878. // during resolution (e.g. beforeModel/model/afterModel),
  26879. // and aborts due to a rejecting promise from shouldContinue().
  26880. wasAborted = true;
  26881. throw reason;
  26882. });
  26883. }
  26884. function handleError(error) {
  26885. // This is the only possible
  26886. // reject value of TransitionState#resolve
  26887. throw {
  26888. error: error,
  26889. handlerWithError: currentState.handlerInfos[payload.resolveIndex].handler,
  26890. wasAborted: wasAborted,
  26891. state: currentState
  26892. };
  26893. }
  26894. function proceed(resolvedHandlerInfo) {
  26895. // Swap the previously unresolved handlerInfo with
  26896. // the resolved handlerInfo
  26897. currentState.handlerInfos[payload.resolveIndex++] = resolvedHandlerInfo;
  26898. // Call the redirect hook. The reason we call it here
  26899. // vs. afterModel is so that redirects into child
  26900. // routes don't re-run the model hooks for this
  26901. // already-resolved route.
  26902. var handler = resolvedHandlerInfo.handler;
  26903. if (handler && handler.redirect) {
  26904. handler.redirect(resolvedHandlerInfo.context, payload);
  26905. }
  26906. // Proceed after ensuring that the redirect hook
  26907. // didn't abort this transition by transitioning elsewhere.
  26908. return innerShouldContinue().then(resolveOneHandlerInfo);
  26909. }
  26910. function resolveOneHandlerInfo() {
  26911. if (payload.resolveIndex === currentState.handlerInfos.length) {
  26912. // This is is the only possible
  26913. // fulfill value of TransitionState#resolve
  26914. return {
  26915. error: null,
  26916. state: currentState
  26917. };
  26918. }
  26919. var handlerInfo = currentState.handlerInfos[payload.resolveIndex];
  26920. return handlerInfo.resolve(async, innerShouldContinue, payload)
  26921. .then(proceed);
  26922. }
  26923. }
  26924. };
  26925. __exports__.TransitionState = TransitionState;
  26926. });
  26927. define("router/transition",
  26928. ["rsvp","./handler-info","./utils","exports"],
  26929. function(__dependency1__, __dependency2__, __dependency3__, __exports__) {
  26930. "use strict";
  26931. var reject = __dependency1__.reject;
  26932. var resolve = __dependency1__.resolve;
  26933. var ResolvedHandlerInfo = __dependency2__.ResolvedHandlerInfo;
  26934. var trigger = __dependency3__.trigger;
  26935. var slice = __dependency3__.slice;
  26936. var log = __dependency3__.log;
  26937. /**
  26938. @private
  26939. A Transition is a thennable (a promise-like object) that represents
  26940. an attempt to transition to another route. It can be aborted, either
  26941. explicitly via `abort` or by attempting another transition while a
  26942. previous one is still underway. An aborted transition can also
  26943. be `retry()`d later.
  26944. */
  26945. function Transition(router, intent, state, error) {
  26946. var transition = this;
  26947. this.state = state || router.state;
  26948. this.intent = intent;
  26949. this.router = router;
  26950. this.data = this.intent && this.intent.data || {};
  26951. this.resolvedModels = {};
  26952. this.queryParams = {};
  26953. if (error) {
  26954. this.promise = reject(error);
  26955. return;
  26956. }
  26957. if (state) {
  26958. this.params = state.params;
  26959. this.queryParams = state.queryParams;
  26960. var len = state.handlerInfos.length;
  26961. if (len) {
  26962. this.targetName = state.handlerInfos[state.handlerInfos.length-1].name;
  26963. }
  26964. for (var i = 0; i < len; ++i) {
  26965. var handlerInfo = state.handlerInfos[i];
  26966. if (!(handlerInfo instanceof ResolvedHandlerInfo)) {
  26967. break;
  26968. }
  26969. this.pivotHandler = handlerInfo.handler;
  26970. }
  26971. this.sequence = Transition.currentSequence++;
  26972. this.promise = state.resolve(router.async, checkForAbort, this)['catch'](function(result) {
  26973. if (result.wasAborted) {
  26974. throw logAbort(transition);
  26975. } else {
  26976. transition.trigger('error', result.error, transition, result.handlerWithError);
  26977. transition.abort();
  26978. throw result.error;
  26979. }
  26980. });
  26981. } else {
  26982. this.promise = resolve(this.state);
  26983. this.params = {};
  26984. }
  26985. function checkForAbort() {
  26986. if (transition.isAborted) {
  26987. return reject();
  26988. }
  26989. }
  26990. }
  26991. Transition.currentSequence = 0;
  26992. Transition.prototype = {
  26993. targetName: null,
  26994. urlMethod: 'update',
  26995. intent: null,
  26996. params: null,
  26997. pivotHandler: null,
  26998. resolveIndex: 0,
  26999. handlerInfos: null,
  27000. resolvedModels: null,
  27001. isActive: true,
  27002. state: null,
  27003. /**
  27004. @public
  27005. The Transition's internal promise. Calling `.then` on this property
  27006. is that same as calling `.then` on the Transition object itself, but
  27007. this property is exposed for when you want to pass around a
  27008. Transition's promise, but not the Transition object itself, since
  27009. Transition object can be externally `abort`ed, while the promise
  27010. cannot.
  27011. */
  27012. promise: null,
  27013. /**
  27014. @public
  27015. Custom state can be stored on a Transition's `data` object.
  27016. This can be useful for decorating a Transition within an earlier
  27017. hook and shared with a later hook. Properties set on `data` will
  27018. be copied to new transitions generated by calling `retry` on this
  27019. transition.
  27020. */
  27021. data: null,
  27022. /**
  27023. @public
  27024. A standard promise hook that resolves if the transition
  27025. succeeds and rejects if it fails/redirects/aborts.
  27026. Forwards to the internal `promise` property which you can
  27027. use in situations where you want to pass around a thennable,
  27028. but not the Transition itself.
  27029. @param {Function} success
  27030. @param {Function} failure
  27031. */
  27032. then: function(success, failure) {
  27033. return this.promise.then(success, failure);
  27034. },
  27035. /**
  27036. @public
  27037. Aborts the Transition. Note you can also implicitly abort a transition
  27038. by initiating another transition while a previous one is underway.
  27039. */
  27040. abort: function() {
  27041. if (this.isAborted) { return this; }
  27042. log(this.router, this.sequence, this.targetName + ": transition was aborted");
  27043. this.isAborted = true;
  27044. this.isActive = false;
  27045. this.router.activeTransition = null;
  27046. return this;
  27047. },
  27048. /**
  27049. @public
  27050. Retries a previously-aborted transition (making sure to abort the
  27051. transition if it's still active). Returns a new transition that
  27052. represents the new attempt to transition.
  27053. */
  27054. retry: function() {
  27055. // TODO: add tests for merged state retry()s
  27056. this.abort();
  27057. return this.router.transitionByIntent(this.intent, false);
  27058. },
  27059. /**
  27060. @public
  27061. Sets the URL-changing method to be employed at the end of a
  27062. successful transition. By default, a new Transition will just
  27063. use `updateURL`, but passing 'replace' to this method will
  27064. cause the URL to update using 'replaceWith' instead. Omitting
  27065. a parameter will disable the URL change, allowing for transitions
  27066. that don't update the URL at completion (this is also used for
  27067. handleURL, since the URL has already changed before the
  27068. transition took place).
  27069. @param {String} method the type of URL-changing method to use
  27070. at the end of a transition. Accepted values are 'replace',
  27071. falsy values, or any other non-falsy value (which is
  27072. interpreted as an updateURL transition).
  27073. @return {Transition} this transition
  27074. */
  27075. method: function(method) {
  27076. this.urlMethod = method;
  27077. return this;
  27078. },
  27079. /**
  27080. @public
  27081. Fires an event on the current list of resolved/resolving
  27082. handlers within this transition. Useful for firing events
  27083. on route hierarchies that haven't fully been entered yet.
  27084. Note: This method is also aliased as `send`
  27085. @param {Boolean} ignoreFailure the name of the event to fire
  27086. @param {String} name the name of the event to fire
  27087. */
  27088. trigger: function (ignoreFailure) {
  27089. var args = slice.call(arguments);
  27090. if (typeof ignoreFailure === 'boolean') {
  27091. args.shift();
  27092. } else {
  27093. // Throw errors on unhandled trigger events by default
  27094. ignoreFailure = false;
  27095. }
  27096. trigger(this.router, this.state.handlerInfos.slice(0, this.resolveIndex + 1), ignoreFailure, args);
  27097. },
  27098. /**
  27099. @public
  27100. Transitions are aborted and their promises rejected
  27101. when redirects occur; this method returns a promise
  27102. that will follow any redirects that occur and fulfill
  27103. with the value fulfilled by any redirecting transitions
  27104. that occur.
  27105. @return {Promise} a promise that fulfills with the same
  27106. value that the final redirecting transition fulfills with
  27107. */
  27108. followRedirects: function() {
  27109. var router = this.router;
  27110. return this.promise['catch'](function(reason) {
  27111. if (router.activeTransition) {
  27112. return router.activeTransition.followRedirects();
  27113. }
  27114. throw reason;
  27115. });
  27116. },
  27117. toString: function() {
  27118. return "Transition (sequence " + this.sequence + ")";
  27119. },
  27120. /**
  27121. @private
  27122. */
  27123. log: function(message) {
  27124. log(this.router, this.sequence, message);
  27125. }
  27126. };
  27127. // Alias 'trigger' as 'send'
  27128. Transition.prototype.send = Transition.prototype.trigger;
  27129. /**
  27130. @private
  27131. Logs and returns a TransitionAborted error.
  27132. */
  27133. function logAbort(transition) {
  27134. log(transition.router, transition.sequence, "detected abort.");
  27135. return new TransitionAborted();
  27136. }
  27137. function TransitionAborted(message) {
  27138. this.message = (message || "TransitionAborted");
  27139. this.name = "TransitionAborted";
  27140. }
  27141. __exports__.Transition = Transition;
  27142. __exports__.logAbort = logAbort;
  27143. __exports__.TransitionAborted = TransitionAborted;
  27144. });
  27145. define("router/utils",
  27146. ["exports"],
  27147. function(__exports__) {
  27148. "use strict";
  27149. var slice = Array.prototype.slice;
  27150. function merge(hash, other) {
  27151. for (var prop in other) {
  27152. if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; }
  27153. }
  27154. }
  27155. var oCreate = Object.create || function(proto) {
  27156. function F() {}
  27157. F.prototype = proto;
  27158. return new F();
  27159. };
  27160. /**
  27161. @private
  27162. Extracts query params from the end of an array
  27163. **/
  27164. function extractQueryParams(array) {
  27165. var len = (array && array.length), head, queryParams;
  27166. if(len && len > 0 && array[len - 1] && array[len - 1].hasOwnProperty('queryParams')) {
  27167. queryParams = array[len - 1].queryParams;
  27168. head = slice.call(array, 0, len - 1);
  27169. return [head, queryParams];
  27170. } else {
  27171. return [array, null];
  27172. }
  27173. }
  27174. /**
  27175. @private
  27176. */
  27177. function log(router, sequence, msg) {
  27178. if (!router.log) { return; }
  27179. if (arguments.length === 3) {
  27180. router.log("Transition #" + sequence + ": " + msg);
  27181. } else {
  27182. msg = sequence;
  27183. router.log(msg);
  27184. }
  27185. }
  27186. function bind(fn, context) {
  27187. var boundArgs = arguments;
  27188. return function(value) {
  27189. var args = slice.call(boundArgs, 2);
  27190. args.push(value);
  27191. return fn.apply(context, args);
  27192. };
  27193. }
  27194. function isParam(object) {
  27195. return (typeof object === "string" || object instanceof String || typeof object === "number" || object instanceof Number);
  27196. }
  27197. function forEach(array, callback) {
  27198. for (var i=0, l=array.length; i<l && false !== callback(array[i]); i++) { }
  27199. }
  27200. /**
  27201. @private
  27202. Serializes a handler using its custom `serialize` method or
  27203. by a default that looks up the expected property name from
  27204. the dynamic segment.
  27205. @param {Object} handler a router handler
  27206. @param {Object} model the model to be serialized for this handler
  27207. @param {Array[Object]} names the names array attached to an
  27208. handler object returned from router.recognizer.handlersFor()
  27209. */
  27210. function serialize(handler, model, names) {
  27211. var object = {};
  27212. if (isParam(model)) {
  27213. object[names[0]] = model;
  27214. return object;
  27215. }
  27216. // Use custom serialize if it exists.
  27217. if (handler.serialize) {
  27218. return handler.serialize(model, names);
  27219. }
  27220. if (names.length !== 1) { return; }
  27221. var name = names[0];
  27222. if (/_id$/.test(name)) {
  27223. object[name] = model.id;
  27224. } else {
  27225. object[name] = model;
  27226. }
  27227. return object;
  27228. }
  27229. function trigger(router, handlerInfos, ignoreFailure, args) {
  27230. if (router.triggerEvent) {
  27231. router.triggerEvent(handlerInfos, ignoreFailure, args);
  27232. return;
  27233. }
  27234. var name = args.shift();
  27235. if (!handlerInfos) {
  27236. if (ignoreFailure) { return; }
  27237. throw new Error("Could not trigger event '" + name + "'. There are no active handlers");
  27238. }
  27239. var eventWasHandled = false;
  27240. for (var i=handlerInfos.length-1; i>=0; i--) {
  27241. var handlerInfo = handlerInfos[i],
  27242. handler = handlerInfo.handler;
  27243. if (handler.events && handler.events[name]) {
  27244. if (handler.events[name].apply(handler, args) === true) {
  27245. eventWasHandled = true;
  27246. } else {
  27247. return;
  27248. }
  27249. }
  27250. }
  27251. if (!eventWasHandled && !ignoreFailure) {
  27252. throw new Error("Nothing handled the event '" + name + "'.");
  27253. }
  27254. }
  27255. function getChangelist(oldObject, newObject) {
  27256. var key;
  27257. var results = {
  27258. all: {},
  27259. changed: {},
  27260. removed: {}
  27261. };
  27262. merge(results.all, newObject);
  27263. var didChange = false;
  27264. // Calculate removals
  27265. for (key in oldObject) {
  27266. if (oldObject.hasOwnProperty(key)) {
  27267. if (!newObject.hasOwnProperty(key)) {
  27268. didChange = true;
  27269. results.removed[key] = oldObject[key];
  27270. }
  27271. }
  27272. }
  27273. // Calculate changes
  27274. for (key in newObject) {
  27275. if (newObject.hasOwnProperty(key)) {
  27276. if (oldObject[key] !== newObject[key]) {
  27277. results.changed[key] = newObject[key];
  27278. didChange = true;
  27279. }
  27280. }
  27281. }
  27282. return didChange && results;
  27283. }
  27284. __exports__.trigger = trigger;
  27285. __exports__.log = log;
  27286. __exports__.oCreate = oCreate;
  27287. __exports__.merge = merge;
  27288. __exports__.extractQueryParams = extractQueryParams;
  27289. __exports__.bind = bind;
  27290. __exports__.isParam = isParam;
  27291. __exports__.forEach = forEach;
  27292. __exports__.slice = slice;
  27293. __exports__.serialize = serialize;
  27294. __exports__.getChangelist = getChangelist;
  27295. });
  27296. define("router",
  27297. ["./router/router","exports"],
  27298. function(__dependency1__, __exports__) {
  27299. "use strict";
  27300. var Router = __dependency1__.Router;
  27301. __exports__.Router = Router;
  27302. });
  27303. })();
  27304. (function() {
  27305. /**
  27306. @module ember
  27307. @submodule ember-routing
  27308. */
  27309. function DSL(name) {
  27310. this.parent = name;
  27311. this.matches = [];
  27312. }
  27313. DSL.prototype = {
  27314. resource: function(name, options, callback) {
  27315. if (arguments.length === 2 && typeof options === 'function') {
  27316. callback = options;
  27317. options = {};
  27318. }
  27319. if (arguments.length === 1) {
  27320. options = {};
  27321. }
  27322. if (typeof options.path !== 'string') {
  27323. options.path = "/" + name;
  27324. }
  27325. if (callback) {
  27326. var dsl = new DSL(name);
  27327. route(dsl, 'loading');
  27328. route(dsl, 'error', { path: "/_unused_dummy_error_path_route_" + name + "/:error" });
  27329. callback.call(dsl);
  27330. this.push(options.path, name, dsl.generate(), options.queryParams);
  27331. } else {
  27332. this.push(options.path, name, null, options.queryParams);
  27333. }
  27334. },
  27335. push: function(url, name, callback, queryParams) {
  27336. var parts = name.split('.');
  27337. if (url === "" || url === "/" || parts[parts.length-1] === "index") { this.explicitIndex = true; }
  27338. this.matches.push([url, name, callback, queryParams]);
  27339. },
  27340. route: function(name, options) {
  27341. route(this, name, options);
  27342. },
  27343. generate: function() {
  27344. var dslMatches = this.matches;
  27345. if (!this.explicitIndex) {
  27346. this.route("index", { path: "/" });
  27347. }
  27348. return function(match) {
  27349. for (var i=0, l=dslMatches.length; i<l; i++) {
  27350. var dslMatch = dslMatches[i];
  27351. var matchObj = match(dslMatch[0]).to(dslMatch[1], dslMatch[2]);
  27352. }
  27353. };
  27354. }
  27355. };
  27356. function route(dsl, name, options) {
  27357. Ember.assert("You must use `this.resource` to nest", typeof options !== 'function');
  27358. options = options || {};
  27359. if (typeof options.path !== 'string') {
  27360. options.path = "/" + name;
  27361. }
  27362. if (dsl.parent && dsl.parent !== 'application') {
  27363. name = dsl.parent + "." + name;
  27364. }
  27365. dsl.push(options.path, name, null, options.queryParams);
  27366. }
  27367. DSL.map = function(callback) {
  27368. var dsl = new DSL();
  27369. callback.call(dsl);
  27370. return dsl;
  27371. };
  27372. Ember.RouterDSL = DSL;
  27373. })();
  27374. (function() {
  27375. var get = Ember.get;
  27376. /**
  27377. @module ember
  27378. @submodule ember-routing
  27379. */
  27380. /**
  27381. Finds a controller instance.
  27382. @for Ember
  27383. @method controllerFor
  27384. @private
  27385. */
  27386. Ember.controllerFor = function(container, controllerName, lookupOptions) {
  27387. return container.lookup('controller:' + controllerName, lookupOptions);
  27388. };
  27389. /**
  27390. Generates a controller factory
  27391. The type of the generated controller factory is derived
  27392. from the context. If the context is an array an array controller
  27393. is generated, if an object, an object controller otherwise, a basic
  27394. controller is generated.
  27395. You can customize your generated controllers by defining
  27396. `App.ObjectController` or `App.ArrayController`.
  27397. @for Ember
  27398. @method generateControllerFactory
  27399. @private
  27400. */
  27401. Ember.generateControllerFactory = function(container, controllerName, context) {
  27402. var Factory, fullName, instance, name, factoryName, controllerType;
  27403. if (context && Ember.isArray(context)) {
  27404. controllerType = 'array';
  27405. } else if (context) {
  27406. controllerType = 'object';
  27407. } else {
  27408. controllerType = 'basic';
  27409. }
  27410. factoryName = 'controller:' + controllerType;
  27411. Factory = container.lookupFactory(factoryName).extend({
  27412. isGenerated: true,
  27413. toString: function() {
  27414. return "(generated " + controllerName + " controller)";
  27415. }
  27416. });
  27417. fullName = 'controller:' + controllerName;
  27418. container.register(fullName, Factory);
  27419. return Factory;
  27420. };
  27421. /**
  27422. Generates and instantiates a controller.
  27423. The type of the generated controller factory is derived
  27424. from the context. If the context is an array an array controller
  27425. is generated, if an object, an object controller otherwise, a basic
  27426. controller is generated.
  27427. @for Ember
  27428. @method generateController
  27429. @private
  27430. */
  27431. Ember.generateController = function(container, controllerName, context) {
  27432. Ember.generateControllerFactory(container, controllerName, context);
  27433. var fullName = 'controller:' + controllerName;
  27434. var instance = container.lookup(fullName);
  27435. if (get(instance, 'namespace.LOG_ACTIVE_GENERATION')) {
  27436. Ember.Logger.info("generated -> " + fullName, { fullName: fullName });
  27437. }
  27438. return instance;
  27439. };
  27440. })();
  27441. (function() {
  27442. /**
  27443. @module ember
  27444. @submodule ember-routing
  27445. */
  27446. var routerJsModule = requireModule("router");
  27447. var Router = routerJsModule.Router;
  27448. var Transition = routerJsModule.Transition;
  27449. var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
  27450. var defineProperty = Ember.defineProperty;
  27451. var slice = Array.prototype.slice;
  27452. var forEach = Ember.EnumerableUtils.forEach;
  27453. var DefaultView = Ember._MetamorphView;
  27454. /**
  27455. The `Ember.Router` class manages the application state and URLs. Refer to
  27456. the [routing guide](http://emberjs.com/guides/routing/) for documentation.
  27457. @class Router
  27458. @namespace Ember
  27459. @extends Ember.Object
  27460. */
  27461. Ember.Router = Ember.Object.extend(Ember.Evented, {
  27462. /**
  27463. The `location` property determines the type of URL's that your
  27464. application will use.
  27465. The following location types are currently available:
  27466. * `hash`
  27467. * `history`
  27468. * `none`
  27469. @property location
  27470. @default 'hash'
  27471. @see {Ember.Location}
  27472. */
  27473. location: 'hash',
  27474. init: function() {
  27475. this.router = this.constructor.router || this.constructor.map(Ember.K);
  27476. this._activeViews = {};
  27477. this._setupLocation();
  27478. if (get(this, 'namespace.LOG_TRANSITIONS_INTERNAL')) {
  27479. this.router.log = Ember.Logger.debug;
  27480. }
  27481. },
  27482. /**
  27483. Represents the current URL.
  27484. @method url
  27485. @returns {String} The current URL.
  27486. */
  27487. url: Ember.computed(function() {
  27488. return get(this, 'location').getURL();
  27489. }),
  27490. /**
  27491. Initializes the current router instance and sets up the change handling
  27492. event listeners used by the instances `location` implementation.
  27493. A property named `initialURL` will be used to determine the initial URL.
  27494. If no value is found `/` will be used.
  27495. @method startRouting
  27496. @private
  27497. */
  27498. startRouting: function() {
  27499. this.router = this.router || this.constructor.map(Ember.K);
  27500. var router = this.router,
  27501. location = get(this, 'location'),
  27502. container = this.container,
  27503. self = this,
  27504. initialURL = get(this, 'initialURL');
  27505. this._setupRouter(router, location);
  27506. container.register('view:default', DefaultView);
  27507. container.register('view:toplevel', Ember.View.extend());
  27508. location.onUpdateURL(function(url) {
  27509. self.handleURL(url);
  27510. });
  27511. if (typeof initialURL === "undefined") {
  27512. initialURL = location.getURL();
  27513. }
  27514. this.handleURL(initialURL);
  27515. },
  27516. /**
  27517. Handles updating the paths and notifying any listeners of the URL
  27518. change.
  27519. Triggers the router level `didTransition` hook.
  27520. @method didTransition
  27521. @private
  27522. */
  27523. didTransition: function(infos) {
  27524. updatePaths(this);
  27525. this._cancelLoadingEvent();
  27526. this.notifyPropertyChange('url');
  27527. // Put this in the runloop so url will be accurate. Seems
  27528. // less surprising than didTransition being out of sync.
  27529. Ember.run.once(this, this.trigger, 'didTransition');
  27530. if (get(this, 'namespace').LOG_TRANSITIONS) {
  27531. Ember.Logger.log("Transitioned into '" + Ember.Router._routePath(infos) + "'");
  27532. }
  27533. },
  27534. handleURL: function(url) {
  27535. return this._doTransition('handleURL', [url]);
  27536. },
  27537. transitionTo: function() {
  27538. return this._doTransition('transitionTo', arguments);
  27539. },
  27540. intermediateTransitionTo: function() {
  27541. this.router.intermediateTransitionTo.apply(this.router, arguments);
  27542. updatePaths(this);
  27543. var infos = this.router.currentHandlerInfos;
  27544. if (get(this, 'namespace').LOG_TRANSITIONS) {
  27545. Ember.Logger.log("Intermediate-transitioned into '" + Ember.Router._routePath(infos) + "'");
  27546. }
  27547. },
  27548. replaceWith: function() {
  27549. return this._doTransition('replaceWith', arguments);
  27550. },
  27551. generate: function() {
  27552. var url = this.router.generate.apply(this.router, arguments);
  27553. return this.location.formatURL(url);
  27554. },
  27555. /**
  27556. Determines if the supplied route is currently active.
  27557. @method isActive
  27558. @param routeName
  27559. @returns {Boolean}
  27560. @private
  27561. */
  27562. isActive: function(routeName) {
  27563. var router = this.router;
  27564. return router.isActive.apply(router, arguments);
  27565. },
  27566. send: function(name, context) {
  27567. this.router.trigger.apply(this.router, arguments);
  27568. },
  27569. /**
  27570. Does this router instance have the given route.
  27571. @method hasRoute
  27572. @returns {Boolean}
  27573. @private
  27574. */
  27575. hasRoute: function(route) {
  27576. return this.router.hasRoute(route);
  27577. },
  27578. /**
  27579. Resets the state of the router by clearing the current route
  27580. handlers and deactivating them.
  27581. @private
  27582. @method reset
  27583. */
  27584. reset: function() {
  27585. this.router.reset();
  27586. },
  27587. _lookupActiveView: function(templateName) {
  27588. var active = this._activeViews[templateName];
  27589. return active && active[0];
  27590. },
  27591. _connectActiveView: function(templateName, view) {
  27592. var existing = this._activeViews[templateName];
  27593. if (existing) {
  27594. existing[0].off('willDestroyElement', this, existing[1]);
  27595. }
  27596. var disconnect = function() {
  27597. delete this._activeViews[templateName];
  27598. };
  27599. this._activeViews[templateName] = [view, disconnect];
  27600. view.one('willDestroyElement', this, disconnect);
  27601. },
  27602. _setupLocation: function() {
  27603. var location = get(this, 'location'),
  27604. rootURL = get(this, 'rootURL');
  27605. if ('string' === typeof location && this.container) {
  27606. var resolvedLocation = this.container.lookup('location:' + location);
  27607. if ('undefined' !== typeof resolvedLocation) {
  27608. location = set(this, 'location', resolvedLocation);
  27609. } else {
  27610. // Allow for deprecated registration of custom location API's
  27611. var options = {implementation: location};
  27612. location = set(this, 'location', Ember.Location.create(options));
  27613. }
  27614. }
  27615. if (typeof rootURL === 'string') {
  27616. location.rootURL = rootURL;
  27617. }
  27618. // ensure that initState is called AFTER the rootURL is set on
  27619. // the location instance
  27620. if (typeof location.initState === 'function') { location.initState(); }
  27621. },
  27622. _getHandlerFunction: function() {
  27623. var seen = {}, container = this.container,
  27624. DefaultRoute = container.lookupFactory('route:basic'),
  27625. self = this;
  27626. return function(name) {
  27627. var routeName = 'route:' + name,
  27628. handler = container.lookup(routeName);
  27629. if (seen[name]) { return handler; }
  27630. seen[name] = true;
  27631. if (!handler) {
  27632. container.register(routeName, DefaultRoute.extend());
  27633. handler = container.lookup(routeName);
  27634. if (get(self, 'namespace.LOG_ACTIVE_GENERATION')) {
  27635. Ember.Logger.info("generated -> " + routeName, { fullName: routeName });
  27636. }
  27637. }
  27638. handler.routeName = name;
  27639. return handler;
  27640. };
  27641. },
  27642. _setupRouter: function(router, location) {
  27643. var lastURL, emberRouter = this;
  27644. router.getHandler = this._getHandlerFunction();
  27645. var doUpdateURL = function() {
  27646. location.setURL(lastURL);
  27647. };
  27648. router.updateURL = function(path) {
  27649. lastURL = path;
  27650. Ember.run.once(doUpdateURL);
  27651. };
  27652. if (location.replaceURL) {
  27653. var doReplaceURL = function() {
  27654. location.replaceURL(lastURL);
  27655. };
  27656. router.replaceURL = function(path) {
  27657. lastURL = path;
  27658. Ember.run.once(doReplaceURL);
  27659. };
  27660. }
  27661. router.didTransition = function(infos) {
  27662. emberRouter.didTransition(infos);
  27663. };
  27664. },
  27665. _doTransition: function(method, args) {
  27666. // Normalize blank route to root URL.
  27667. args = slice.call(args);
  27668. args[0] = args[0] || '/';
  27669. var passedName = args[0], name, self = this,
  27670. isQueryParamsOnly = false, queryParams;
  27671. if (!isQueryParamsOnly && passedName.charAt(0) !== '/') {
  27672. if (!this.router.hasRoute(passedName)) {
  27673. name = args[0] = passedName + '.index';
  27674. } else {
  27675. name = passedName;
  27676. }
  27677. Ember.assert("The route " + passedName + " was not found", this.router.hasRoute(name));
  27678. }
  27679. if (queryParams) {
  27680. // router.js expects queryParams to be passed in in
  27681. // their final serialized form, so we need to translate.
  27682. if (!name) {
  27683. // Need to determine destination route name.
  27684. var handlerInfos = this.router.activeTransition ?
  27685. this.router.activeTransition.state.handlerInfos :
  27686. this.router.state.handlerInfos;
  27687. name = handlerInfos[handlerInfos.length - 1].name;
  27688. args.unshift(name);
  27689. }
  27690. var qpMappings = this._queryParamNamesFor(name);
  27691. Ember.Router._translateQueryParams(queryParams, qpMappings.translations, name);
  27692. for (var key in queryParams) {
  27693. if (key in qpMappings.queryParams) {
  27694. var value = queryParams[key];
  27695. delete queryParams[key];
  27696. queryParams[qpMappings.queryParams[key]] = value;
  27697. }
  27698. }
  27699. }
  27700. var transitionPromise = this.router[method].apply(this.router, args);
  27701. transitionPromise.then(null, function(error) {
  27702. if (error.name === "UnrecognizedURLError") {
  27703. Ember.assert("The URL '" + error.message + "' did not match any routes in your application");
  27704. }
  27705. }, 'Ember: Check for Router unrecognized URL error');
  27706. // We want to return the configurable promise object
  27707. // so that callers of this function can use `.method()` on it,
  27708. // which obviously doesn't exist for normal RSVP promises.
  27709. return transitionPromise;
  27710. },
  27711. _scheduleLoadingEvent: function(transition, originRoute) {
  27712. this._cancelLoadingEvent();
  27713. this._loadingStateTimer = Ember.run.scheduleOnce('routerTransitions', this, '_fireLoadingEvent', transition, originRoute);
  27714. },
  27715. _fireLoadingEvent: function(transition, originRoute) {
  27716. if (!this.router.activeTransition) {
  27717. // Don't fire an event if we've since moved on from
  27718. // the transition that put us in a loading state.
  27719. return;
  27720. }
  27721. transition.trigger(true, 'loading', transition, originRoute);
  27722. },
  27723. _cancelLoadingEvent: function () {
  27724. if (this._loadingStateTimer) {
  27725. Ember.run.cancel(this._loadingStateTimer);
  27726. }
  27727. this._loadingStateTimer = null;
  27728. },
  27729. _queryParamNamesFor: function(routeName) {
  27730. // TODO: add caching
  27731. routeName = this.router.hasRoute(routeName) ? routeName : routeName + '.index';
  27732. var handlerInfos = this.router.recognizer.handlersFor(routeName);
  27733. var result = { queryParams: Ember.create(null), translations: Ember.create(null) };
  27734. var routerjs = this.router;
  27735. forEach(handlerInfos, function(recogHandler) {
  27736. var route = routerjs.getHandler(recogHandler.handler);
  27737. getQueryParamsForRoute(route, result);
  27738. });
  27739. return result;
  27740. },
  27741. _queryParamNamesForSingle: function(routeName) {
  27742. // TODO: add caching
  27743. var result = { queryParams: Ember.create(null), translations: Ember.create(null) };
  27744. var route = this.router.getHandler(routeName);
  27745. getQueryParamsForRoute(route, result);
  27746. return result;
  27747. },
  27748. /**
  27749. @private
  27750. Utility function for fetching all the current query params
  27751. values from a controller.
  27752. */
  27753. _queryParamOverrides: function(results, queryParams, callback) {
  27754. for (var name in queryParams) {
  27755. var parts = name.split(':');
  27756. var controller = this.container.lookup('controller:' + parts[0]);
  27757. Ember.assert(fmt("Could not lookup controller '%@' while setting up query params", [controller]), controller);
  27758. // Now assign the final URL-serialized key-value pair,
  27759. // e.g. "foo[propName]": "value"
  27760. results[queryParams[name]] = get(controller, parts[1]);
  27761. if (callback) {
  27762. // Give callback a chance to override.
  27763. callback(name, queryParams[name], name);
  27764. }
  27765. }
  27766. }
  27767. });
  27768. /**
  27769. @private
  27770. */
  27771. function getQueryParamsForRoute(route, result) {
  27772. var controllerName = route.controllerName || route.routeName,
  27773. controller = route.controllerFor(controllerName, true);
  27774. if (controller && controller.queryParams) {
  27775. forEach(controller.queryParams, function(propName) {
  27776. var parts = propName.split(':');
  27777. var urlKeyName;
  27778. if (parts.length > 1) {
  27779. urlKeyName = parts[1];
  27780. } else {
  27781. // TODO: use _queryParamScope here?
  27782. if (controllerName !== 'application') {
  27783. urlKeyName = controllerName + '[' + propName + ']';
  27784. } else {
  27785. urlKeyName = propName;
  27786. }
  27787. }
  27788. var controllerFullname = controllerName + ':' + propName;
  27789. result.queryParams[controllerFullname] = urlKeyName;
  27790. result.translations[parts[0]] = controllerFullname;
  27791. });
  27792. }
  27793. }
  27794. /**
  27795. Helper function for iterating root-ward, starting
  27796. from (but not including) the provided `originRoute`.
  27797. Returns true if the last callback fired requested
  27798. to bubble upward.
  27799. @private
  27800. */
  27801. function forEachRouteAbove(originRoute, transition, callback) {
  27802. var handlerInfos = transition.state.handlerInfos,
  27803. originRouteFound = false;
  27804. for (var i = handlerInfos.length - 1; i >= 0; --i) {
  27805. var handlerInfo = handlerInfos[i],
  27806. route = handlerInfo.handler;
  27807. if (!originRouteFound) {
  27808. if (originRoute === route) {
  27809. originRouteFound = true;
  27810. }
  27811. continue;
  27812. }
  27813. if (callback(route, handlerInfos[i + 1].handler) !== true) {
  27814. return false;
  27815. }
  27816. }
  27817. return true;
  27818. }
  27819. // These get invoked when an action bubbles above ApplicationRoute
  27820. // and are not meant to be overridable.
  27821. var defaultActionHandlers = {
  27822. willResolveModel: function(transition, originRoute) {
  27823. originRoute.router._scheduleLoadingEvent(transition, originRoute);
  27824. },
  27825. error: function(error, transition, originRoute) {
  27826. // Attempt to find an appropriate error substate to enter.
  27827. var router = originRoute.router;
  27828. var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) {
  27829. var childErrorRouteName = findChildRouteName(route, childRoute, 'error');
  27830. if (childErrorRouteName) {
  27831. router.intermediateTransitionTo(childErrorRouteName, error);
  27832. return;
  27833. }
  27834. return true;
  27835. });
  27836. if (tryTopLevel) {
  27837. // Check for top-level error state to enter.
  27838. if (routeHasBeenDefined(originRoute.router, 'application_error')) {
  27839. router.intermediateTransitionTo('application_error', error);
  27840. return;
  27841. }
  27842. } else {
  27843. // Don't fire an assertion if we found an error substate.
  27844. return;
  27845. }
  27846. Ember.Logger.error('Error while loading route: ' + error.stack);
  27847. },
  27848. loading: function(transition, originRoute) {
  27849. // Attempt to find an appropriate loading substate to enter.
  27850. var router = originRoute.router;
  27851. var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) {
  27852. var childLoadingRouteName = findChildRouteName(route, childRoute, 'loading');
  27853. if (childLoadingRouteName) {
  27854. router.intermediateTransitionTo(childLoadingRouteName);
  27855. return;
  27856. }
  27857. // Don't bubble above pivot route.
  27858. if (transition.pivotHandler !== route) {
  27859. return true;
  27860. }
  27861. });
  27862. if (tryTopLevel) {
  27863. // Check for top-level loading state to enter.
  27864. if (routeHasBeenDefined(originRoute.router, 'application_loading')) {
  27865. router.intermediateTransitionTo('application_loading');
  27866. return;
  27867. }
  27868. }
  27869. }
  27870. };
  27871. function findChildRouteName(parentRoute, originatingChildRoute, name) {
  27872. var router = parentRoute.router,
  27873. childName,
  27874. targetChildRouteName = originatingChildRoute.routeName.split('.').pop(),
  27875. namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.';
  27876. // Second, try general loading state, e.g. 'loading'
  27877. childName = namespace + name;
  27878. if (routeHasBeenDefined(router, childName)) {
  27879. return childName;
  27880. }
  27881. }
  27882. function routeHasBeenDefined(router, name) {
  27883. var container = router.container;
  27884. return router.hasRoute(name) &&
  27885. (container.has('template:' + name) || container.has('route:' + name));
  27886. }
  27887. function triggerEvent(handlerInfos, ignoreFailure, args) {
  27888. var name = args.shift();
  27889. if (!handlerInfos) {
  27890. if (ignoreFailure) { return; }
  27891. throw new Ember.Error("Can't trigger action '" + name + "' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks.");
  27892. }
  27893. var eventWasHandled = false;
  27894. for (var i = handlerInfos.length - 1; i >= 0; i--) {
  27895. var handlerInfo = handlerInfos[i],
  27896. handler = handlerInfo.handler;
  27897. if (handler._actions && handler._actions[name]) {
  27898. if (handler._actions[name].apply(handler, args) === true) {
  27899. eventWasHandled = true;
  27900. } else {
  27901. return;
  27902. }
  27903. }
  27904. }
  27905. if (defaultActionHandlers[name]) {
  27906. defaultActionHandlers[name].apply(null, args);
  27907. return;
  27908. }
  27909. if (!eventWasHandled && !ignoreFailure) {
  27910. throw new Ember.Error("Nothing handled the action '" + name + "'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.");
  27911. }
  27912. }
  27913. function updatePaths(router) {
  27914. var appController = router.container.lookup('controller:application');
  27915. if (!appController) {
  27916. // appController might not exist when top-level loading/error
  27917. // substates have been entered since ApplicationRoute hasn't
  27918. // actually been entered at that point.
  27919. return;
  27920. }
  27921. var infos = router.router.currentHandlerInfos,
  27922. path = Ember.Router._routePath(infos);
  27923. if (!('currentPath' in appController)) {
  27924. defineProperty(appController, 'currentPath');
  27925. }
  27926. set(appController, 'currentPath', path);
  27927. if (!('currentRouteName' in appController)) {
  27928. defineProperty(appController, 'currentRouteName');
  27929. }
  27930. set(appController, 'currentRouteName', infos[infos.length - 1].name);
  27931. }
  27932. Ember.Router.reopenClass({
  27933. router: null,
  27934. map: function(callback) {
  27935. var router = this.router;
  27936. if (!router) {
  27937. router = new Router();
  27938. router.callbacks = [];
  27939. router.triggerEvent = triggerEvent;
  27940. this.reopenClass({ router: router });
  27941. }
  27942. var dsl = Ember.RouterDSL.map(function() {
  27943. this.resource('application', { path: "/" }, function() {
  27944. for (var i=0; i < router.callbacks.length; i++) {
  27945. router.callbacks[i].call(this);
  27946. }
  27947. callback.call(this);
  27948. });
  27949. });
  27950. router.callbacks.push(callback);
  27951. router.map(dsl.generate());
  27952. return router;
  27953. },
  27954. _routePath: function(handlerInfos) {
  27955. var path = [];
  27956. // We have to handle coalescing resource names that
  27957. // are prefixed with their parent's names, e.g.
  27958. // ['foo', 'foo.bar.baz'] => 'foo.bar.baz', not 'foo.foo.bar.baz'
  27959. function intersectionMatches(a1, a2) {
  27960. for (var i = 0, len = a1.length; i < len; ++i) {
  27961. if (a1[i] !== a2[i]) {
  27962. return false;
  27963. }
  27964. }
  27965. return true;
  27966. }
  27967. for (var i=1, l=handlerInfos.length; i<l; i++) {
  27968. var name = handlerInfos[i].name,
  27969. nameParts = name.split("."),
  27970. oldNameParts = slice.call(path);
  27971. while (oldNameParts.length) {
  27972. if (intersectionMatches(oldNameParts, nameParts)) {
  27973. break;
  27974. }
  27975. oldNameParts.shift();
  27976. }
  27977. path.push.apply(path, nameParts.slice(oldNameParts.length));
  27978. }
  27979. return path.join(".");
  27980. },
  27981. _translateQueryParams: function(queryParams, translations, routeName) {
  27982. for (var name in queryParams) {
  27983. if (!queryParams.hasOwnProperty(name)) { continue; }
  27984. if (name in translations) {
  27985. queryParams[translations[name]] = queryParams[name];
  27986. delete queryParams[name];
  27987. } else {
  27988. Ember.assert(fmt("You supplied an unknown query param controller property '%@' for route '%@'. Only the following query param properties can be set for this route: %@", [name, routeName, Ember.keys(translations)]), name in queryParams);
  27989. }
  27990. }
  27991. }
  27992. });
  27993. })();
  27994. (function() {
  27995. /**
  27996. @module ember
  27997. @submodule ember-routing
  27998. */
  27999. var get = Ember.get, set = Ember.set,
  28000. getProperties = Ember.getProperties,
  28001. classify = Ember.String.classify,
  28002. fmt = Ember.String.fmt,
  28003. a_forEach = Ember.EnumerableUtils.forEach,
  28004. a_replace = Ember.EnumerableUtils.replace;
  28005. /**
  28006. The `Ember.Route` class is used to define individual routes. Refer to
  28007. the [routing guide](http://emberjs.com/guides/routing/) for documentation.
  28008. @class Route
  28009. @namespace Ember
  28010. @extends Ember.Object
  28011. @uses Ember.ActionHandler
  28012. */
  28013. Ember.Route = Ember.Object.extend(Ember.ActionHandler, {
  28014. /**
  28015. @private
  28016. @method exit
  28017. */
  28018. exit: function() {
  28019. this.deactivate();
  28020. this.teardownViews();
  28021. },
  28022. /**
  28023. @private
  28024. @method enter
  28025. */
  28026. enter: function() {
  28027. this.activate();
  28028. },
  28029. /**
  28030. The name of the view to use by default when rendering this routes template.
  28031. When rendering a template, the route will, by default, determine the
  28032. template and view to use from the name of the route itself. If you need to
  28033. define a specific view, set this property.
  28034. This is useful when multiple routes would benefit from using the same view
  28035. because it doesn't require a custom `renderTemplate` method. For example,
  28036. the following routes will all render using the `App.PostsListView` view:
  28037. ```js
  28038. var PostsList = Ember.Route.extend({
  28039. viewName: 'postsList',
  28040. });
  28041. App.PostsIndexRoute = PostsList.extend();
  28042. App.PostsArchivedRoute = PostsList.extend();
  28043. ```
  28044. @property viewName
  28045. @type String
  28046. @default null
  28047. */
  28048. viewName: null,
  28049. /**
  28050. The name of the template to use by default when rendering this routes
  28051. template.
  28052. This is similar with `viewName`, but is useful when you just want a custom
  28053. template without a view.
  28054. ```js
  28055. var PostsList = Ember.Route.extend({
  28056. templateName: 'posts/list'
  28057. });
  28058. App.PostsIndexRoute = PostsList.extend();
  28059. App.PostsArchivedRoute = PostsList.extend();
  28060. ```
  28061. @property templateName
  28062. @type String
  28063. @default null
  28064. */
  28065. templateName: null,
  28066. /**
  28067. The name of the controller to associate with this route.
  28068. By default, Ember will lookup a route's controller that matches the name
  28069. of the route (i.e. `App.PostController` for `App.PostRoute`). However,
  28070. if you would like to define a specific controller to use, you can do so
  28071. using this property.
  28072. This is useful in many ways, as the controller specified will be:
  28073. * passed to the `setupController` method.
  28074. * used as the controller for the view being rendered by the route.
  28075. * returned from a call to `controllerFor` for the route.
  28076. @property controllerName
  28077. @type String
  28078. @default null
  28079. */
  28080. controllerName: null,
  28081. /**
  28082. The collection of functions, keyed by name, available on this route as
  28083. action targets.
  28084. These functions will be invoked when a matching `{{action}}` is triggered
  28085. from within a template and the application's current route is this route.
  28086. Actions can also be invoked from other parts of your application via `Route#send`
  28087. or `Controller#send`.
  28088. The `actions` hash will inherit action handlers from
  28089. the `actions` hash defined on extended Route parent classes
  28090. or mixins rather than just replace the entire hash, e.g.:
  28091. ```js
  28092. App.CanDisplayBanner = Ember.Mixin.create({
  28093. actions: {
  28094. displayBanner: function(msg) {
  28095. // ...
  28096. }
  28097. }
  28098. });
  28099. App.WelcomeRoute = Ember.Route.extend(App.CanDisplayBanner, {
  28100. actions: {
  28101. playMusic: function() {
  28102. // ...
  28103. }
  28104. }
  28105. });
  28106. // `WelcomeRoute`, when active, will be able to respond
  28107. // to both actions, since the actions hash is merged rather
  28108. // then replaced when extending mixins / parent classes.
  28109. this.send('displayBanner');
  28110. this.send('playMusic');
  28111. ```
  28112. Within a route's action handler, the value of the `this` context
  28113. is the Route object:
  28114. ```js
  28115. App.SongRoute = Ember.Route.extend({
  28116. actions: {
  28117. myAction: function() {
  28118. this.controllerFor("song");
  28119. this.transitionTo("other.route");
  28120. ...
  28121. }
  28122. }
  28123. });
  28124. ```
  28125. It is also possible to call `this._super()` from within an
  28126. action handler if it overrides a handler defined on a parent
  28127. class or mixin:
  28128. Take for example the following routes:
  28129. ```js
  28130. App.DebugRoute = Ember.Mixin.create({
  28131. actions: {
  28132. debugRouteInformation: function() {
  28133. console.debug("trololo");
  28134. }
  28135. }
  28136. });
  28137. App.AnnoyingDebugRoute = Ember.Route.extend(App.DebugRoute, {
  28138. actions: {
  28139. debugRouteInformation: function() {
  28140. // also call the debugRouteInformation of mixed in App.DebugRoute
  28141. this._super();
  28142. // show additional annoyance
  28143. window.alert(...);
  28144. }
  28145. }
  28146. });
  28147. ```
  28148. ## Bubbling
  28149. By default, an action will stop bubbling once a handler defined
  28150. on the `actions` hash handles it. To continue bubbling the action,
  28151. you must return `true` from the handler:
  28152. ```js
  28153. App.Router.map(function() {
  28154. this.resource("album", function() {
  28155. this.route("song");
  28156. });
  28157. });
  28158. App.AlbumRoute = Ember.Route.extend({
  28159. actions: {
  28160. startPlaying: function() {
  28161. }
  28162. }
  28163. });
  28164. App.AlbumSongRoute = Ember.Route.extend({
  28165. actions: {
  28166. startPlaying: function() {
  28167. // ...
  28168. if (actionShouldAlsoBeTriggeredOnParentRoute) {
  28169. return true;
  28170. }
  28171. }
  28172. }
  28173. });
  28174. ```
  28175. ## Built-in actions
  28176. There are a few built-in actions pertaining to transitions that you
  28177. can use to customize transition behavior: `willTransition` and
  28178. `error`.
  28179. ### `willTransition`
  28180. The `willTransition` action is fired at the beginning of any
  28181. attempted transition with a `Transition` object as the sole
  28182. argument. This action can be used for aborting, redirecting,
  28183. or decorating the transition from the currently active routes.
  28184. A good example is preventing navigation when a form is
  28185. half-filled out:
  28186. ```js
  28187. App.ContactFormRoute = Ember.Route.extend({
  28188. actions: {
  28189. willTransition: function(transition) {
  28190. if (this.controller.get('userHasEnteredData')) {
  28191. this.controller.displayNavigationConfirm();
  28192. transition.abort();
  28193. }
  28194. }
  28195. }
  28196. });
  28197. ```
  28198. You can also redirect elsewhere by calling
  28199. `this.transitionTo('elsewhere')` from within `willTransition`.
  28200. Note that `willTransition` will not be fired for the
  28201. redirecting `transitionTo`, since `willTransition` doesn't
  28202. fire when there is already a transition underway. If you want
  28203. subsequent `willTransition` actions to fire for the redirecting
  28204. transition, you must first explicitly call
  28205. `transition.abort()`.
  28206. ### `error`
  28207. When attempting to transition into a route, any of the hooks
  28208. may return a promise that rejects, at which point an `error`
  28209. action will be fired on the partially-entered routes, allowing
  28210. for per-route error handling logic, or shared error handling
  28211. logic defined on a parent route.
  28212. Here is an example of an error handler that will be invoked
  28213. for rejected promises from the various hooks on the route,
  28214. as well as any unhandled errors from child routes:
  28215. ```js
  28216. App.AdminRoute = Ember.Route.extend({
  28217. beforeModel: function() {
  28218. return Ember.RSVP.reject("bad things!");
  28219. },
  28220. actions: {
  28221. error: function(error, transition) {
  28222. // Assuming we got here due to the error in `beforeModel`,
  28223. // we can expect that error === "bad things!",
  28224. // but a promise model rejecting would also
  28225. // call this hook, as would any errors encountered
  28226. // in `afterModel`.
  28227. // The `error` hook is also provided the failed
  28228. // `transition`, which can be stored and later
  28229. // `.retry()`d if desired.
  28230. this.transitionTo('login');
  28231. }
  28232. }
  28233. });
  28234. ```
  28235. `error` actions that bubble up all the way to `ApplicationRoute`
  28236. will fire a default error handler that logs the error. You can
  28237. specify your own global default error handler by overriding the
  28238. `error` handler on `ApplicationRoute`:
  28239. ```js
  28240. App.ApplicationRoute = Ember.Route.extend({
  28241. actions: {
  28242. error: function(error, transition) {
  28243. this.controllerFor('banner').displayError(error.message);
  28244. }
  28245. }
  28246. });
  28247. ```
  28248. @property actions
  28249. @type Hash
  28250. @default null
  28251. */
  28252. _actions: {
  28253. finalizeQueryParamChange: function(params, finalParams) {
  28254. }
  28255. },
  28256. /**
  28257. @deprecated
  28258. Please use `actions` instead.
  28259. @method events
  28260. */
  28261. events: null,
  28262. mergedProperties: ['events'],
  28263. /**
  28264. This hook is executed when the router completely exits this route. It is
  28265. not executed when the model for the route changes.
  28266. @method deactivate
  28267. */
  28268. deactivate: Ember.K,
  28269. /**
  28270. This hook is executed when the router enters the route. It is not executed
  28271. when the model for the route changes.
  28272. @method activate
  28273. */
  28274. activate: Ember.K,
  28275. /**
  28276. Transition into another route. Optionally supply model(s) for the
  28277. route in question. If multiple models are supplied they will be applied
  28278. last to first recursively up the resource tree (see Multiple Models Example
  28279. below). The model(s) will be serialized into the URL using the appropriate
  28280. route's `serialize` hook. See also 'replaceWith'.
  28281. Simple Transition Example
  28282. ```javascript
  28283. App.Router.map(function() {
  28284. this.route("index");
  28285. this.route("secret");
  28286. this.route("fourOhFour", { path: "*:"});
  28287. });
  28288. App.IndexRoute = Ember.Route.extend({
  28289. actions: {
  28290. moveToSecret: function(context){
  28291. if (authorized()){
  28292. this.transitionTo('secret', context);
  28293. }
  28294. this.transitionTo('fourOhFour');
  28295. }
  28296. }
  28297. });
  28298. ```
  28299. Transition to a nested route
  28300. ```javascript
  28301. App.Router.map(function() {
  28302. this.resource('articles', { path: '/articles' }, function() {
  28303. this.route('new');
  28304. });
  28305. });
  28306. App.IndexRoute = Ember.Route.extend({
  28307. actions: {
  28308. transitionToNewArticle: function() {
  28309. this.transitionTo('articles.new');
  28310. }
  28311. }
  28312. });
  28313. ```
  28314. Multiple Models Example
  28315. ```javascript
  28316. App.Router.map(function() {
  28317. this.route("index");
  28318. this.resource('breakfast', {path:':breakfastId'}, function(){
  28319. this.resource('cereal', {path: ':cerealId'});
  28320. });
  28321. });
  28322. App.IndexRoute = Ember.Route.extend({
  28323. actions: {
  28324. moveToChocolateCereal: function(){
  28325. var cereal = { cerealId: "ChocolateYumminess"},
  28326. breakfast = {breakfastId: "CerealAndMilk"};
  28327. this.transitionTo('cereal', breakfast, cereal);
  28328. }
  28329. }
  28330. });
  28331. @method transitionTo
  28332. @param {String} name the name of the route
  28333. @param {...Object} models the model(s) to be used while transitioning
  28334. to the route.
  28335. @return {Transition} the transition object associated with this
  28336. attempted transition
  28337. */
  28338. transitionTo: function(name, context) {
  28339. var router = this.router;
  28340. return router.transitionTo.apply(router, arguments);
  28341. },
  28342. /**
  28343. Perform a synchronous transition into another route without attempting
  28344. to resolve promises, update the URL, or abort any currently active
  28345. asynchronous transitions (i.e. regular transitions caused by
  28346. `transitionTo` or URL changes).
  28347. This method is handy for performing intermediate transitions on the
  28348. way to a final destination route, and is called internally by the
  28349. default implementations of the `error` and `loading` handlers.
  28350. @method intermediateTransitionTo
  28351. @param {String} name the name of the route
  28352. @param {...Object} models the model(s) to be used while transitioning
  28353. to the route.
  28354. */
  28355. intermediateTransitionTo: function() {
  28356. var router = this.router;
  28357. router.intermediateTransitionTo.apply(router, arguments);
  28358. },
  28359. /**
  28360. Refresh the model on this route and any child routes, firing the
  28361. `beforeModel`, `model`, and `afterModel` hooks in a similar fashion
  28362. to how routes are entered when transitioning in from other route.
  28363. The current route params (e.g. `article_id`) will be passed in
  28364. to the respective model hooks, and if a different model is returned,
  28365. `setupController` and associated route hooks will re-fire as well.
  28366. An example usage of this method is re-querying the server for the
  28367. latest information using the same parameters as when the route
  28368. was first entered.
  28369. Note that this will cause `model` hooks to fire even on routes
  28370. that were provided a model object when the route was initially
  28371. entered.
  28372. @method refresh
  28373. @return {Transition} the transition object associated with this
  28374. attempted transition
  28375. */
  28376. refresh: function() {
  28377. return this.router.router.refresh(this).method('replace');
  28378. },
  28379. /**
  28380. Transition into another route while replacing the current URL, if possible.
  28381. This will replace the current history entry instead of adding a new one.
  28382. Beside that, it is identical to `transitionTo` in all other respects. See
  28383. 'transitionTo' for additional information regarding multiple models.
  28384. Example
  28385. ```javascript
  28386. App.Router.map(function() {
  28387. this.route("index");
  28388. this.route("secret");
  28389. });
  28390. App.SecretRoute = Ember.Route.extend({
  28391. afterModel: function() {
  28392. if (!authorized()){
  28393. this.replaceWith('index');
  28394. }
  28395. }
  28396. });
  28397. ```
  28398. @method replaceWith
  28399. @param {String} name the name of the route
  28400. @param {...Object} models the model(s) to be used while transitioning
  28401. to the route.
  28402. @return {Transition} the transition object associated with this
  28403. attempted transition
  28404. */
  28405. replaceWith: function() {
  28406. var router = this.router;
  28407. return router.replaceWith.apply(router, arguments);
  28408. },
  28409. /**
  28410. Sends an action to the router, which will delegate it to the currently
  28411. active route hierarchy per the bubbling rules explained under `actions`.
  28412. Example
  28413. ```javascript
  28414. App.Router.map(function() {
  28415. this.route("index");
  28416. });
  28417. App.ApplicationRoute = Ember.Route.extend({
  28418. actions: {
  28419. track: function(arg) {
  28420. console.log(arg, 'was clicked');
  28421. }
  28422. }
  28423. });
  28424. App.IndexRoute = Ember.Route.extend({
  28425. actions: {
  28426. trackIfDebug: function(arg) {
  28427. if (debug) {
  28428. this.send('track', arg);
  28429. }
  28430. }
  28431. }
  28432. });
  28433. ```
  28434. @method send
  28435. @param {String} name the name of the action to trigger
  28436. @param {...*} args
  28437. */
  28438. send: function() {
  28439. return this.router.send.apply(this.router, arguments);
  28440. },
  28441. /**
  28442. This hook is the entry point for router.js
  28443. @private
  28444. @method setup
  28445. */
  28446. setup: function(context, transition) {
  28447. var controllerName = this.controllerName || this.routeName,
  28448. controller = this.controllerFor(controllerName, true);
  28449. if (!controller) {
  28450. controller = this.generateController(controllerName, context);
  28451. }
  28452. // Assign the route's controller so that it can more easily be
  28453. // referenced in action handlers
  28454. this.controller = controller;
  28455. if (this.setupControllers) {
  28456. Ember.deprecate("Ember.Route.setupControllers is deprecated. Please use Ember.Route.setupController(controller, model) instead.");
  28457. this.setupControllers(controller, context);
  28458. } else {
  28459. this.setupController(controller, context);
  28460. }
  28461. if (this.renderTemplates) {
  28462. Ember.deprecate("Ember.Route.renderTemplates is deprecated. Please use Ember.Route.renderTemplate(controller, model) instead.");
  28463. this.renderTemplates(context);
  28464. } else {
  28465. this.renderTemplate(controller, context);
  28466. }
  28467. },
  28468. /**
  28469. This hook is the first of the route entry validation hooks
  28470. called when an attempt is made to transition into a route
  28471. or one of its children. It is called before `model` and
  28472. `afterModel`, and is appropriate for cases when:
  28473. 1) A decision can be made to redirect elsewhere without
  28474. needing to resolve the model first.
  28475. 2) Any async operations need to occur first before the
  28476. model is attempted to be resolved.
  28477. This hook is provided the current `transition` attempt
  28478. as a parameter, which can be used to `.abort()` the transition,
  28479. save it for a later `.retry()`, or retrieve values set
  28480. on it from a previous hook. You can also just call
  28481. `this.transitionTo` to another route to implicitly
  28482. abort the `transition`.
  28483. You can return a promise from this hook to pause the
  28484. transition until the promise resolves (or rejects). This could
  28485. be useful, for instance, for retrieving async code from
  28486. the server that is required to enter a route.
  28487. ```js
  28488. App.PostRoute = Ember.Route.extend({
  28489. beforeModel: function(transition) {
  28490. if (!App.Post) {
  28491. return Ember.$.getScript('/models/post.js');
  28492. }
  28493. }
  28494. });
  28495. ```
  28496. If `App.Post` doesn't exist in the above example,
  28497. `beforeModel` will use jQuery's `getScript`, which
  28498. returns a promise that resolves after the server has
  28499. successfully retrieved and executed the code from the
  28500. server. Note that if an error were to occur, it would
  28501. be passed to the `error` hook on `Ember.Route`, but
  28502. it's also possible to handle errors specific to
  28503. `beforeModel` right from within the hook (to distinguish
  28504. from the shared error handling behavior of the `error`
  28505. hook):
  28506. ```js
  28507. App.PostRoute = Ember.Route.extend({
  28508. beforeModel: function(transition) {
  28509. if (!App.Post) {
  28510. var self = this;
  28511. return Ember.$.getScript('post.js').then(null, function(e) {
  28512. self.transitionTo('help');
  28513. // Note that the above transitionTo will implicitly
  28514. // halt the transition. If you were to return
  28515. // nothing from this promise reject handler,
  28516. // according to promise semantics, that would
  28517. // convert the reject into a resolve and the
  28518. // transition would continue. To propagate the
  28519. // error so that it'd be handled by the `error`
  28520. // hook, you would have to either
  28521. return Ember.RSVP.reject(e);
  28522. });
  28523. }
  28524. }
  28525. });
  28526. ```
  28527. @method beforeModel
  28528. @param {Transition} transition
  28529. @param {Object} queryParams the active query params for this route
  28530. @return {Promise} if the value returned from this hook is
  28531. a promise, the transition will pause until the transition
  28532. resolves. Otherwise, non-promise return values are not
  28533. utilized in any way.
  28534. */
  28535. beforeModel: Ember.K,
  28536. /**
  28537. This hook is called after this route's model has resolved.
  28538. It follows identical async/promise semantics to `beforeModel`
  28539. but is provided the route's resolved model in addition to
  28540. the `transition`, and is therefore suited to performing
  28541. logic that can only take place after the model has already
  28542. resolved.
  28543. ```js
  28544. App.PostsRoute = Ember.Route.extend({
  28545. afterModel: function(posts, transition) {
  28546. if (posts.length === 1) {
  28547. this.transitionTo('post.show', posts[0]);
  28548. }
  28549. }
  28550. });
  28551. ```
  28552. Refer to documentation for `beforeModel` for a description
  28553. of transition-pausing semantics when a promise is returned
  28554. from this hook.
  28555. @method afterModel
  28556. @param {Object} resolvedModel the value returned from `model`,
  28557. or its resolved value if it was a promise
  28558. @param {Transition} transition
  28559. @param {Object} queryParams the active query params for this handler
  28560. @return {Promise} if the value returned from this hook is
  28561. a promise, the transition will pause until the transition
  28562. resolves. Otherwise, non-promise return values are not
  28563. utilized in any way.
  28564. */
  28565. afterModel: Ember.K,
  28566. /**
  28567. A hook you can implement to optionally redirect to another route.
  28568. If you call `this.transitionTo` from inside of this hook, this route
  28569. will not be entered in favor of the other hook.
  28570. `redirect` and `afterModel` behave very similarly and are
  28571. called almost at the same time, but they have an important
  28572. distinction in the case that, from one of these hooks, a
  28573. redirect into a child route of this route occurs: redirects
  28574. from `afterModel` essentially invalidate the current attempt
  28575. to enter this route, and will result in this route's `beforeModel`,
  28576. `model`, and `afterModel` hooks being fired again within
  28577. the new, redirecting transition. Redirects that occur within
  28578. the `redirect` hook, on the other hand, will _not_ cause
  28579. these hooks to be fired again the second time around; in
  28580. other words, by the time the `redirect` hook has been called,
  28581. both the resolved model and attempted entry into this route
  28582. are considered to be fully validated.
  28583. @method redirect
  28584. @param {Object} model the model for this route
  28585. */
  28586. redirect: Ember.K,
  28587. /**
  28588. Called when the context is changed by router.js.
  28589. @private
  28590. @method contextDidChange
  28591. */
  28592. contextDidChange: function() {
  28593. this.currentModel = this.context;
  28594. },
  28595. /**
  28596. A hook you can implement to convert the URL into the model for
  28597. this route.
  28598. ```js
  28599. App.Router.map(function() {
  28600. this.resource('post', {path: '/posts/:post_id'});
  28601. });
  28602. ```
  28603. The model for the `post` route is `App.Post.find(params.post_id)`.
  28604. By default, if your route has a dynamic segment ending in `_id`:
  28605. * The model class is determined from the segment (`post_id`'s
  28606. class is `App.Post`)
  28607. * The find method is called on the model class with the value of
  28608. the dynamic segment.
  28609. Note that for routes with dynamic segments, this hook is only
  28610. executed when entered via the URL. If the route is entered
  28611. through a transition (e.g. when using the `link-to` Handlebars
  28612. helper), then a model context is already provided and this hook
  28613. is not called. Routes without dynamic segments will always
  28614. execute the model hook.
  28615. This hook follows the asynchronous/promise semantics
  28616. described in the documentation for `beforeModel`. In particular,
  28617. if a promise returned from `model` fails, the error will be
  28618. handled by the `error` hook on `Ember.Route`.
  28619. Example
  28620. ```js
  28621. App.PostRoute = Ember.Route.extend({
  28622. model: function(params) {
  28623. return App.Post.find(params.post_id);
  28624. }
  28625. });
  28626. ```
  28627. @method model
  28628. @param {Object} params the parameters extracted from the URL
  28629. @param {Transition} transition
  28630. @param {Object} queryParams the query params for this route
  28631. @return {Object|Promise} the model for this route. If
  28632. a promise is returned, the transition will pause until
  28633. the promise resolves, and the resolved value of the promise
  28634. will be used as the model for this route.
  28635. */
  28636. model: function(params, transition) {
  28637. var match, name, sawParams, value;
  28638. for (var prop in params) {
  28639. if (prop === 'queryParams') { continue; }
  28640. if (match = prop.match(/^(.*)_id$/)) {
  28641. name = match[1];
  28642. value = params[prop];
  28643. }
  28644. sawParams = true;
  28645. }
  28646. if (!name && sawParams) { return params; }
  28647. else if (!name) { return; }
  28648. return this.findModel(name, value);
  28649. },
  28650. /**
  28651. @private
  28652. Router.js hook.
  28653. */
  28654. deserialize: function(params, transition) {
  28655. return this.model(params, transition);
  28656. },
  28657. /**
  28658. @method findModel
  28659. @param {String} type the model type
  28660. @param {Object} value the value passed to find
  28661. */
  28662. findModel: function(){
  28663. var store = get(this, 'store');
  28664. return store.find.apply(store, arguments);
  28665. },
  28666. /**
  28667. Store property provides a hook for data persistence libraries to inject themselves.
  28668. By default, this store property provides the exact same functionality previously
  28669. in the model hook.
  28670. Currently, the required interface is:
  28671. `store.find(modelName, findArguments)`
  28672. @method store
  28673. @param {Object} store
  28674. */
  28675. store: Ember.computed(function(){
  28676. var container = this.container;
  28677. var routeName = this.routeName;
  28678. var namespace = get(this, 'router.namespace');
  28679. return {
  28680. find: function(name, value) {
  28681. var modelClass = container.lookupFactory('model:' + name);
  28682. Ember.assert("You used the dynamic segment " + name + "_id in your route " +
  28683. routeName + ", but " + namespace + "." + classify(name) +
  28684. " did not exist and you did not override your route's `model` " +
  28685. "hook.", modelClass);
  28686. if (!modelClass) { return; }
  28687. return modelClass.find(value);
  28688. }
  28689. };
  28690. }),
  28691. /**
  28692. A hook you can implement to convert the route's model into parameters
  28693. for the URL.
  28694. ```js
  28695. App.Router.map(function() {
  28696. this.resource('post', {path: '/posts/:post_id'});
  28697. });
  28698. App.PostRoute = Ember.Route.extend({
  28699. model: function(params) {
  28700. // the server returns `{ id: 12 }`
  28701. return jQuery.getJSON("/posts/" + params.post_id);
  28702. },
  28703. serialize: function(model) {
  28704. // this will make the URL `/posts/12`
  28705. return { post_id: model.id };
  28706. }
  28707. });
  28708. ```
  28709. The default `serialize` method will insert the model's `id` into the
  28710. route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'.
  28711. If the route has multiple dynamic segments or does not contain '_id', `serialize`
  28712. will return `Ember.getProperties(model, params)`
  28713. This method is called when `transitionTo` is called with a context
  28714. in order to populate the URL.
  28715. @method serialize
  28716. @param {Object} model the route's model
  28717. @param {Array} params an Array of parameter names for the current
  28718. route (in the example, `['post_id']`.
  28719. @return {Object} the serialized parameters
  28720. */
  28721. serialize: function(model, params) {
  28722. if (params.length < 1) { return; }
  28723. if (!model) { return; }
  28724. var name = params[0], object = {};
  28725. if (/_id$/.test(name) && params.length === 1) {
  28726. object[name] = get(model, "id");
  28727. } else {
  28728. object = getProperties(model, params);
  28729. }
  28730. return object;
  28731. },
  28732. /**
  28733. A hook you can use to setup the controller for the current route.
  28734. This method is called with the controller for the current route and the
  28735. model supplied by the `model` hook.
  28736. By default, the `setupController` hook sets the `content` property of
  28737. the controller to the `model`.
  28738. This means that your template will get a proxy for the model as its
  28739. context, and you can act as though the model itself was the context.
  28740. The provided controller will be one resolved based on the name
  28741. of this route.
  28742. If no explicit controller is defined, Ember will automatically create
  28743. an appropriate controller for the model.
  28744. * if the model is an `Ember.Array` (including record arrays from Ember
  28745. Data), the controller is an `Ember.ArrayController`.
  28746. * otherwise, the controller is an `Ember.ObjectController`.
  28747. As an example, consider the router:
  28748. ```js
  28749. App.Router.map(function() {
  28750. this.resource('post', {path: '/posts/:post_id'});
  28751. });
  28752. ```
  28753. For the `post` route, a controller named `App.PostController` would
  28754. be used if it is defined. If it is not defined, an `Ember.ObjectController`
  28755. instance would be used.
  28756. Example
  28757. ```js
  28758. App.PostRoute = Ember.Route.extend({
  28759. setupController: function(controller, model) {
  28760. controller.set('model', model);
  28761. }
  28762. });
  28763. ```
  28764. @method setupController
  28765. @param {Controller} controller instance
  28766. @param {Object} model
  28767. */
  28768. setupController: function(controller, context, transition) {
  28769. if (controller && (context !== undefined)) {
  28770. set(controller, 'model', context);
  28771. }
  28772. },
  28773. /**
  28774. Returns the controller for a particular route or name.
  28775. The controller instance must already have been created, either through entering the
  28776. associated route or using `generateController`.
  28777. ```js
  28778. App.PostRoute = Ember.Route.extend({
  28779. setupController: function(controller, post) {
  28780. this._super(controller, post);
  28781. this.controllerFor('posts').set('currentPost', post);
  28782. }
  28783. });
  28784. ```
  28785. @method controllerFor
  28786. @param {String} name the name of the route or controller
  28787. @return {Ember.Controller}
  28788. */
  28789. controllerFor: function(name, _skipAssert) {
  28790. var container = this.container,
  28791. route = container.lookup('route:'+name),
  28792. controller;
  28793. if (route && route.controllerName) {
  28794. name = route.controllerName;
  28795. }
  28796. controller = container.lookup('controller:' + name);
  28797. // NOTE: We're specifically checking that skipAssert is true, because according
  28798. // to the old API the second parameter was model. We do not want people who
  28799. // passed a model to skip the assertion.
  28800. Ember.assert("The controller named '"+name+"' could not be found. Make sure " +
  28801. "that this route exists and has already been entered at least " +
  28802. "once. If you are accessing a controller not associated with a " +
  28803. "route, make sure the controller class is explicitly defined.",
  28804. controller || _skipAssert === true);
  28805. return controller;
  28806. },
  28807. /**
  28808. Generates a controller for a route.
  28809. If the optional model is passed then the controller type is determined automatically,
  28810. e.g., an ArrayController for arrays.
  28811. Example
  28812. ```js
  28813. App.PostRoute = Ember.Route.extend({
  28814. setupController: function(controller, post) {
  28815. this._super(controller, post);
  28816. this.generateController('posts', post);
  28817. }
  28818. });
  28819. ```
  28820. @method generateController
  28821. @param {String} name the name of the controller
  28822. @param {Object} model the model to infer the type of the controller (optional)
  28823. */
  28824. generateController: function(name, model) {
  28825. var container = this.container;
  28826. model = model || this.modelFor(name);
  28827. return Ember.generateController(container, name, model);
  28828. },
  28829. /**
  28830. Returns the model of a parent (or any ancestor) route
  28831. in a route hierarchy. During a transition, all routes
  28832. must resolve a model object, and if a route
  28833. needs access to a parent route's model in order to
  28834. resolve a model (or just reuse the model from a parent),
  28835. it can call `this.modelFor(theNameOfParentRoute)` to
  28836. retrieve it.
  28837. Example
  28838. ```js
  28839. App.Router.map(function() {
  28840. this.resource('post', { path: '/post/:post_id' }, function() {
  28841. this.resource('comments');
  28842. });
  28843. });
  28844. App.CommentsRoute = Ember.Route.extend({
  28845. afterModel: function() {
  28846. this.set('post', this.modelFor('post'));
  28847. }
  28848. });
  28849. ```
  28850. @method modelFor
  28851. @param {String} name the name of the route
  28852. @return {Object} the model object
  28853. */
  28854. modelFor: function(name) {
  28855. var route = this.container.lookup('route:' + name),
  28856. transition = this.router.router.activeTransition;
  28857. // If we are mid-transition, we want to try and look up
  28858. // resolved parent contexts on the current transitionEvent.
  28859. if (transition) {
  28860. var modelLookupName = (route && route.routeName) || name;
  28861. if (transition.resolvedModels.hasOwnProperty(modelLookupName)) {
  28862. return transition.resolvedModels[modelLookupName];
  28863. }
  28864. }
  28865. return route && route.currentModel;
  28866. },
  28867. /**
  28868. A hook you can use to render the template for the current route.
  28869. This method is called with the controller for the current route and the
  28870. model supplied by the `model` hook. By default, it renders the route's
  28871. template, configured with the controller for the route.
  28872. This method can be overridden to set up and render additional or
  28873. alternative templates.
  28874. ```js
  28875. App.PostsRoute = Ember.Route.extend({
  28876. renderTemplate: function(controller, model) {
  28877. var favController = this.controllerFor('favoritePost');
  28878. // Render the `favoritePost` template into
  28879. // the outlet `posts`, and display the `favoritePost`
  28880. // controller.
  28881. this.render('favoritePost', {
  28882. outlet: 'posts',
  28883. controller: favController
  28884. });
  28885. }
  28886. });
  28887. ```
  28888. @method renderTemplate
  28889. @param {Object} controller the route's controller
  28890. @param {Object} model the route's model
  28891. */
  28892. renderTemplate: function(controller, model) {
  28893. this.render();
  28894. },
  28895. /**
  28896. Renders a template into an outlet.
  28897. This method has a number of defaults, based on the name of the
  28898. route specified in the router.
  28899. For example:
  28900. ```js
  28901. App.Router.map(function() {
  28902. this.route('index');
  28903. this.resource('post', {path: '/posts/:post_id'});
  28904. });
  28905. App.PostRoute = App.Route.extend({
  28906. renderTemplate: function() {
  28907. this.render();
  28908. }
  28909. });
  28910. ```
  28911. The name of the `PostRoute`, as defined by the router, is `post`.
  28912. By default, render will:
  28913. * render the `post` template
  28914. * with the `post` view (`PostView`) for event handling, if one exists
  28915. * and the `post` controller (`PostController`), if one exists
  28916. * into the `main` outlet of the `application` template
  28917. You can override this behavior:
  28918. ```js
  28919. App.PostRoute = App.Route.extend({
  28920. renderTemplate: function() {
  28921. this.render('myPost', { // the template to render
  28922. into: 'index', // the template to render into
  28923. outlet: 'detail', // the name of the outlet in that template
  28924. controller: 'blogPost' // the controller to use for the template
  28925. });
  28926. }
  28927. });
  28928. ```
  28929. Remember that the controller's `content` will be the route's model. In
  28930. this case, the default model will be `App.Post.find(params.post_id)`.
  28931. @method render
  28932. @param {String} name the name of the template to render
  28933. @param {Object} options the options
  28934. */
  28935. render: function(name, options) {
  28936. Ember.assert("The name in the given arguments is undefined", arguments.length > 0 ? !Ember.isNone(arguments[0]) : true);
  28937. var namePassed = !!name;
  28938. if (typeof name === 'object' && !options) {
  28939. options = name;
  28940. name = this.routeName;
  28941. }
  28942. options = options || {};
  28943. var templateName;
  28944. if (name) {
  28945. name = name.replace(/\//g, '.');
  28946. templateName = name;
  28947. } else {
  28948. name = this.routeName;
  28949. templateName = this.templateName || name;
  28950. }
  28951. var viewName = options.view || this.viewName || name;
  28952. var container = this.container,
  28953. view = container.lookup('view:' + viewName),
  28954. template = view ? view.get('template') : null;
  28955. if (!template) {
  28956. template = container.lookup('template:' + templateName);
  28957. }
  28958. if (!view && !template) {
  28959. Ember.assert("Could not find \"" + name + "\" template or view.", !namePassed);
  28960. if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) {
  28961. Ember.Logger.info("Could not find \"" + name + "\" template or view. Nothing will be rendered", { fullName: 'template:' + name });
  28962. }
  28963. return;
  28964. }
  28965. options = normalizeOptions(this, name, template, options);
  28966. view = setupView(view, container, options);
  28967. if (options.outlet === 'main') { this.lastRenderedTemplate = name; }
  28968. appendView(this, view, options);
  28969. },
  28970. /**
  28971. Disconnects a view that has been rendered into an outlet.
  28972. You may pass any or all of the following options to `disconnectOutlet`:
  28973. * `outlet`: the name of the outlet to clear (default: 'main')
  28974. * `parentView`: the name of the view containing the outlet to clear
  28975. (default: the view rendered by the parent route)
  28976. Example:
  28977. ```js
  28978. App.ApplicationRoute = App.Route.extend({
  28979. actions: {
  28980. showModal: function(evt) {
  28981. this.render(evt.modalName, {
  28982. outlet: 'modal',
  28983. into: 'application'
  28984. });
  28985. },
  28986. hideModal: function(evt) {
  28987. this.disconnectOutlet({
  28988. outlet: 'modal',
  28989. parentView: 'application'
  28990. });
  28991. }
  28992. }
  28993. });
  28994. ```
  28995. @method disconnectOutlet
  28996. @param {Object} options the options
  28997. */
  28998. disconnectOutlet: function(options) {
  28999. options = options || {};
  29000. options.parentView = options.parentView ? options.parentView.replace(/\//g, '.') : parentTemplate(this);
  29001. options.outlet = options.outlet || 'main';
  29002. var parentView = this.router._lookupActiveView(options.parentView);
  29003. if (parentView) { parentView.disconnectOutlet(options.outlet); }
  29004. },
  29005. willDestroy: function() {
  29006. this.teardownViews();
  29007. },
  29008. /**
  29009. @private
  29010. @method teardownViews
  29011. */
  29012. teardownViews: function() {
  29013. // Tear down the top level view
  29014. if (this.teardownTopLevelView) { this.teardownTopLevelView(); }
  29015. // Tear down any outlets rendered with 'into'
  29016. var teardownOutletViews = this.teardownOutletViews || [];
  29017. a_forEach(teardownOutletViews, function(teardownOutletView) {
  29018. teardownOutletView();
  29019. });
  29020. delete this.teardownTopLevelView;
  29021. delete this.teardownOutletViews;
  29022. delete this.lastRenderedTemplate;
  29023. }
  29024. });
  29025. function parentRoute(route) {
  29026. var handlerInfos = route.router.router.state.handlerInfos;
  29027. if (!handlerInfos) { return; }
  29028. var parent, current;
  29029. for (var i=0, l=handlerInfos.length; i<l; i++) {
  29030. current = handlerInfos[i].handler;
  29031. if (current === route) { return parent; }
  29032. parent = current;
  29033. }
  29034. }
  29035. function parentTemplate(route) {
  29036. var parent = parentRoute(route), template;
  29037. if (!parent) { return; }
  29038. if (template = parent.lastRenderedTemplate) {
  29039. return template;
  29040. } else {
  29041. return parentTemplate(parent);
  29042. }
  29043. }
  29044. function normalizeOptions(route, name, template, options) {
  29045. options = options || {};
  29046. options.into = options.into ? options.into.replace(/\//g, '.') : parentTemplate(route);
  29047. options.outlet = options.outlet || 'main';
  29048. options.name = name;
  29049. options.template = template;
  29050. options.LOG_VIEW_LOOKUPS = get(route.router, 'namespace.LOG_VIEW_LOOKUPS');
  29051. Ember.assert("An outlet ("+options.outlet+") was specified but was not found.", options.outlet === 'main' || options.into);
  29052. var controller = options.controller, namedController;
  29053. if (options.controller) {
  29054. controller = options.controller;
  29055. } else if (namedController = route.container.lookup('controller:' + name)) {
  29056. controller = namedController;
  29057. } else {
  29058. controller = route.controllerName || route.routeName;
  29059. }
  29060. if (typeof controller === 'string') {
  29061. var controllerName = controller;
  29062. controller = route.container.lookup('controller:' + controllerName);
  29063. if (!controller) {
  29064. throw new Ember.Error("You passed `controller: '" + controllerName + "'` into the `render` method, but no such controller could be found.");
  29065. }
  29066. }
  29067. options.controller = controller;
  29068. return options;
  29069. }
  29070. function setupView(view, container, options) {
  29071. if (view) {
  29072. if (options.LOG_VIEW_LOOKUPS) {
  29073. Ember.Logger.info("Rendering " + options.name + " with " + view, { fullName: 'view:' + options.name });
  29074. }
  29075. } else {
  29076. var defaultView = options.into ? 'view:default' : 'view:toplevel';
  29077. view = container.lookup(defaultView);
  29078. if (options.LOG_VIEW_LOOKUPS) {
  29079. Ember.Logger.info("Rendering " + options.name + " with default view " + view, { fullName: 'view:' + options.name });
  29080. }
  29081. }
  29082. if (!get(view, 'templateName')) {
  29083. set(view, 'template', options.template);
  29084. set(view, '_debugTemplateName', options.name);
  29085. }
  29086. set(view, 'renderedName', options.name);
  29087. set(view, 'controller', options.controller);
  29088. return view;
  29089. }
  29090. function appendView(route, view, options) {
  29091. if (options.into) {
  29092. var parentView = route.router._lookupActiveView(options.into);
  29093. var teardownOutletView = generateOutletTeardown(parentView, options.outlet);
  29094. if (!route.teardownOutletViews) { route.teardownOutletViews = []; }
  29095. a_replace(route.teardownOutletViews, 0, 0, [teardownOutletView]);
  29096. parentView.connectOutlet(options.outlet, view);
  29097. } else {
  29098. var rootElement = get(route, 'router.namespace.rootElement');
  29099. // tear down view if one is already rendered
  29100. if (route.teardownTopLevelView) {
  29101. route.teardownTopLevelView();
  29102. }
  29103. route.router._connectActiveView(options.name, view);
  29104. route.teardownTopLevelView = generateTopLevelTeardown(view);
  29105. view.appendTo(rootElement);
  29106. }
  29107. }
  29108. function generateTopLevelTeardown(view) {
  29109. return function() { view.destroy(); };
  29110. }
  29111. function generateOutletTeardown(parentView, outlet) {
  29112. return function() { parentView.disconnectOutlet(outlet); };
  29113. }
  29114. })();
  29115. (function() {
  29116. })();
  29117. (function() {
  29118. Ember.onLoad('Ember.Handlebars', function() {
  29119. var handlebarsResolve = Ember.Handlebars.resolveParams,
  29120. map = Ember.ArrayPolyfills.map,
  29121. get = Ember.get,
  29122. handlebarsGet = Ember.Handlebars.get;
  29123. function resolveParams(context, params, options) {
  29124. return map.call(resolvePaths(context, params, options), function(path, i) {
  29125. if (null === path) {
  29126. // Param was string/number, not a path, so just return raw string/number.
  29127. return params[i];
  29128. } else {
  29129. return handlebarsGet(context, path, options);
  29130. }
  29131. });
  29132. }
  29133. function resolvePaths(context, params, options) {
  29134. var resolved = handlebarsResolve(context, params, options),
  29135. types = options.types;
  29136. return map.call(resolved, function(object, i) {
  29137. if (types[i] === 'ID') {
  29138. return unwrap(object, params[i]);
  29139. } else {
  29140. return null;
  29141. }
  29142. });
  29143. function unwrap(object, path) {
  29144. if (path === 'controller') { return path; }
  29145. if (Ember.ControllerMixin.detect(object)) {
  29146. return unwrap(get(object, 'model'), path ? path + '.model' : 'model');
  29147. } else {
  29148. return path;
  29149. }
  29150. }
  29151. }
  29152. Ember.Router.resolveParams = resolveParams;
  29153. Ember.Router.resolvePaths = resolvePaths;
  29154. });
  29155. })();
  29156. (function() {
  29157. /**
  29158. @module ember
  29159. @submodule ember-routing
  29160. */
  29161. var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
  29162. var slice = Array.prototype.slice;
  29163. Ember.onLoad('Ember.Handlebars', function(Handlebars) {
  29164. var QueryParams = Ember.Object.extend({
  29165. values: null
  29166. });
  29167. var resolveParams = Ember.Router.resolveParams,
  29168. translateQueryParams = Ember.Router._translateQueryParams,
  29169. resolvePaths = Ember.Router.resolvePaths,
  29170. isSimpleClick = Ember.ViewUtils.isSimpleClick;
  29171. function fullRouteName(router, name) {
  29172. var nameWithIndex;
  29173. if (!router.hasRoute(name)) {
  29174. nameWithIndex = name + '.index';
  29175. Ember.assert(fmt("The attempt to link-to route '%@' failed (also tried '%@'). " +
  29176. "The router did not find '%@' in its possible routes: '%@'",
  29177. [name, nameWithIndex, name, Ember.keys(router.router.recognizer.names).join("', '")]),
  29178. router.hasRoute(nameWithIndex));
  29179. name = nameWithIndex;
  29180. }
  29181. return name;
  29182. }
  29183. function getResolvedPaths(options) {
  29184. var types = options.options.types,
  29185. data = options.options.data;
  29186. return resolvePaths(options.context, options.params, { types: types, data: data });
  29187. }
  29188. /**
  29189. `Ember.LinkView` renders an element whose `click` event triggers a
  29190. transition of the application's instance of `Ember.Router` to
  29191. a supplied route by name.
  29192. Instances of `LinkView` will most likely be created through
  29193. the `link-to` Handlebars helper, but properties of this class
  29194. can be overridden to customize application-wide behavior.
  29195. @class LinkView
  29196. @namespace Ember
  29197. @extends Ember.View
  29198. @see {Handlebars.helpers.link-to}
  29199. **/
  29200. var LinkView = Ember.LinkView = Ember.View.extend({
  29201. tagName: 'a',
  29202. currentWhen: null,
  29203. /**
  29204. Sets the `title` attribute of the `LinkView`'s HTML element.
  29205. @property title
  29206. @default null
  29207. **/
  29208. title: null,
  29209. /**
  29210. Sets the `rel` attribute of the `LinkView`'s HTML element.
  29211. @property rel
  29212. @default null
  29213. **/
  29214. rel: null,
  29215. /**
  29216. The CSS class to apply to `LinkView`'s element when its `active`
  29217. property is `true`.
  29218. @property activeClass
  29219. @type String
  29220. @default active
  29221. **/
  29222. activeClass: 'active',
  29223. /**
  29224. The CSS class to apply to `LinkView`'s element when its `loading`
  29225. property is `true`.
  29226. @property loadingClass
  29227. @type String
  29228. @default loading
  29229. **/
  29230. loadingClass: 'loading',
  29231. /**
  29232. The CSS class to apply to a `LinkView`'s element when its `disabled`
  29233. property is `true`.
  29234. @property disabledClass
  29235. @type String
  29236. @default disabled
  29237. **/
  29238. disabledClass: 'disabled',
  29239. _isDisabled: false,
  29240. /**
  29241. Determines whether the `LinkView` will trigger routing via
  29242. the `replaceWith` routing strategy.
  29243. @property replace
  29244. @type Boolean
  29245. @default false
  29246. **/
  29247. replace: false,
  29248. /**
  29249. By default the `{{link-to}}` helper will bind to the `href` and
  29250. `title` attributes. It's discourage that you override these defaults,
  29251. however you can push onto the array if needed.
  29252. @property attributeBindings
  29253. @type Array | String
  29254. @default ['href', 'title', 'rel']
  29255. **/
  29256. attributeBindings: ['href', 'title', 'rel'],
  29257. /**
  29258. By default the `{{link-to}}` helper will bind to the `active`, `loading`, and
  29259. `disabled` classes. It is discouraged to override these directly.
  29260. @property classNameBindings
  29261. @type Array
  29262. @default ['active', 'loading', 'disabled']
  29263. **/
  29264. classNameBindings: ['active', 'loading', 'disabled'],
  29265. /**
  29266. By default the `{{link-to}}` helper responds to the `click` event. You
  29267. can override this globally by setting this property to your custom
  29268. event name.
  29269. This is particularly useful on mobile when one wants to avoid the 300ms
  29270. click delay using some sort of custom `tap` event.
  29271. @property eventName
  29272. @type String
  29273. @default click
  29274. */
  29275. eventName: 'click',
  29276. // this is doc'ed here so it shows up in the events
  29277. // section of the API documentation, which is where
  29278. // people will likely go looking for it.
  29279. /**
  29280. Triggers the `LinkView`'s routing behavior. If
  29281. `eventName` is changed to a value other than `click`
  29282. the routing behavior will trigger on that custom event
  29283. instead.
  29284. @event click
  29285. **/
  29286. /**
  29287. An overridable method called when LinkView objects are instantiated.
  29288. Example:
  29289. ```javascript
  29290. App.MyLinkView = Ember.LinkView.extend({
  29291. init: function() {
  29292. this._super();
  29293. Ember.Logger.log('Event is ' + this.get('eventName'));
  29294. }
  29295. });
  29296. ```
  29297. NOTE: If you do override `init` for a framework class like `Ember.View` or
  29298. `Ember.ArrayController`, be sure to call `this._super()` in your
  29299. `init` declaration! If you don't, Ember may not have an opportunity to
  29300. do important setup work, and you'll see strange behavior in your
  29301. application.
  29302. @method init
  29303. */
  29304. init: function() {
  29305. this._super.apply(this, arguments);
  29306. // Map desired event name to invoke function
  29307. var eventName = get(this, 'eventName'), i;
  29308. this.on(eventName, this, this._invoke);
  29309. },
  29310. /**
  29311. This method is invoked by observers installed during `init` that fire
  29312. whenever the params change
  29313. @private
  29314. @method _paramsChanged
  29315. */
  29316. _paramsChanged: function() {
  29317. this.notifyPropertyChange('resolvedParams');
  29318. },
  29319. /**
  29320. This is called to setup observers that will trigger a rerender.
  29321. @private
  29322. @method _setupPathObservers
  29323. **/
  29324. _setupPathObservers: function(){
  29325. var helperParameters = this.parameters,
  29326. linkTextPath = helperParameters.options.linkTextPath,
  29327. paths = getResolvedPaths(helperParameters),
  29328. length = paths.length,
  29329. path, i, normalizedPath;
  29330. if (linkTextPath) {
  29331. normalizedPath = Ember.Handlebars.normalizePath(helperParameters.context, linkTextPath, helperParameters.options.data);
  29332. this.registerObserver(normalizedPath.root, normalizedPath.path, this, this.rerender);
  29333. }
  29334. for(i=0; i < length; i++) {
  29335. path = paths[i];
  29336. if (null === path) {
  29337. // A literal value was provided, not a path, so nothing to observe.
  29338. continue;
  29339. }
  29340. normalizedPath = Ember.Handlebars.normalizePath(helperParameters.context, path, helperParameters.options.data);
  29341. this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged);
  29342. }
  29343. var queryParamsObject = this.queryParamsObject;
  29344. if (queryParamsObject) {
  29345. var values = queryParamsObject.values;
  29346. // Install observers for all of the hash options
  29347. // provided in the (query-params) subexpression.
  29348. for (var k in values) {
  29349. if (!values.hasOwnProperty(k)) { continue; }
  29350. if (queryParamsObject.types[k] === 'ID') {
  29351. normalizedPath = Ember.Handlebars.normalizePath(helperParameters.context, values[k], helperParameters.options.data);
  29352. this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged);
  29353. }
  29354. }
  29355. }
  29356. },
  29357. afterRender: function(){
  29358. this._super.apply(this, arguments);
  29359. this._setupPathObservers();
  29360. },
  29361. /**
  29362. Even though this isn't a virtual view, we want to treat it as if it is
  29363. so that you can access the parent with {{view.prop}}
  29364. @private
  29365. @method concreteView
  29366. **/
  29367. concreteView: Ember.computed(function() {
  29368. return get(this, 'parentView');
  29369. }).property('parentView'),
  29370. /**
  29371. Accessed as a classname binding to apply the `LinkView`'s `disabledClass`
  29372. CSS `class` to the element when the link is disabled.
  29373. When `true` interactions with the element will not trigger route changes.
  29374. @property disabled
  29375. */
  29376. disabled: Ember.computed(function computeLinkViewDisabled(key, value) {
  29377. if (value !== undefined) { this.set('_isDisabled', value); }
  29378. return value ? get(this, 'disabledClass') : false;
  29379. }),
  29380. /**
  29381. Accessed as a classname binding to apply the `LinkView`'s `activeClass`
  29382. CSS `class` to the element when the link is active.
  29383. A `LinkView` is considered active when its `currentWhen` property is `true`
  29384. or the application's current route is the route the `LinkView` would trigger
  29385. transitions into.
  29386. @property active
  29387. **/
  29388. active: Ember.computed(function computeLinkViewActive() {
  29389. if (get(this, 'loading')) { return false; }
  29390. var router = get(this, 'router'),
  29391. routeArgs = get(this, 'routeArgs'),
  29392. contexts = routeArgs.slice(1),
  29393. resolvedParams = get(this, 'resolvedParams'),
  29394. currentWhen = this.currentWhen || resolvedParams[0],
  29395. currentWithIndex = currentWhen + '.index',
  29396. isActive = router.isActive.apply(router, [currentWhen].concat(contexts)) ||
  29397. router.isActive.apply(router, [currentWithIndex].concat(contexts));
  29398. if (isActive) { return get(this, 'activeClass'); }
  29399. }).property('resolvedParams', 'routeArgs'),
  29400. /**
  29401. Accessed as a classname binding to apply the `LinkView`'s `loadingClass`
  29402. CSS `class` to the element when the link is loading.
  29403. A `LinkView` is considered loading when it has at least one
  29404. parameter whose value is currently null or undefined. During
  29405. this time, clicking the link will perform no transition and
  29406. emit a warning that the link is still in a loading state.
  29407. @property loading
  29408. **/
  29409. loading: Ember.computed(function computeLinkViewLoading() {
  29410. if (!get(this, 'routeArgs')) { return get(this, 'loadingClass'); }
  29411. }).property('routeArgs'),
  29412. /**
  29413. Returns the application's main router from the container.
  29414. @private
  29415. @property router
  29416. **/
  29417. router: Ember.computed(function() {
  29418. return get(this, 'controller').container.lookup('router:main');
  29419. }),
  29420. /**
  29421. Event handler that invokes the link, activating the associated route.
  29422. @private
  29423. @method _invoke
  29424. @param {Event} event
  29425. */
  29426. _invoke: function(event) {
  29427. if (!isSimpleClick(event)) { return true; }
  29428. if (this.preventDefault !== false) { event.preventDefault(); }
  29429. if (this.bubbles === false) { event.stopPropagation(); }
  29430. if (get(this, '_isDisabled')) { return false; }
  29431. if (get(this, 'loading')) {
  29432. Ember.Logger.warn("This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid.");
  29433. return false;
  29434. }
  29435. var router = get(this, 'router'),
  29436. routeArgs = get(this, 'routeArgs');
  29437. if (get(this, 'replace')) {
  29438. router.replaceWith.apply(router, routeArgs);
  29439. } else {
  29440. router.transitionTo.apply(router, routeArgs);
  29441. }
  29442. },
  29443. /**
  29444. Computed property that returns an array of the
  29445. resolved parameters passed to the `link-to` helper,
  29446. e.g.:
  29447. ```hbs
  29448. {{link-to a b '123' c}}
  29449. ```
  29450. will generate a `resolvedParams` of:
  29451. ```js
  29452. [aObject, bObject, '123', cObject]
  29453. ```
  29454. @private
  29455. @property
  29456. @return {Array}
  29457. */
  29458. resolvedParams: Ember.computed(function() {
  29459. var parameters = this.parameters,
  29460. options = parameters.options,
  29461. types = options.types,
  29462. data = options.data;
  29463. if (parameters.params.length === 0) {
  29464. var appController = this.container.lookup('controller:application');
  29465. return [get(appController, 'currentRouteName')];
  29466. } else {
  29467. return resolveParams(parameters.context, parameters.params, { types: types, data: data });
  29468. }
  29469. // Original implementation if query params not enabled
  29470. return resolveParams(parameters.context, parameters.params, { types: types, data: data });
  29471. }).property('router.url'),
  29472. /**
  29473. Computed property that returns the current route name and
  29474. any dynamic segments.
  29475. @private
  29476. @property
  29477. @return {Array} An array with the route name and any dynamic segments
  29478. */
  29479. routeArgs: Ember.computed(function computeLinkViewRouteArgs() {
  29480. var resolvedParams = get(this, 'resolvedParams').slice(0),
  29481. router = get(this, 'router'),
  29482. namedRoute = resolvedParams[0];
  29483. if (!namedRoute) { return; }
  29484. namedRoute = fullRouteName(router, namedRoute);
  29485. resolvedParams[0] = namedRoute;
  29486. for (var i = 1, len = resolvedParams.length; i < len; ++i) {
  29487. var param = resolvedParams[i];
  29488. if (param === null || typeof param === 'undefined') {
  29489. // If contexts aren't present, consider the linkView unloaded.
  29490. return;
  29491. }
  29492. }
  29493. return resolvedParams;
  29494. }).property('resolvedParams', 'queryParams'),
  29495. queryParamsObject: null,
  29496. queryParams: Ember.computed(function computeLinkViewQueryParams() {
  29497. var queryParamsObject = get(this, 'queryParamsObject'),
  29498. suppliedParams = {};
  29499. if (queryParamsObject) {
  29500. Ember.merge(suppliedParams, queryParamsObject.values);
  29501. }
  29502. var resolvedParams = get(this, 'resolvedParams'),
  29503. router = get(this, 'router'),
  29504. routeName = resolvedParams[0],
  29505. paramsForRoute = router._queryParamNamesFor(routeName),
  29506. queryParams = paramsForRoute.queryParams,
  29507. translations = paramsForRoute.translations,
  29508. paramsForRecognizer = {};
  29509. // Normalize supplied params into their long-form name
  29510. // e.g. 'foo' -> 'controllername:foo'
  29511. translateQueryParams(suppliedParams, translations, routeName);
  29512. var helperParameters = this.parameters;
  29513. router._queryParamOverrides(paramsForRecognizer, queryParams, function(name, resultsName) {
  29514. if (!(name in suppliedParams)) { return; }
  29515. var parts = name.split(':');
  29516. var type = queryParamsObject.types[parts[1]];
  29517. var value;
  29518. if (type === 'ID') {
  29519. var normalizedPath = Ember.Handlebars.normalizePath(helperParameters.context, suppliedParams[name], helperParameters.options.data);
  29520. value = Ember.Handlebars.get(normalizedPath.root, normalizedPath.path, helperParameters.options);
  29521. } else {
  29522. value = suppliedParams[name];
  29523. }
  29524. delete suppliedParams[name];
  29525. paramsForRecognizer[resultsName] = value;
  29526. });
  29527. return paramsForRecognizer;
  29528. }).property('resolvedParams.[]'),
  29529. /**
  29530. Sets the element's `href` attribute to the url for
  29531. the `LinkView`'s targeted route.
  29532. If the `LinkView`'s `tagName` is changed to a value other
  29533. than `a`, this property will be ignored.
  29534. @property href
  29535. **/
  29536. href: Ember.computed(function computeLinkViewHref() {
  29537. if (get(this, 'tagName') !== 'a') { return; }
  29538. var router = get(this, 'router'),
  29539. routeArgs = get(this, 'routeArgs');
  29540. return routeArgs ? router.generate.apply(router, routeArgs) : get(this, 'loadingHref');
  29541. }).property('routeArgs'),
  29542. /**
  29543. The default href value to use while a link-to is loading.
  29544. Only applies when tagName is 'a'
  29545. @property loadingHref
  29546. @type String
  29547. @default #
  29548. */
  29549. loadingHref: '#'
  29550. });
  29551. LinkView.toString = function() { return "LinkView"; };
  29552. /**
  29553. The `{{link-to}}` helper renders a link to the supplied
  29554. `routeName` passing an optionally supplied model to the
  29555. route as its `model` context of the route. The block
  29556. for `{{link-to}}` becomes the innerHTML of the rendered
  29557. element:
  29558. ```handlebars
  29559. {{#link-to 'photoGallery'}}
  29560. Great Hamster Photos
  29561. {{/link-to}}
  29562. ```
  29563. ```html
  29564. <a href="/hamster-photos">
  29565. Great Hamster Photos
  29566. </a>
  29567. ```
  29568. ### Supplying a tagName
  29569. By default `{{link-to}}` renders an `<a>` element. This can
  29570. be overridden for a single use of `{{link-to}}` by supplying
  29571. a `tagName` option:
  29572. ```handlebars
  29573. {{#link-to 'photoGallery' tagName="li"}}
  29574. Great Hamster Photos
  29575. {{/link-to}}
  29576. ```
  29577. ```html
  29578. <li>
  29579. Great Hamster Photos
  29580. </li>
  29581. ```
  29582. To override this option for your entire application, see
  29583. "Overriding Application-wide Defaults".
  29584. ### Disabling the `link-to` helper
  29585. By default `{{link-to}}` is enabled.
  29586. any passed value to `disabled` helper property will disable the `link-to` helper.
  29587. static use: the `disabled` option:
  29588. ```handlebars
  29589. {{#link-to 'photoGallery' disabled=true}}
  29590. Great Hamster Photos
  29591. {{/link-to}}
  29592. ```
  29593. dynamic use: the `disabledWhen` option:
  29594. ```handlebars
  29595. {{#link-to 'photoGallery' disabledWhen=controller.someProperty}}
  29596. Great Hamster Photos
  29597. {{/link-to}}
  29598. ```
  29599. any passed value to `disabled` will disable it except `undefined`.
  29600. to ensure that only `true` disable the `link-to` helper you can
  29601. override the global behaviour of `Ember.LinkView`.
  29602. ```javascript
  29603. Ember.LinkView.reopen({
  29604. disabled: Ember.computed(function(key, value) {
  29605. if (value !== undefined) {
  29606. this.set('_isDisabled', value === true);
  29607. }
  29608. return value === true ? get(this, 'disabledClass') : false;
  29609. })
  29610. });
  29611. ```
  29612. see "Overriding Application-wide Defaults" for more.
  29613. ### Handling `href`
  29614. `{{link-to}}` will use your application's Router to
  29615. fill the element's `href` property with a url that
  29616. matches the path to the supplied `routeName` for your
  29617. routers's configured `Location` scheme, which defaults
  29618. to Ember.HashLocation.
  29619. ### Handling current route
  29620. `{{link-to}}` will apply a CSS class name of 'active'
  29621. when the application's current route matches
  29622. the supplied routeName. For example, if the application's
  29623. current route is 'photoGallery.recent' the following
  29624. use of `{{link-to}}`:
  29625. ```handlebars
  29626. {{#link-to 'photoGallery.recent'}}
  29627. Great Hamster Photos from the last week
  29628. {{/link-to}}
  29629. ```
  29630. will result in
  29631. ```html
  29632. <a href="/hamster-photos/this-week" class="active">
  29633. Great Hamster Photos
  29634. </a>
  29635. ```
  29636. The CSS class name used for active classes can be customized
  29637. for a single use of `{{link-to}}` by passing an `activeClass`
  29638. option:
  29639. ```handlebars
  29640. {{#link-to 'photoGallery.recent' activeClass="current-url"}}
  29641. Great Hamster Photos from the last week
  29642. {{/link-to}}
  29643. ```
  29644. ```html
  29645. <a href="/hamster-photos/this-week" class="current-url">
  29646. Great Hamster Photos
  29647. </a>
  29648. ```
  29649. To override this option for your entire application, see
  29650. "Overriding Application-wide Defaults".
  29651. ### Supplying a model
  29652. An optional model argument can be used for routes whose
  29653. paths contain dynamic segments. This argument will become
  29654. the model context of the linked route:
  29655. ```javascript
  29656. App.Router.map(function() {
  29657. this.resource("photoGallery", {path: "hamster-photos/:photo_id"});
  29658. });
  29659. ```
  29660. ```handlebars
  29661. {{#link-to 'photoGallery' aPhoto}}
  29662. {{aPhoto.title}}
  29663. {{/link-to}}
  29664. ```
  29665. ```html
  29666. <a href="/hamster-photos/42">
  29667. Tomster
  29668. </a>
  29669. ```
  29670. ### Supplying multiple models
  29671. For deep-linking to route paths that contain multiple
  29672. dynamic segments, multiple model arguments can be used.
  29673. As the router transitions through the route path, each
  29674. supplied model argument will become the context for the
  29675. route with the dynamic segments:
  29676. ```javascript
  29677. App.Router.map(function() {
  29678. this.resource("photoGallery", {path: "hamster-photos/:photo_id"}, function() {
  29679. this.route("comment", {path: "comments/:comment_id"});
  29680. });
  29681. });
  29682. ```
  29683. This argument will become the model context of the linked route:
  29684. ```handlebars
  29685. {{#link-to 'photoGallery.comment' aPhoto comment}}
  29686. {{comment.body}}
  29687. {{/link-to}}
  29688. ```
  29689. ```html
  29690. <a href="/hamster-photos/42/comment/718">
  29691. A+++ would snuggle again.
  29692. </a>
  29693. ```
  29694. ### Supplying an explicit dynamic segment value
  29695. If you don't have a model object available to pass to `{{link-to}}`,
  29696. an optional string or integer argument can be passed for routes whose
  29697. paths contain dynamic segments. This argument will become the value
  29698. of the dynamic segment:
  29699. ```javascript
  29700. App.Router.map(function() {
  29701. this.resource("photoGallery", {path: "hamster-photos/:photo_id"});
  29702. });
  29703. ```
  29704. ```handlebars
  29705. {{#link-to 'photoGallery' aPhotoId}}
  29706. {{aPhoto.title}}
  29707. {{/link-to}}
  29708. ```
  29709. ```html
  29710. <a href="/hamster-photos/42">
  29711. Tomster
  29712. </a>
  29713. ```
  29714. When transitioning into the linked route, the `model` hook will
  29715. be triggered with parameters including this passed identifier.
  29716. ### Allowing Default Action
  29717. By default the `{{link-to}}` helper prevents the default browser action
  29718. by calling `preventDefault()` as this sort of action bubbling is normally
  29719. handled internally and we do not want to take the browser to a new URL (for
  29720. example).
  29721. If you need to override this behavior specify `preventDefault=false` in
  29722. your template:
  29723. ```handlebars
  29724. {{#link-to 'photoGallery' aPhotoId preventDefault=false}}
  29725. {{aPhotoId.title}}
  29726. {{/link-to}}
  29727. ```
  29728. ### Overriding attributes
  29729. You can override any given property of the Ember.LinkView
  29730. that is generated by the `{{link-to}}` helper by passing
  29731. key/value pairs, like so:
  29732. ```handlebars
  29733. {{#link-to aPhoto tagName='li' title='Following this link will change your life' classNames='pic sweet'}}
  29734. Uh-mazing!
  29735. {{/link-to}}
  29736. ```
  29737. See [Ember.LinkView](/api/classes/Ember.LinkView.html) for a
  29738. complete list of overrideable properties. Be sure to also
  29739. check out inherited properties of `LinkView`.
  29740. ### Overriding Application-wide Defaults
  29741. ``{{link-to}}`` creates an instance of Ember.LinkView
  29742. for rendering. To override options for your entire
  29743. application, reopen Ember.LinkView and supply the
  29744. desired values:
  29745. ``` javascript
  29746. Ember.LinkView.reopen({
  29747. activeClass: "is-active",
  29748. tagName: 'li'
  29749. })
  29750. ```
  29751. It is also possible to override the default event in
  29752. this manner:
  29753. ``` javascript
  29754. Ember.LinkView.reopen({
  29755. eventName: 'customEventName'
  29756. });
  29757. ```
  29758. @method link-to
  29759. @for Ember.Handlebars.helpers
  29760. @param {String} routeName
  29761. @param {Object} [context]*
  29762. @param [options] {Object} Handlebars key/value pairs of options, you can override any property of Ember.LinkView
  29763. @return {String} HTML string
  29764. @see {Ember.LinkView}
  29765. */
  29766. Ember.Handlebars.registerHelper('link-to', function linkToHelper(name) {
  29767. var options = slice.call(arguments, -1)[0],
  29768. params = slice.call(arguments, 0, -1),
  29769. hash = options.hash;
  29770. if (params[params.length - 1] instanceof QueryParams) {
  29771. hash.queryParamsObject = params.pop();
  29772. }
  29773. hash.disabledBinding = hash.disabledWhen;
  29774. if (!options.fn) {
  29775. var linkTitle = params.shift();
  29776. var linkType = options.types.shift();
  29777. var context = this;
  29778. if (linkType === 'ID') {
  29779. options.linkTextPath = linkTitle;
  29780. options.fn = function() {
  29781. return Ember.Handlebars.getEscaped(context, linkTitle, options);
  29782. };
  29783. } else {
  29784. options.fn = function() {
  29785. return linkTitle;
  29786. };
  29787. }
  29788. }
  29789. hash.parameters = {
  29790. context: this,
  29791. options: options,
  29792. params: params
  29793. };
  29794. return Ember.Handlebars.helpers.view.call(this, LinkView, options);
  29795. });
  29796. /**
  29797. See [link-to](/api/classes/Ember.Handlebars.helpers.html#method_link-to)
  29798. @method linkTo
  29799. @for Ember.Handlebars.helpers
  29800. @deprecated
  29801. @param {String} routeName
  29802. @param {Object} [context]*
  29803. @return {String} HTML string
  29804. */
  29805. Ember.Handlebars.registerHelper('linkTo', function linkToHelper() {
  29806. Ember.warn("The 'linkTo' view helper is deprecated in favor of 'link-to'");
  29807. return Ember.Handlebars.helpers['link-to'].apply(this, arguments);
  29808. });
  29809. });
  29810. })();
  29811. (function() {
  29812. /**
  29813. @module ember
  29814. @submodule ember-routing
  29815. */
  29816. var get = Ember.get, set = Ember.set;
  29817. Ember.onLoad('Ember.Handlebars', function(Handlebars) {
  29818. /**
  29819. @module ember
  29820. @submodule ember-routing
  29821. */
  29822. Handlebars.OutletView = Ember.ContainerView.extend(Ember._Metamorph);
  29823. /**
  29824. The `outlet` helper is a placeholder that the router will fill in with
  29825. the appropriate template based on the current state of the application.
  29826. ``` handlebars
  29827. {{outlet}}
  29828. ```
  29829. By default, a template based on Ember's naming conventions will be rendered
  29830. into the `outlet` (e.g. `App.PostsRoute` will render the `posts` template).
  29831. You can render a different template by using the `render()` method in the
  29832. route's `renderTemplate` hook. The following will render the `favoritePost`
  29833. template into the `outlet`.
  29834. ``` javascript
  29835. App.PostsRoute = Ember.Route.extend({
  29836. renderTemplate: function() {
  29837. this.render('favoritePost');
  29838. }
  29839. });
  29840. ```
  29841. You can create custom named outlets for more control.
  29842. ``` handlebars
  29843. {{outlet 'favoritePost'}}
  29844. {{outlet 'posts'}}
  29845. ```
  29846. Then you can define what template is rendered into each outlet in your
  29847. route.
  29848. ``` javascript
  29849. App.PostsRoute = Ember.Route.extend({
  29850. renderTemplate: function() {
  29851. this.render('favoritePost', { outlet: 'favoritePost' });
  29852. this.render('posts', { outlet: 'posts' });
  29853. }
  29854. });
  29855. ```
  29856. You can specify the view that the outlet uses to contain and manage the
  29857. templates rendered into it.
  29858. ``` handlebars
  29859. {{outlet view='sectionContainer'}}
  29860. ```
  29861. ``` javascript
  29862. App.SectionContainer = Ember.ContainerView.extend({
  29863. tagName: 'section',
  29864. classNames: ['special']
  29865. });
  29866. ```
  29867. @method outlet
  29868. @for Ember.Handlebars.helpers
  29869. @param {String} property the property on the controller
  29870. that holds the view for this outlet
  29871. @return {String} HTML string
  29872. */
  29873. Handlebars.registerHelper('outlet', function outletHelper(property, options) {
  29874. var outletSource,
  29875. container,
  29876. viewName,
  29877. viewClass,
  29878. viewFullName;
  29879. if (property && property.data && property.data.isRenderData) {
  29880. options = property;
  29881. property = 'main';
  29882. }
  29883. container = options.data.view.container;
  29884. outletSource = options.data.view;
  29885. while (!outletSource.get('template.isTop')) {
  29886. outletSource = outletSource.get('_parentView');
  29887. }
  29888. // provide controller override
  29889. viewName = options.hash.view;
  29890. if (viewName) {
  29891. viewFullName = 'view:' + viewName;
  29892. Ember.assert("Using a quoteless view parameter with {{outlet}} is not supported. Please update to quoted usage '{{outlet \"" + viewName + "\"}}.", options.hashTypes.view !== 'ID');
  29893. Ember.assert("The view name you supplied '" + viewName + "' did not resolve to a view.", container.has(viewFullName));
  29894. }
  29895. viewClass = viewName ? container.lookupFactory(viewFullName) : options.hash.viewClass || Handlebars.OutletView;
  29896. options.data.view.set('outletSource', outletSource);
  29897. options.hash.currentViewBinding = '_view.outletSource._outlets.' + property;
  29898. return Handlebars.helpers.view.call(this, viewClass, options);
  29899. });
  29900. });
  29901. })();
  29902. (function() {
  29903. /**
  29904. @module ember
  29905. @submodule ember-routing
  29906. */
  29907. var get = Ember.get, set = Ember.set;
  29908. Ember.onLoad('Ember.Handlebars', function(Handlebars) {
  29909. /**
  29910. Calling ``{{render}}`` from within a template will insert another
  29911. template that matches the provided name. The inserted template will
  29912. access its properties on its own controller (rather than the controller
  29913. of the parent template).
  29914. If a view class with the same name exists, the view class also will be used.
  29915. Note: A given controller may only be used *once* in your app in this manner.
  29916. A singleton instance of the controller will be created for you.
  29917. Example:
  29918. ```javascript
  29919. App.NavigationController = Ember.Controller.extend({
  29920. who: "world"
  29921. });
  29922. ```
  29923. ```handlebars
  29924. <!-- navigation.hbs -->
  29925. Hello, {{who}}.
  29926. ```
  29927. ```handelbars
  29928. <!-- application.hbs -->
  29929. <h1>My great app</h1>
  29930. {{render "navigation"}}
  29931. ```
  29932. ```html
  29933. <h1>My great app</h1>
  29934. <div class='ember-view'>
  29935. Hello, world.
  29936. </div>
  29937. ```
  29938. Optionally you may provide a second argument: a property path
  29939. that will be bound to the `model` property of the controller.
  29940. If a `model` property path is specified, then a new instance of the
  29941. controller will be created and `{{render}}` can be used multiple times
  29942. with the same name.
  29943. For example if you had this `author` template.
  29944. ```handlebars
  29945. <div class="author">
  29946. Written by {{firstName}} {{lastName}}.
  29947. Total Posts: {{postCount}}
  29948. </div>
  29949. ```
  29950. You could render it inside the `post` template using the `render` helper.
  29951. ```handlebars
  29952. <div class="post">
  29953. <h1>{{title}}</h1>
  29954. <div>{{body}}</div>
  29955. {{render "author" author}}
  29956. </div>
  29957. ```
  29958. @method render
  29959. @for Ember.Handlebars.helpers
  29960. @param {String} name
  29961. @param {Object?} contextString
  29962. @param {Hash} options
  29963. @return {String} HTML string
  29964. */
  29965. Ember.Handlebars.registerHelper('render', function renderHelper(name, contextString, options) {
  29966. var length = arguments.length;
  29967. var contextProvided = length === 3,
  29968. container, router, controller, view, context, lookupOptions;
  29969. container = (options || contextString).data.keywords.controller.container;
  29970. router = container.lookup('router:main');
  29971. if (length === 2) {
  29972. // use the singleton controller
  29973. options = contextString;
  29974. contextString = undefined;
  29975. Ember.assert("You can only use the {{render}} helper once without a model object as its second argument, as in {{render \"post\" post}}.", !router || !router._lookupActiveView(name));
  29976. } else if (length === 3) {
  29977. // create a new controller
  29978. context = Ember.Handlebars.get(options.contexts[1], contextString, options);
  29979. } else {
  29980. throw Ember.Error("You must pass a templateName to render");
  29981. }
  29982. Ember.deprecate("Using a quoteless parameter with {{render}} is deprecated. Please update to quoted usage '{{render \"" + name + "\"}}.", options.types[0] !== 'ID');
  29983. // # legacy namespace
  29984. name = name.replace(/\//g, '.');
  29985. // \ legacy slash as namespace support
  29986. view = container.lookup('view:' + name) || container.lookup('view:default');
  29987. // provide controller override
  29988. var controllerName = options.hash.controller || name;
  29989. var controllerFullName = 'controller:' + controllerName;
  29990. if (options.hash.controller) {
  29991. Ember.assert("The controller name you supplied '" + controllerName + "' did not resolve to a controller.", container.has(controllerFullName));
  29992. }
  29993. var parentController = options.data.keywords.controller;
  29994. // choose name
  29995. if (length > 2) {
  29996. var factory = container.lookupFactory(controllerFullName) ||
  29997. Ember.generateControllerFactory(container, controllerName, context);
  29998. controller = factory.create({
  29999. model: context,
  30000. parentController: parentController,
  30001. target: parentController
  30002. });
  30003. } else {
  30004. controller = container.lookup(controllerFullName) ||
  30005. Ember.generateController(container, controllerName);
  30006. controller.setProperties({
  30007. target: parentController,
  30008. parentController: parentController
  30009. });
  30010. }
  30011. var root = options.contexts[1];
  30012. if (root) {
  30013. view.registerObserver(root, contextString, function() {
  30014. controller.set('model', Ember.Handlebars.get(root, contextString, options));
  30015. });
  30016. }
  30017. options.hash.viewName = Ember.String.camelize(name);
  30018. var templateName = 'template:' + name;
  30019. Ember.assert("You used `{{render '" + name + "'}}`, but '" + name + "' can not be found as either a template or a view.", container.has("view:" + name) || container.has(templateName) || options.fn);
  30020. options.hash.template = container.lookup(templateName);
  30021. options.hash.controller = controller;
  30022. if (router && !context) {
  30023. router._connectActiveView(name, view);
  30024. }
  30025. Ember.Handlebars.helpers.view.call(this, view, options);
  30026. });
  30027. });
  30028. })();
  30029. (function() {
  30030. /**
  30031. @module ember
  30032. @submodule ember-routing
  30033. */
  30034. Ember.onLoad('Ember.Handlebars', function(Handlebars) {
  30035. var resolveParams = Ember.Router.resolveParams,
  30036. isSimpleClick = Ember.ViewUtils.isSimpleClick;
  30037. var EmberHandlebars = Ember.Handlebars,
  30038. handlebarsGet = EmberHandlebars.get,
  30039. SafeString = EmberHandlebars.SafeString,
  30040. forEach = Ember.ArrayPolyfills.forEach,
  30041. get = Ember.get,
  30042. a_slice = Array.prototype.slice;
  30043. function args(options, actionName) {
  30044. var ret = [];
  30045. if (actionName) { ret.push(actionName); }
  30046. var types = options.options.types.slice(1),
  30047. data = options.options.data;
  30048. return ret.concat(resolveParams(options.context, options.params, { types: types, data: data }));
  30049. }
  30050. var ActionHelper = EmberHandlebars.ActionHelper = {
  30051. registeredActions: {}
  30052. };
  30053. var keys = ["alt", "shift", "meta", "ctrl"];
  30054. var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/;
  30055. var isAllowedEvent = function(event, allowedKeys) {
  30056. if (typeof allowedKeys === "undefined") {
  30057. if (POINTER_EVENT_TYPE_REGEX.test(event.type)) {
  30058. return isSimpleClick(event);
  30059. } else {
  30060. allowedKeys = '';
  30061. }
  30062. }
  30063. if (allowedKeys.indexOf("any") >= 0) {
  30064. return true;
  30065. }
  30066. var allowed = true;
  30067. forEach.call(keys, function(key) {
  30068. if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) {
  30069. allowed = false;
  30070. }
  30071. });
  30072. return allowed;
  30073. };
  30074. ActionHelper.registerAction = function(actionName, options, allowedKeys) {
  30075. var actionId = (++Ember.uuid).toString();
  30076. ActionHelper.registeredActions[actionId] = {
  30077. eventName: options.eventName,
  30078. handler: function handleRegisteredAction(event) {
  30079. if (!isAllowedEvent(event, allowedKeys)) { return true; }
  30080. if (options.preventDefault !== false) {
  30081. event.preventDefault();
  30082. }
  30083. if (options.bubbles === false) {
  30084. event.stopPropagation();
  30085. }
  30086. var target = options.target;
  30087. if (target.target) {
  30088. target = handlebarsGet(target.root, target.target, target.options);
  30089. } else {
  30090. target = target.root;
  30091. }
  30092. if (options.boundProperty) {
  30093. Ember.deprecate("Using a quoteless parameter with {{action}} is deprecated. Please update to quoted usage '{{action \"" + actionName + "\"}}.", false);
  30094. }
  30095. Ember.run(function runRegisteredAction() {
  30096. if (target.send) {
  30097. target.send.apply(target, args(options.parameters, actionName));
  30098. } else {
  30099. Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function');
  30100. target[actionName].apply(target, args(options.parameters));
  30101. }
  30102. });
  30103. }
  30104. };
  30105. options.view.on('willClearRender', function() {
  30106. delete ActionHelper.registeredActions[actionId];
  30107. });
  30108. return actionId;
  30109. };
  30110. /**
  30111. The `{{action}}` helper registers an HTML element within a template for DOM
  30112. event handling and forwards that interaction to the templates's controller
  30113. or supplied `target` option (see 'Specifying a Target').
  30114. If the controller does not implement the event, the event is sent
  30115. to the current route, and it bubbles up the route hierarchy from there.
  30116. User interaction with that element will invoke the supplied action name on
  30117. the appropriate target.
  30118. Given the following application Handlebars template on the page
  30119. ```handlebars
  30120. <div {{action 'anActionName'}}>
  30121. click me
  30122. </div>
  30123. ```
  30124. And application code
  30125. ```javascript
  30126. App.ApplicationController = Ember.Controller.extend({
  30127. actions: {
  30128. anActionName: function() {
  30129. }
  30130. }
  30131. });
  30132. ```
  30133. Will result in the following rendered HTML
  30134. ```html
  30135. <div class="ember-view">
  30136. <div data-ember-action="1">
  30137. click me
  30138. </div>
  30139. </div>
  30140. ```
  30141. Clicking "click me" will trigger the `anActionName` action of the
  30142. `App.ApplicationController`. In this case, no additional parameters will be passed.
  30143. If you provide additional parameters to the helper:
  30144. ```handlebars
  30145. <button {{action 'edit' post}}>Edit</button>
  30146. ```
  30147. Those parameters will be passed along as arguments to the JavaScript
  30148. function implementing the action.
  30149. ### Event Propagation
  30150. Events triggered through the action helper will automatically have
  30151. `.preventDefault()` called on them. You do not need to do so in your event
  30152. handlers. If you need to allow event propagation (to handle file inputs for
  30153. example) you can supply the `preventDefault=false` option to the `{{action}}` helper:
  30154. ```handlebars
  30155. <div {{action "sayHello" preventDefault=false}}>
  30156. <input type="file" />
  30157. <input type="checkbox" />
  30158. </div>
  30159. ```
  30160. To disable bubbling, pass `bubbles=false` to the helper:
  30161. ```handlebars
  30162. <button {{action 'edit' post bubbles=false}}>Edit</button>
  30163. ```
  30164. If you need the default handler to trigger you should either register your
  30165. own event handler, or use event methods on your view class. See [Ember.View](/api/classes/Ember.View.html)
  30166. 'Responding to Browser Events' for more information.
  30167. ### Specifying DOM event type
  30168. By default the `{{action}}` helper registers for DOM `click` events. You can
  30169. supply an `on` option to the helper to specify a different DOM event name:
  30170. ```handlebars
  30171. <div {{action "anActionName" on="doubleClick"}}>
  30172. click me
  30173. </div>
  30174. ```
  30175. See `Ember.View` 'Responding to Browser Events' for a list of
  30176. acceptable DOM event names.
  30177. NOTE: Because `{{action}}` depends on Ember's event dispatch system it will
  30178. only function if an `Ember.EventDispatcher` instance is available. An
  30179. `Ember.EventDispatcher` instance will be created when a new `Ember.Application`
  30180. is created. Having an instance of `Ember.Application` will satisfy this
  30181. requirement.
  30182. ### Specifying whitelisted modifier keys
  30183. By default the `{{action}}` helper will ignore click event with pressed modifier
  30184. keys. You can supply an `allowedKeys` option to specify which keys should not be ignored.
  30185. ```handlebars
  30186. <div {{action "anActionName" allowedKeys="alt"}}>
  30187. click me
  30188. </div>
  30189. ```
  30190. This way the `{{action}}` will fire when clicking with the alt key pressed down.
  30191. Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys.
  30192. ```handlebars
  30193. <div {{action "anActionName" allowedKeys="any"}}>
  30194. click me with any key pressed
  30195. </div>
  30196. ```
  30197. ### Specifying a Target
  30198. There are several possible target objects for `{{action}}` helpers:
  30199. In a typical Ember application, where views are managed through use of the
  30200. `{{outlet}}` helper, actions will bubble to the current controller, then
  30201. to the current route, and then up the route hierarchy.
  30202. Alternatively, a `target` option can be provided to the helper to change
  30203. which object will receive the method call. This option must be a path
  30204. to an object, accessible in the current context:
  30205. ```handlebars
  30206. {{! the application template }}
  30207. <div {{action "anActionName" target=view}}>
  30208. click me
  30209. </div>
  30210. ```
  30211. ```javascript
  30212. App.ApplicationView = Ember.View.extend({
  30213. actions: {
  30214. anActionName: function(){}
  30215. }
  30216. });
  30217. ```
  30218. ### Additional Parameters
  30219. You may specify additional parameters to the `{{action}}` helper. These
  30220. parameters are passed along as the arguments to the JavaScript function
  30221. implementing the action.
  30222. ```handlebars
  30223. {{#each person in people}}
  30224. <div {{action "edit" person}}>
  30225. click me
  30226. </div>
  30227. {{/each}}
  30228. ```
  30229. Clicking "click me" will trigger the `edit` method on the current controller
  30230. with the value of `person` as a parameter.
  30231. @method action
  30232. @for Ember.Handlebars.helpers
  30233. @param {String} actionName
  30234. @param {Object} [context]*
  30235. @param {Hash} options
  30236. */
  30237. EmberHandlebars.registerHelper('action', function actionHelper(actionName) {
  30238. var options = arguments[arguments.length - 1],
  30239. contexts = a_slice.call(arguments, 1, -1);
  30240. var hash = options.hash,
  30241. controller;
  30242. // create a hash to pass along to registerAction
  30243. var action = {
  30244. eventName: hash.on || "click"
  30245. };
  30246. action.parameters = {
  30247. context: this,
  30248. options: options,
  30249. params: contexts
  30250. };
  30251. action.view = options.data.view;
  30252. var root, target;
  30253. if (hash.target) {
  30254. root = this;
  30255. target = hash.target;
  30256. } else if (controller = options.data.keywords.controller) {
  30257. root = controller;
  30258. }
  30259. action.target = { root: root, target: target, options: options };
  30260. action.bubbles = hash.bubbles;
  30261. action.preventDefault = hash.preventDefault;
  30262. action.boundProperty = options.types[0] === "ID";
  30263. var actionId = ActionHelper.registerAction(actionName, action, hash.allowedKeys);
  30264. return new SafeString('data-ember-action="' + actionId + '"');
  30265. });
  30266. });
  30267. })();
  30268. (function() {
  30269. })();
  30270. (function() {
  30271. /**
  30272. @module ember
  30273. @submodule ember-routing
  30274. */
  30275. var get = Ember.get, set = Ember.set,
  30276. map = Ember.EnumerableUtils.map;
  30277. var queuedQueryParamChanges = {};
  30278. Ember.ControllerMixin.reopen({
  30279. /**
  30280. Transition the application into another route. The route may
  30281. be either a single route or route path:
  30282. ```javascript
  30283. aController.transitionToRoute('blogPosts');
  30284. aController.transitionToRoute('blogPosts.recentEntries');
  30285. ```
  30286. Optionally supply a model for the route in question. The model
  30287. will be serialized into the URL using the `serialize` hook of
  30288. the route:
  30289. ```javascript
  30290. aController.transitionToRoute('blogPost', aPost);
  30291. ```
  30292. Multiple models will be applied last to first recursively up the
  30293. resource tree.
  30294. ```javascript
  30295. this.resource('blogPost', {path:':blogPostId'}, function(){
  30296. this.resource('blogComment', {path: ':blogCommentId'});
  30297. });
  30298. aController.transitionToRoute('blogComment', aPost, aComment);
  30299. ```
  30300. See also 'replaceRoute'.
  30301. @param {String} name the name of the route
  30302. @param {...Object} models the model(s) to be used while transitioning
  30303. to the route.
  30304. @for Ember.ControllerMixin
  30305. @method transitionToRoute
  30306. */
  30307. transitionToRoute: function() {
  30308. // target may be either another controller or a router
  30309. var target = get(this, 'target'),
  30310. method = target.transitionToRoute || target.transitionTo;
  30311. return method.apply(target, arguments);
  30312. },
  30313. /**
  30314. @deprecated
  30315. @for Ember.ControllerMixin
  30316. @method transitionTo
  30317. */
  30318. transitionTo: function() {
  30319. Ember.deprecate("transitionTo is deprecated. Please use transitionToRoute.");
  30320. return this.transitionToRoute.apply(this, arguments);
  30321. },
  30322. /**
  30323. Transition into another route while replacing the current URL, if possible.
  30324. This will replace the current history entry instead of adding a new one.
  30325. Beside that, it is identical to `transitionToRoute` in all other respects.
  30326. ```javascript
  30327. aController.replaceRoute('blogPosts');
  30328. aController.replaceRoute('blogPosts.recentEntries');
  30329. ```
  30330. Optionally supply a model for the route in question. The model
  30331. will be serialized into the URL using the `serialize` hook of
  30332. the route:
  30333. ```javascript
  30334. aController.replaceRoute('blogPost', aPost);
  30335. ```
  30336. Multiple models will be applied last to first recursively up the
  30337. resource tree.
  30338. ```javascript
  30339. this.resource('blogPost', {path:':blogPostId'}, function(){
  30340. this.resource('blogComment', {path: ':blogCommentId'});
  30341. });
  30342. aController.replaceRoute('blogComment', aPost, aComment);
  30343. ```
  30344. @param {String} name the name of the route
  30345. @param {...Object} models the model(s) to be used while transitioning
  30346. to the route.
  30347. @for Ember.ControllerMixin
  30348. @method replaceRoute
  30349. */
  30350. replaceRoute: function() {
  30351. // target may be either another controller or a router
  30352. var target = get(this, 'target'),
  30353. method = target.replaceRoute || target.replaceWith;
  30354. return method.apply(target, arguments);
  30355. },
  30356. /**
  30357. @deprecated
  30358. @for Ember.ControllerMixin
  30359. @method replaceWith
  30360. */
  30361. replaceWith: function() {
  30362. Ember.deprecate("replaceWith is deprecated. Please use replaceRoute.");
  30363. return this.replaceRoute.apply(this, arguments);
  30364. }
  30365. });
  30366. })();
  30367. (function() {
  30368. /**
  30369. @module ember
  30370. @submodule ember-routing
  30371. */
  30372. var get = Ember.get, set = Ember.set;
  30373. Ember.View.reopen({
  30374. /**
  30375. Sets the private `_outlets` object on the view.
  30376. @method init
  30377. */
  30378. init: function() {
  30379. set(this, '_outlets', {});
  30380. this._super();
  30381. },
  30382. /**
  30383. Manually fill any of a view's `{{outlet}}` areas with the
  30384. supplied view.
  30385. Example
  30386. ```javascript
  30387. var MyView = Ember.View.extend({
  30388. template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ')
  30389. });
  30390. var myView = MyView.create();
  30391. myView.appendTo('body');
  30392. // The html for myView now looks like:
  30393. // <div id="ember228" class="ember-view">Child view: </div>
  30394. var FooView = Ember.View.extend({
  30395. template: Ember.Handlebars.compile('<h1>Foo</h1> ')
  30396. });
  30397. var fooView = FooView.create();
  30398. myView.connectOutlet('main', fooView);
  30399. // The html for myView now looks like:
  30400. // <div id="ember228" class="ember-view">Child view:
  30401. // <div id="ember234" class="ember-view"><h1>Foo</h1> </div>
  30402. // </div>
  30403. ```
  30404. @method connectOutlet
  30405. @param {String} outletName A unique name for the outlet
  30406. @param {Object} view An Ember.View
  30407. */
  30408. connectOutlet: function(outletName, view) {
  30409. if (this._pendingDisconnections) {
  30410. delete this._pendingDisconnections[outletName];
  30411. }
  30412. if (this._hasEquivalentView(outletName, view)) {
  30413. view.destroy();
  30414. return;
  30415. }
  30416. var outlets = get(this, '_outlets'),
  30417. container = get(this, 'container'),
  30418. router = container && container.lookup('router:main'),
  30419. renderedName = get(view, 'renderedName');
  30420. set(outlets, outletName, view);
  30421. if (router && renderedName) {
  30422. router._connectActiveView(renderedName, view);
  30423. }
  30424. },
  30425. /**
  30426. Determines if the view has already been created by checking if
  30427. the view has the same constructor, template, and context as the
  30428. view in the `_outlets` object.
  30429. @private
  30430. @method _hasEquivalentView
  30431. @param {String} outletName The name of the outlet we are checking
  30432. @param {Object} view An Ember.View
  30433. @return {Boolean}
  30434. */
  30435. _hasEquivalentView: function(outletName, view) {
  30436. var existingView = get(this, '_outlets.'+outletName);
  30437. return existingView &&
  30438. existingView.constructor === view.constructor &&
  30439. existingView.get('template') === view.get('template') &&
  30440. existingView.get('context') === view.get('context');
  30441. },
  30442. /**
  30443. Removes an outlet from the view.
  30444. Example
  30445. ```javascript
  30446. var MyView = Ember.View.extend({
  30447. template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ')
  30448. });
  30449. var myView = MyView.create();
  30450. myView.appendTo('body');
  30451. // myView's html:
  30452. // <div id="ember228" class="ember-view">Child view: </div>
  30453. var FooView = Ember.View.extend({
  30454. template: Ember.Handlebars.compile('<h1>Foo</h1> ')
  30455. });
  30456. var fooView = FooView.create();
  30457. myView.connectOutlet('main', fooView);
  30458. // myView's html:
  30459. // <div id="ember228" class="ember-view">Child view:
  30460. // <div id="ember234" class="ember-view"><h1>Foo</h1> </div>
  30461. // </div>
  30462. myView.disconnectOutlet('main');
  30463. // myView's html:
  30464. // <div id="ember228" class="ember-view">Child view: </div>
  30465. ```
  30466. @method disconnectOutlet
  30467. @param {String} outletName The name of the outlet to be removed
  30468. */
  30469. disconnectOutlet: function(outletName) {
  30470. if (!this._pendingDisconnections) {
  30471. this._pendingDisconnections = {};
  30472. }
  30473. this._pendingDisconnections[outletName] = true;
  30474. Ember.run.once(this, '_finishDisconnections');
  30475. },
  30476. /**
  30477. Gets an outlet that is pending disconnection and then
  30478. nullifys the object on the `_outlet` object.
  30479. @private
  30480. @method _finishDisconnections
  30481. */
  30482. _finishDisconnections: function() {
  30483. if (this.isDestroyed) return; // _outlets will be gone anyway
  30484. var outlets = get(this, '_outlets');
  30485. var pendingDisconnections = this._pendingDisconnections;
  30486. this._pendingDisconnections = null;
  30487. for (var outletName in pendingDisconnections) {
  30488. set(outlets, outletName, null);
  30489. }
  30490. }
  30491. });
  30492. })();
  30493. (function() {
  30494. /**
  30495. @module ember
  30496. @submodule ember-views
  30497. */
  30498. // Add a new named queue after the 'actions' queue (where RSVP promises
  30499. // resolve), which is used in router transitions to prevent unnecessary
  30500. // loading state entry if all context promises resolve on the
  30501. // 'actions' queue first.
  30502. var queues = Ember.run.queues,
  30503. indexOf = Ember.ArrayPolyfills.indexOf;
  30504. queues.splice(indexOf.call(queues, 'actions') + 1, 0, 'routerTransitions');
  30505. })();
  30506. (function() {
  30507. /**
  30508. @module ember
  30509. @submodule ember-routing
  30510. */
  30511. var get = Ember.get, set = Ember.set;
  30512. /**
  30513. Ember.Location returns an instance of the correct implementation of
  30514. the `location` API.
  30515. ## Implementations
  30516. You can pass an implementation name (`hash`, `history`, `none`) to force a
  30517. particular implementation to be used in your application.
  30518. ### HashLocation
  30519. Using `HashLocation` results in URLs with a `#` (hash sign) separating the
  30520. server side URL portion of the URL from the portion that is used by Ember.
  30521. This relies upon the `hashchange` event existing in the browser.
  30522. Example:
  30523. ```javascript
  30524. App.Router.map(function() {
  30525. this.resource('posts', function() {
  30526. this.route('new');
  30527. });
  30528. });
  30529. App.Router.reopen({
  30530. location: 'hash'
  30531. });
  30532. ```
  30533. This will result in a posts.new url of `/#/posts/new`.
  30534. ### HistoryLocation
  30535. Using `HistoryLocation` results in URLs that are indistinguishable from a
  30536. standard URL. This relies upon the browser's `history` API.
  30537. Example:
  30538. ```javascript
  30539. App.Router.map(function() {
  30540. this.resource('posts', function() {
  30541. this.route('new');
  30542. });
  30543. });
  30544. App.Router.reopen({
  30545. location: 'history'
  30546. });
  30547. ```
  30548. This will result in a posts.new url of `/posts/new`.
  30549. ### NoneLocation
  30550. Using `NoneLocation` causes Ember to not store the applications URL state
  30551. in the actual URL. This is generally used for testing purposes, and is one
  30552. of the changes made when calling `App.setupForTesting()`.
  30553. ## Location API
  30554. Each location implementation must provide the following methods:
  30555. * implementation: returns the string name used to reference the implementation.
  30556. * getURL: returns the current URL.
  30557. * setURL(path): sets the current URL.
  30558. * replaceURL(path): replace the current URL (optional).
  30559. * onUpdateURL(callback): triggers the callback when the URL changes.
  30560. * formatURL(url): formats `url` to be placed into `href` attribute.
  30561. Calling setURL or replaceURL will not trigger onUpdateURL callbacks.
  30562. @class Location
  30563. @namespace Ember
  30564. @static
  30565. */
  30566. Ember.Location = {
  30567. /**
  30568. This is deprecated in favor of using the container to lookup the location
  30569. implementation as desired.
  30570. For example:
  30571. ```javascript
  30572. // Given a location registered as follows:
  30573. container.register('location:history-test', HistoryTestLocation);
  30574. // You could create a new instance via:
  30575. container.lookup('location:history-test');
  30576. ```
  30577. @method create
  30578. @param {Object} options
  30579. @return {Object} an instance of an implementation of the `location` API
  30580. @deprecated Use the container to lookup the location implementation that you
  30581. need.
  30582. */
  30583. create: function(options) {
  30584. var implementation = options && options.implementation;
  30585. Ember.assert("Ember.Location.create: you must specify a 'implementation' option", !!implementation);
  30586. var implementationClass = this.implementations[implementation];
  30587. Ember.assert("Ember.Location.create: " + implementation + " is not a valid implementation", !!implementationClass);
  30588. return implementationClass.create.apply(implementationClass, arguments);
  30589. },
  30590. /**
  30591. This is deprecated in favor of using the container to register the
  30592. location implementation as desired.
  30593. Example:
  30594. ```javascript
  30595. Application.initializer({
  30596. name: "history-test-location",
  30597. initialize: function(container, application) {
  30598. application.register('location:history-test', HistoryTestLocation);
  30599. }
  30600. });
  30601. ```
  30602. @method registerImplementation
  30603. @param {String} name
  30604. @param {Object} implementation of the `location` API
  30605. @deprecated Register your custom location implementation with the
  30606. container directly.
  30607. */
  30608. registerImplementation: function(name, implementation) {
  30609. Ember.deprecate('Using the Ember.Location.registerImplementation is no longer supported. Register your custom location implementation with the container instead.', false);
  30610. this.implementations[name] = implementation;
  30611. },
  30612. implementations: {},
  30613. /**
  30614. Returns the current `location.hash` by parsing location.href since browsers
  30615. inconsistently URL-decode `location.hash`.
  30616. https://bugzilla.mozilla.org/show_bug.cgi?id=483304
  30617. @private
  30618. @method getHash
  30619. */
  30620. getHash: function () {
  30621. var href = window.location.href,
  30622. hashIndex = href.indexOf('#');
  30623. if (hashIndex === -1) {
  30624. return '';
  30625. } else {
  30626. return href.substr(hashIndex);
  30627. }
  30628. }
  30629. };
  30630. })();
  30631. (function() {
  30632. /**
  30633. @module ember
  30634. @submodule ember-routing
  30635. */
  30636. var get = Ember.get, set = Ember.set;
  30637. /**
  30638. Ember.NoneLocation does not interact with the browser. It is useful for
  30639. testing, or when you need to manage state with your Router, but temporarily
  30640. don't want it to muck with the URL (for example when you embed your
  30641. application in a larger page).
  30642. @class NoneLocation
  30643. @namespace Ember
  30644. @extends Ember.Object
  30645. */
  30646. Ember.NoneLocation = Ember.Object.extend({
  30647. implementation: 'none',
  30648. path: '',
  30649. /**
  30650. Returns the current path.
  30651. @private
  30652. @method getURL
  30653. @return {String} path
  30654. */
  30655. getURL: function() {
  30656. return get(this, 'path');
  30657. },
  30658. /**
  30659. Set the path and remembers what was set. Using this method
  30660. to change the path will not invoke the `updateURL` callback.
  30661. @private
  30662. @method setURL
  30663. @param path {String}
  30664. */
  30665. setURL: function(path) {
  30666. set(this, 'path', path);
  30667. },
  30668. /**
  30669. Register a callback to be invoked when the path changes. These
  30670. callbacks will execute when the user presses the back or forward
  30671. button, but not after `setURL` is invoked.
  30672. @private
  30673. @method onUpdateURL
  30674. @param callback {Function}
  30675. */
  30676. onUpdateURL: function(callback) {
  30677. this.updateCallback = callback;
  30678. },
  30679. /**
  30680. Sets the path and calls the `updateURL` callback.
  30681. @private
  30682. @method handleURL
  30683. @param callback {Function}
  30684. */
  30685. handleURL: function(url) {
  30686. set(this, 'path', url);
  30687. this.updateCallback(url);
  30688. },
  30689. /**
  30690. Given a URL, formats it to be placed into the page as part
  30691. of an element's `href` attribute.
  30692. This is used, for example, when using the {{action}} helper
  30693. to generate a URL based on an event.
  30694. @private
  30695. @method formatURL
  30696. @param url {String}
  30697. @return {String} url
  30698. */
  30699. formatURL: function(url) {
  30700. // The return value is not overly meaningful, but we do not want to throw
  30701. // errors when test code renders templates containing {{action href=true}}
  30702. // helpers.
  30703. return url;
  30704. }
  30705. });
  30706. })();
  30707. (function() {
  30708. /**
  30709. @module ember
  30710. @submodule ember-routing
  30711. */
  30712. var get = Ember.get, set = Ember.set,
  30713. getHash = Ember.Location.getHash;
  30714. /**
  30715. `Ember.HashLocation` implements the location API using the browser's
  30716. hash. At present, it relies on a `hashchange` event existing in the
  30717. browser.
  30718. @class HashLocation
  30719. @namespace Ember
  30720. @extends Ember.Object
  30721. */
  30722. Ember.HashLocation = Ember.Object.extend({
  30723. implementation: 'hash',
  30724. init: function() {
  30725. set(this, 'location', get(this, 'location') || window.location);
  30726. },
  30727. /**
  30728. Returns the current `location.hash`, minus the '#' at the front.
  30729. @private
  30730. @method getURL
  30731. */
  30732. getURL: function() {
  30733. return getHash().substr(1);
  30734. },
  30735. /**
  30736. Set the `location.hash` and remembers what was set. This prevents
  30737. `onUpdateURL` callbacks from triggering when the hash was set by
  30738. `HashLocation`.
  30739. @private
  30740. @method setURL
  30741. @param path {String}
  30742. */
  30743. setURL: function(path) {
  30744. get(this, 'location').hash = path;
  30745. set(this, 'lastSetURL', path);
  30746. },
  30747. /**
  30748. Uses location.replace to update the url without a page reload
  30749. or history modification.
  30750. @private
  30751. @method replaceURL
  30752. @param path {String}
  30753. */
  30754. replaceURL: function(path) {
  30755. get(this, 'location').replace('#' + path);
  30756. set(this, 'lastSetURL', path);
  30757. },
  30758. /**
  30759. Register a callback to be invoked when the hash changes. These
  30760. callbacks will execute when the user presses the back or forward
  30761. button, but not after `setURL` is invoked.
  30762. @private
  30763. @method onUpdateURL
  30764. @param callback {Function}
  30765. */
  30766. onUpdateURL: function(callback) {
  30767. var self = this;
  30768. var guid = Ember.guidFor(this);
  30769. Ember.$(window).on('hashchange.ember-location-'+guid, function() {
  30770. Ember.run(function() {
  30771. var path = self.getURL();
  30772. if (get(self, 'lastSetURL') === path) { return; }
  30773. set(self, 'lastSetURL', null);
  30774. callback(path);
  30775. });
  30776. });
  30777. },
  30778. /**
  30779. Given a URL, formats it to be placed into the page as part
  30780. of an element's `href` attribute.
  30781. This is used, for example, when using the {{action}} helper
  30782. to generate a URL based on an event.
  30783. @private
  30784. @method formatURL
  30785. @param url {String}
  30786. */
  30787. formatURL: function(url) {
  30788. return '#'+url;
  30789. },
  30790. /**
  30791. Cleans up the HashLocation event listener.
  30792. @private
  30793. @method willDestroy
  30794. */
  30795. willDestroy: function() {
  30796. var guid = Ember.guidFor(this);
  30797. Ember.$(window).off('hashchange.ember-location-'+guid);
  30798. }
  30799. });
  30800. })();
  30801. (function() {
  30802. /**
  30803. @module ember
  30804. @submodule ember-routing
  30805. */
  30806. var get = Ember.get, set = Ember.set;
  30807. var popstateFired = false;
  30808. var supportsHistoryState = window.history && 'state' in window.history;
  30809. /**
  30810. Ember.HistoryLocation implements the location API using the browser's
  30811. history.pushState API.
  30812. @class HistoryLocation
  30813. @namespace Ember
  30814. @extends Ember.Object
  30815. */
  30816. Ember.HistoryLocation = Ember.Object.extend({
  30817. implementation: 'history',
  30818. init: function() {
  30819. set(this, 'location', get(this, 'location') || window.location);
  30820. set(this, 'baseURL', Ember.$('base').attr('href') || '');
  30821. },
  30822. /**
  30823. Used to set state on first call to setURL
  30824. @private
  30825. @method initState
  30826. */
  30827. initState: function() {
  30828. set(this, 'history', get(this, 'history') || window.history);
  30829. this.replaceState(this.formatURL(this.getURL()));
  30830. },
  30831. /**
  30832. Will be pre-pended to path upon state change
  30833. @property rootURL
  30834. @default '/'
  30835. */
  30836. rootURL: '/',
  30837. /**
  30838. Returns the current `location.pathname` without `rootURL`.
  30839. @private
  30840. @method getURL
  30841. @return url {String}
  30842. */
  30843. getURL: function() {
  30844. var rootURL = get(this, 'rootURL'),
  30845. location = get(this, 'location'),
  30846. path = location.pathname,
  30847. baseURL = get(this, 'baseURL');
  30848. rootURL = rootURL.replace(/\/$/, '');
  30849. baseURL = baseURL.replace(/\/$/, '');
  30850. var url = path.replace(baseURL, '').replace(rootURL, '');
  30851. return url;
  30852. },
  30853. /**
  30854. Uses `history.pushState` to update the url without a page reload.
  30855. @private
  30856. @method setURL
  30857. @param path {String}
  30858. */
  30859. setURL: function(path) {
  30860. var state = this.getState();
  30861. path = this.formatURL(path);
  30862. if (state && state.path !== path) {
  30863. this.pushState(path);
  30864. }
  30865. },
  30866. /**
  30867. Uses `history.replaceState` to update the url without a page reload
  30868. or history modification.
  30869. @private
  30870. @method replaceURL
  30871. @param path {String}
  30872. */
  30873. replaceURL: function(path) {
  30874. var state = this.getState();
  30875. path = this.formatURL(path);
  30876. if (state && state.path !== path) {
  30877. this.replaceState(path);
  30878. }
  30879. },
  30880. /**
  30881. Get the current `history.state`
  30882. Polyfill checks for native browser support and falls back to retrieving
  30883. from a private _historyState variable
  30884. @private
  30885. @method getState
  30886. @return state {Object}
  30887. */
  30888. getState: function() {
  30889. return supportsHistoryState ? get(this, 'history').state : this._historyState;
  30890. },
  30891. /**
  30892. Pushes a new state.
  30893. @private
  30894. @method pushState
  30895. @param path {String}
  30896. */
  30897. pushState: function(path) {
  30898. var state = { path: path };
  30899. get(this, 'history').pushState(state, null, path);
  30900. // store state if browser doesn't support `history.state`
  30901. if (!supportsHistoryState) {
  30902. this._historyState = state;
  30903. }
  30904. // used for webkit workaround
  30905. this._previousURL = this.getURL();
  30906. },
  30907. /**
  30908. Replaces the current state.
  30909. @private
  30910. @method replaceState
  30911. @param path {String}
  30912. */
  30913. replaceState: function(path) {
  30914. var state = { path: path };
  30915. get(this, 'history').replaceState(state, null, path);
  30916. // store state if browser doesn't support `history.state`
  30917. if (!supportsHistoryState) {
  30918. this._historyState = state;
  30919. }
  30920. // used for webkit workaround
  30921. this._previousURL = this.getURL();
  30922. },
  30923. /**
  30924. Register a callback to be invoked whenever the browser
  30925. history changes, including using forward and back buttons.
  30926. @private
  30927. @method onUpdateURL
  30928. @param callback {Function}
  30929. */
  30930. onUpdateURL: function(callback) {
  30931. var guid = Ember.guidFor(this),
  30932. self = this;
  30933. Ember.$(window).on('popstate.ember-location-'+guid, function(e) {
  30934. // Ignore initial page load popstate event in Chrome
  30935. if (!popstateFired) {
  30936. popstateFired = true;
  30937. if (self.getURL() === self._previousURL) { return; }
  30938. }
  30939. callback(self.getURL());
  30940. });
  30941. },
  30942. /**
  30943. Used when using `{{action}}` helper. The url is always appended to the rootURL.
  30944. @private
  30945. @method formatURL
  30946. @param url {String}
  30947. @return formatted url {String}
  30948. */
  30949. formatURL: function(url) {
  30950. var rootURL = get(this, 'rootURL'),
  30951. baseURL = get(this, 'baseURL');
  30952. if (url !== '') {
  30953. rootURL = rootURL.replace(/\/$/, '');
  30954. baseURL = baseURL.replace(/\/$/, '');
  30955. } else if(baseURL.match(/^\//) && rootURL.match(/^\//)) {
  30956. baseURL = baseURL.replace(/\/$/, '');
  30957. }
  30958. return baseURL + rootURL + url;
  30959. },
  30960. /**
  30961. Cleans up the HistoryLocation event listener.
  30962. @private
  30963. @method willDestroy
  30964. */
  30965. willDestroy: function() {
  30966. var guid = Ember.guidFor(this);
  30967. Ember.$(window).off('popstate.ember-location-'+guid);
  30968. }
  30969. });
  30970. })();
  30971. (function() {
  30972. })();
  30973. (function() {
  30974. /**
  30975. Ember Routing
  30976. @module ember
  30977. @submodule ember-routing
  30978. @requires ember-views
  30979. */
  30980. })();
  30981. (function() {
  30982. function visit(vertex, fn, visited, path) {
  30983. var name = vertex.name,
  30984. vertices = vertex.incoming,
  30985. names = vertex.incomingNames,
  30986. len = names.length,
  30987. i;
  30988. if (!visited) {
  30989. visited = {};
  30990. }
  30991. if (!path) {
  30992. path = [];
  30993. }
  30994. if (visited.hasOwnProperty(name)) {
  30995. return;
  30996. }
  30997. path.push(name);
  30998. visited[name] = true;
  30999. for (i = 0; i < len; i++) {
  31000. visit(vertices[names[i]], fn, visited, path);
  31001. }
  31002. fn(vertex, path);
  31003. path.pop();
  31004. }
  31005. function DAG() {
  31006. this.names = [];
  31007. this.vertices = {};
  31008. }
  31009. DAG.prototype.add = function(name) {
  31010. if (!name) { return; }
  31011. if (this.vertices.hasOwnProperty(name)) {
  31012. return this.vertices[name];
  31013. }
  31014. var vertex = {
  31015. name: name, incoming: {}, incomingNames: [], hasOutgoing: false, value: null
  31016. };
  31017. this.vertices[name] = vertex;
  31018. this.names.push(name);
  31019. return vertex;
  31020. };
  31021. DAG.prototype.map = function(name, value) {
  31022. this.add(name).value = value;
  31023. };
  31024. DAG.prototype.addEdge = function(fromName, toName) {
  31025. if (!fromName || !toName || fromName === toName) {
  31026. return;
  31027. }
  31028. var from = this.add(fromName), to = this.add(toName);
  31029. if (to.incoming.hasOwnProperty(fromName)) {
  31030. return;
  31031. }
  31032. function checkCycle(vertex, path) {
  31033. if (vertex.name === toName) {
  31034. throw new Ember.Error("cycle detected: " + toName + " <- " + path.join(" <- "));
  31035. }
  31036. }
  31037. visit(from, checkCycle);
  31038. from.hasOutgoing = true;
  31039. to.incoming[fromName] = from;
  31040. to.incomingNames.push(fromName);
  31041. };
  31042. DAG.prototype.topsort = function(fn) {
  31043. var visited = {},
  31044. vertices = this.vertices,
  31045. names = this.names,
  31046. len = names.length,
  31047. i, vertex;
  31048. for (i = 0; i < len; i++) {
  31049. vertex = vertices[names[i]];
  31050. if (!vertex.hasOutgoing) {
  31051. visit(vertex, fn, visited);
  31052. }
  31053. }
  31054. };
  31055. DAG.prototype.addEdges = function(name, value, before, after) {
  31056. var i;
  31057. this.map(name, value);
  31058. if (before) {
  31059. if (typeof before === 'string') {
  31060. this.addEdge(name, before);
  31061. } else {
  31062. for (i = 0; i < before.length; i++) {
  31063. this.addEdge(name, before[i]);
  31064. }
  31065. }
  31066. }
  31067. if (after) {
  31068. if (typeof after === 'string') {
  31069. this.addEdge(after, name);
  31070. } else {
  31071. for (i = 0; i < after.length; i++) {
  31072. this.addEdge(after[i], name);
  31073. }
  31074. }
  31075. }
  31076. };
  31077. Ember.DAG = DAG;
  31078. })();
  31079. (function() {
  31080. /**
  31081. @module ember
  31082. @submodule ember-application
  31083. */
  31084. var get = Ember.get,
  31085. classify = Ember.String.classify,
  31086. capitalize = Ember.String.capitalize,
  31087. decamelize = Ember.String.decamelize;
  31088. /**
  31089. The DefaultResolver defines the default lookup rules to resolve
  31090. container lookups before consulting the container for registered
  31091. items:
  31092. * templates are looked up on `Ember.TEMPLATES`
  31093. * other names are looked up on the application after converting
  31094. the name. For example, `controller:post` looks up
  31095. `App.PostController` by default.
  31096. * there are some nuances (see examples below)
  31097. ### How Resolving Works
  31098. The container calls this object's `resolve` method with the
  31099. `fullName` argument.
  31100. It first parses the fullName into an object using `parseName`.
  31101. Then it checks for the presence of a type-specific instance
  31102. method of the form `resolve[Type]` and calls it if it exists.
  31103. For example if it was resolving 'template:post', it would call
  31104. the `resolveTemplate` method.
  31105. Its last resort is to call the `resolveOther` method.
  31106. The methods of this object are designed to be easy to override
  31107. in a subclass. For example, you could enhance how a template
  31108. is resolved like so:
  31109. ```javascript
  31110. App = Ember.Application.create({
  31111. Resolver: Ember.DefaultResolver.extend({
  31112. resolveTemplate: function(parsedName) {
  31113. var resolvedTemplate = this._super(parsedName);
  31114. if (resolvedTemplate) { return resolvedTemplate; }
  31115. return Ember.TEMPLATES['not_found'];
  31116. }
  31117. })
  31118. });
  31119. ```
  31120. Some examples of how names are resolved:
  31121. ```
  31122. 'template:post' //=> Ember.TEMPLATES['post']
  31123. 'template:posts/byline' //=> Ember.TEMPLATES['posts/byline']
  31124. 'template:posts.byline' //=> Ember.TEMPLATES['posts/byline']
  31125. 'template:blogPost' //=> Ember.TEMPLATES['blogPost']
  31126. // OR
  31127. // Ember.TEMPLATES['blog_post']
  31128. 'controller:post' //=> App.PostController
  31129. 'controller:posts.index' //=> App.PostsIndexController
  31130. 'controller:blog/post' //=> Blog.PostController
  31131. 'controller:basic' //=> Ember.Controller
  31132. 'route:post' //=> App.PostRoute
  31133. 'route:posts.index' //=> App.PostsIndexRoute
  31134. 'route:blog/post' //=> Blog.PostRoute
  31135. 'route:basic' //=> Ember.Route
  31136. 'view:post' //=> App.PostView
  31137. 'view:posts.index' //=> App.PostsIndexView
  31138. 'view:blog/post' //=> Blog.PostView
  31139. 'view:basic' //=> Ember.View
  31140. 'foo:post' //=> App.PostFoo
  31141. 'model:post' //=> App.Post
  31142. ```
  31143. @class DefaultResolver
  31144. @namespace Ember
  31145. @extends Ember.Object
  31146. */
  31147. Ember.DefaultResolver = Ember.Object.extend({
  31148. /**
  31149. This will be set to the Application instance when it is
  31150. created.
  31151. @property namespace
  31152. */
  31153. namespace: null,
  31154. normalize: function(fullName) {
  31155. var split = fullName.split(':', 2),
  31156. type = split[0],
  31157. name = split[1];
  31158. Ember.assert("Tried to normalize a container name without a colon (:) in " +
  31159. "it. You probably tried to lookup a name that did not contain " +
  31160. "a type, a colon, and a name. A proper lookup name would be " +
  31161. "`view:post`.", split.length === 2);
  31162. if (type !== 'template') {
  31163. var result = name;
  31164. if (result.indexOf('.') > -1) {
  31165. result = result.replace(/\.(.)/g, function(m) { return m.charAt(1).toUpperCase(); });
  31166. }
  31167. if (name.indexOf('_') > -1) {
  31168. result = result.replace(/_(.)/g, function(m) { return m.charAt(1).toUpperCase(); });
  31169. }
  31170. return type + ':' + result;
  31171. } else {
  31172. return fullName;
  31173. }
  31174. },
  31175. /**
  31176. This method is called via the container's resolver method.
  31177. It parses the provided `fullName` and then looks up and
  31178. returns the appropriate template or class.
  31179. @method resolve
  31180. @param {String} fullName the lookup string
  31181. @return {Object} the resolved factory
  31182. */
  31183. resolve: function(fullName) {
  31184. var parsedName = this.parseName(fullName),
  31185. typeSpecificResolveMethod = this[parsedName.resolveMethodName];
  31186. if (!parsedName.name || !parsedName.type) {
  31187. throw new TypeError("Invalid fullName: `" + fullName + "`, must be of the form `type:name` ");
  31188. }
  31189. if (typeSpecificResolveMethod) {
  31190. var resolved = typeSpecificResolveMethod.call(this, parsedName);
  31191. if (resolved) { return resolved; }
  31192. }
  31193. return this.resolveOther(parsedName);
  31194. },
  31195. /**
  31196. Convert the string name of the form "type:name" to
  31197. a Javascript object with the parsed aspects of the name
  31198. broken out.
  31199. @protected
  31200. @param {String} fullName the lookup string
  31201. @method parseName
  31202. */
  31203. parseName: function(fullName) {
  31204. var nameParts = fullName.split(":"),
  31205. type = nameParts[0], fullNameWithoutType = nameParts[1],
  31206. name = fullNameWithoutType,
  31207. namespace = get(this, 'namespace'),
  31208. root = namespace;
  31209. if (type !== 'template' && name.indexOf('/') !== -1) {
  31210. var parts = name.split('/');
  31211. name = parts[parts.length - 1];
  31212. var namespaceName = capitalize(parts.slice(0, -1).join('.'));
  31213. root = Ember.Namespace.byName(namespaceName);
  31214. Ember.assert('You are looking for a ' + name + ' ' + type + ' in the ' + namespaceName + ' namespace, but the namespace could not be found', root);
  31215. }
  31216. return {
  31217. fullName: fullName,
  31218. type: type,
  31219. fullNameWithoutType: fullNameWithoutType,
  31220. name: name,
  31221. root: root,
  31222. resolveMethodName: "resolve" + classify(type)
  31223. };
  31224. },
  31225. /**
  31226. Look up the template in Ember.TEMPLATES
  31227. @protected
  31228. @param {Object} parsedName a parseName object with the parsed
  31229. fullName lookup string
  31230. @method resolveTemplate
  31231. */
  31232. resolveTemplate: function(parsedName) {
  31233. var templateName = parsedName.fullNameWithoutType.replace(/\./g, '/');
  31234. if (Ember.TEMPLATES[templateName]) {
  31235. return Ember.TEMPLATES[templateName];
  31236. }
  31237. templateName = decamelize(templateName);
  31238. if (Ember.TEMPLATES[templateName]) {
  31239. return Ember.TEMPLATES[templateName];
  31240. }
  31241. },
  31242. /**
  31243. Given a parseName object (output from `parseName`), apply
  31244. the conventions expected by `Ember.Router`
  31245. @protected
  31246. @param {Object} parsedName a parseName object with the parsed
  31247. fullName lookup string
  31248. @method useRouterNaming
  31249. */
  31250. useRouterNaming: function(parsedName) {
  31251. parsedName.name = parsedName.name.replace(/\./g, '_');
  31252. if (parsedName.name === 'basic') {
  31253. parsedName.name = '';
  31254. }
  31255. },
  31256. /**
  31257. Lookup the controller using `resolveOther`
  31258. @protected
  31259. @param {Object} parsedName a parseName object with the parsed
  31260. fullName lookup string
  31261. @method resolveController
  31262. */
  31263. resolveController: function(parsedName) {
  31264. this.useRouterNaming(parsedName);
  31265. return this.resolveOther(parsedName);
  31266. },
  31267. /**
  31268. Lookup the route using `resolveOther`
  31269. @protected
  31270. @param {Object} parsedName a parseName object with the parsed
  31271. fullName lookup string
  31272. @method resolveRoute
  31273. */
  31274. resolveRoute: function(parsedName) {
  31275. this.useRouterNaming(parsedName);
  31276. return this.resolveOther(parsedName);
  31277. },
  31278. /**
  31279. Lookup the view using `resolveOther`
  31280. @protected
  31281. @param {Object} parsedName a parseName object with the parsed
  31282. fullName lookup string
  31283. @method resolveView
  31284. */
  31285. resolveView: function(parsedName) {
  31286. this.useRouterNaming(parsedName);
  31287. return this.resolveOther(parsedName);
  31288. },
  31289. resolveHelper: function(parsedName) {
  31290. return this.resolveOther(parsedName) || Ember.Handlebars.helpers[parsedName.fullNameWithoutType];
  31291. },
  31292. /**
  31293. Lookup the model on the Application namespace
  31294. @protected
  31295. @param {Object} parsedName a parseName object with the parsed
  31296. fullName lookup string
  31297. @method resolveModel
  31298. */
  31299. resolveModel: function(parsedName) {
  31300. var className = classify(parsedName.name),
  31301. factory = get(parsedName.root, className);
  31302. if (factory) { return factory; }
  31303. },
  31304. /**
  31305. Look up the specified object (from parsedName) on the appropriate
  31306. namespace (usually on the Application)
  31307. @protected
  31308. @param {Object} parsedName a parseName object with the parsed
  31309. fullName lookup string
  31310. @method resolveOther
  31311. */
  31312. resolveOther: function(parsedName) {
  31313. var className = classify(parsedName.name) + classify(parsedName.type),
  31314. factory = get(parsedName.root, className);
  31315. if (factory) { return factory; }
  31316. },
  31317. /**
  31318. Returns a human-readable description for a fullName. Used by the
  31319. Application namespace in assertions to describe the
  31320. precise name of the class that Ember is looking for, rather than
  31321. container keys.
  31322. @protected
  31323. @param {String} fullName the lookup string
  31324. @method lookupDescription
  31325. */
  31326. lookupDescription: function(fullName) {
  31327. var parsedName = this.parseName(fullName);
  31328. if (parsedName.type === 'template') {
  31329. return "template at " + parsedName.fullNameWithoutType.replace(/\./g, '/');
  31330. }
  31331. var description = parsedName.root + "." + classify(parsedName.name);
  31332. if (parsedName.type !== 'model') { description += classify(parsedName.type); }
  31333. return description;
  31334. },
  31335. makeToString: function(factory, fullName) {
  31336. return factory.toString();
  31337. }
  31338. });
  31339. })();
  31340. (function() {
  31341. /**
  31342. @module ember
  31343. @submodule ember-application
  31344. */
  31345. var get = Ember.get, set = Ember.set;
  31346. function DeprecatedContainer(container) {
  31347. this._container = container;
  31348. }
  31349. DeprecatedContainer.deprecate = function(method) {
  31350. return function() {
  31351. var container = this._container;
  31352. Ember.deprecate('Using the defaultContainer is no longer supported. [defaultContainer#' + method + '] see: http://git.io/EKPpnA', false);
  31353. return container[method].apply(container, arguments);
  31354. };
  31355. };
  31356. DeprecatedContainer.prototype = {
  31357. _container: null,
  31358. lookup: DeprecatedContainer.deprecate('lookup'),
  31359. resolve: DeprecatedContainer.deprecate('resolve'),
  31360. register: DeprecatedContainer.deprecate('register')
  31361. };
  31362. /**
  31363. An instance of `Ember.Application` is the starting point for every Ember
  31364. application. It helps to instantiate, initialize and coordinate the many
  31365. objects that make up your app.
  31366. Each Ember app has one and only one `Ember.Application` object. In fact, the
  31367. very first thing you should do in your application is create the instance:
  31368. ```javascript
  31369. window.App = Ember.Application.create();
  31370. ```
  31371. Typically, the application object is the only global variable. All other
  31372. classes in your app should be properties on the `Ember.Application` instance,
  31373. which highlights its first role: a global namespace.
  31374. For example, if you define a view class, it might look like this:
  31375. ```javascript
  31376. App.MyView = Ember.View.extend();
  31377. ```
  31378. By default, calling `Ember.Application.create()` will automatically initialize
  31379. your application by calling the `Ember.Application.initialize()` method. If
  31380. you need to delay initialization, you can call your app's `deferReadiness()`
  31381. method. When you are ready for your app to be initialized, call its
  31382. `advanceReadiness()` method.
  31383. You can define a `ready` method on the `Ember.Application` instance, which
  31384. will be run by Ember when the application is initialized.
  31385. Because `Ember.Application` inherits from `Ember.Namespace`, any classes
  31386. you create will have useful string representations when calling `toString()`.
  31387. See the `Ember.Namespace` documentation for more information.
  31388. While you can think of your `Ember.Application` as a container that holds the
  31389. other classes in your application, there are several other responsibilities
  31390. going on under-the-hood that you may want to understand.
  31391. ### Event Delegation
  31392. Ember uses a technique called _event delegation_. This allows the framework
  31393. to set up a global, shared event listener instead of requiring each view to
  31394. do it manually. For example, instead of each view registering its own
  31395. `mousedown` listener on its associated element, Ember sets up a `mousedown`
  31396. listener on the `body`.
  31397. If a `mousedown` event occurs, Ember will look at the target of the event and
  31398. start walking up the DOM node tree, finding corresponding views and invoking
  31399. their `mouseDown` method as it goes.
  31400. `Ember.Application` has a number of default events that it listens for, as
  31401. well as a mapping from lowercase events to camel-cased view method names. For
  31402. example, the `keypress` event causes the `keyPress` method on the view to be
  31403. called, the `dblclick` event causes `doubleClick` to be called, and so on.
  31404. If there is a bubbling browser event that Ember does not listen for by
  31405. default, you can specify custom events and their corresponding view method
  31406. names by setting the application's `customEvents` property:
  31407. ```javascript
  31408. App = Ember.Application.create({
  31409. customEvents: {
  31410. // add support for the paste event
  31411. paste: "paste"
  31412. }
  31413. });
  31414. ```
  31415. By default, the application sets up these event listeners on the document
  31416. body. However, in cases where you are embedding an Ember application inside
  31417. an existing page, you may want it to set up the listeners on an element
  31418. inside the body.
  31419. For example, if only events inside a DOM element with the ID of `ember-app`
  31420. should be delegated, set your application's `rootElement` property:
  31421. ```javascript
  31422. window.App = Ember.Application.create({
  31423. rootElement: '#ember-app'
  31424. });
  31425. ```
  31426. The `rootElement` can be either a DOM element or a jQuery-compatible selector
  31427. string. Note that *views appended to the DOM outside the root element will
  31428. not receive events.* If you specify a custom root element, make sure you only
  31429. append views inside it!
  31430. To learn more about the advantages of event delegation and the Ember view
  31431. layer, and a list of the event listeners that are setup by default, visit the
  31432. [Ember View Layer guide](http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_event-delegation).
  31433. ### Initializers
  31434. Libraries on top of Ember can register additional initializers, like so:
  31435. ```javascript
  31436. Ember.Application.initializer({
  31437. name: "store",
  31438. initialize: function(container, application) {
  31439. container.register('store:main', application.Store);
  31440. }
  31441. });
  31442. ```
  31443. ### Routing
  31444. In addition to creating your application's router, `Ember.Application` is
  31445. also responsible for telling the router when to start routing. Transitions
  31446. between routes can be logged with the `LOG_TRANSITIONS` flag, and more
  31447. detailed intra-transition logging can be logged with
  31448. the `LOG_TRANSITIONS_INTERNAL` flag:
  31449. ```javascript
  31450. window.App = Ember.Application.create({
  31451. LOG_TRANSITIONS: true, // basic logging of successful transitions
  31452. LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps
  31453. });
  31454. ```
  31455. By default, the router will begin trying to translate the current URL into
  31456. application state once the browser emits the `DOMContentReady` event. If you
  31457. need to defer routing, you can call the application's `deferReadiness()`
  31458. method. Once routing can begin, call the `advanceReadiness()` method.
  31459. If there is any setup required before routing begins, you can implement a
  31460. `ready()` method on your app that will be invoked immediately before routing
  31461. begins.
  31462. ```
  31463. @class Application
  31464. @namespace Ember
  31465. @extends Ember.Namespace
  31466. */
  31467. var Application = Ember.Application = Ember.Namespace.extend(Ember.DeferredMixin, {
  31468. /**
  31469. The root DOM element of the Application. This can be specified as an
  31470. element or a
  31471. [jQuery-compatible selector string](http://api.jquery.com/category/selectors/).
  31472. This is the element that will be passed to the Application's,
  31473. `eventDispatcher`, which sets up the listeners for event delegation. Every
  31474. view in your application should be a child of the element you specify here.
  31475. @property rootElement
  31476. @type DOMElement
  31477. @default 'body'
  31478. */
  31479. rootElement: 'body',
  31480. /**
  31481. The `Ember.EventDispatcher` responsible for delegating events to this
  31482. application's views.
  31483. The event dispatcher is created by the application at initialization time
  31484. and sets up event listeners on the DOM element described by the
  31485. application's `rootElement` property.
  31486. See the documentation for `Ember.EventDispatcher` for more information.
  31487. @property eventDispatcher
  31488. @type Ember.EventDispatcher
  31489. @default null
  31490. */
  31491. eventDispatcher: null,
  31492. /**
  31493. The DOM events for which the event dispatcher should listen.
  31494. By default, the application's `Ember.EventDispatcher` listens
  31495. for a set of standard DOM events, such as `mousedown` and
  31496. `keyup`, and delegates them to your application's `Ember.View`
  31497. instances.
  31498. If you would like additional bubbling events to be delegated to your
  31499. views, set your `Ember.Application`'s `customEvents` property
  31500. to a hash containing the DOM event name as the key and the
  31501. corresponding view method name as the value. For example:
  31502. ```javascript
  31503. App = Ember.Application.create({
  31504. customEvents: {
  31505. // add support for the paste event
  31506. paste: "paste"
  31507. }
  31508. });
  31509. ```
  31510. @property customEvents
  31511. @type Object
  31512. @default null
  31513. */
  31514. customEvents: null,
  31515. // Start off the number of deferrals at 1. This will be
  31516. // decremented by the Application's own `initialize` method.
  31517. _readinessDeferrals: 1,
  31518. init: function() {
  31519. if (!this.$) { this.$ = Ember.$; }
  31520. this.__container__ = this.buildContainer();
  31521. this.Router = this.defaultRouter();
  31522. this._super();
  31523. this.scheduleInitialize();
  31524. Ember.libraries.registerCoreLibrary('Handlebars', Ember.Handlebars.VERSION);
  31525. Ember.libraries.registerCoreLibrary('jQuery', Ember.$().jquery);
  31526. if ( Ember.LOG_VERSION ) {
  31527. Ember.LOG_VERSION = false; // we only need to see this once per Application#init
  31528. var maxNameLength = Math.max.apply(this, Ember.A(Ember.libraries).mapBy("name.length"));
  31529. Ember.debug('-------------------------------');
  31530. Ember.libraries.each(function(name, version) {
  31531. var spaces = new Array(maxNameLength - name.length + 1).join(" ");
  31532. Ember.debug([name, spaces, ' : ', version].join(""));
  31533. });
  31534. Ember.debug('-------------------------------');
  31535. }
  31536. },
  31537. /**
  31538. Build the container for the current application.
  31539. Also register a default application view in case the application
  31540. itself does not.
  31541. @private
  31542. @method buildContainer
  31543. @return {Ember.Container} the configured container
  31544. */
  31545. buildContainer: function() {
  31546. var container = this.__container__ = Application.buildContainer(this);
  31547. return container;
  31548. },
  31549. /**
  31550. If the application has not opted out of routing and has not explicitly
  31551. defined a router, supply a default router for the application author
  31552. to configure.
  31553. This allows application developers to do:
  31554. ```javascript
  31555. var App = Ember.Application.create();
  31556. App.Router.map(function() {
  31557. this.resource('posts');
  31558. });
  31559. ```
  31560. @private
  31561. @method defaultRouter
  31562. @return {Ember.Router} the default router
  31563. */
  31564. defaultRouter: function() {
  31565. if (this.Router === false) { return; }
  31566. var container = this.__container__;
  31567. if (this.Router) {
  31568. container.unregister('router:main');
  31569. container.register('router:main', this.Router);
  31570. }
  31571. return container.lookupFactory('router:main');
  31572. },
  31573. /**
  31574. Automatically initialize the application once the DOM has
  31575. become ready.
  31576. The initialization itself is scheduled on the actions queue
  31577. which ensures that application loading finishes before
  31578. booting.
  31579. If you are asynchronously loading code, you should call
  31580. `deferReadiness()` to defer booting, and then call
  31581. `advanceReadiness()` once all of your code has finished
  31582. loading.
  31583. @private
  31584. @method scheduleInitialize
  31585. */
  31586. scheduleInitialize: function() {
  31587. var self = this;
  31588. if (!this.$ || this.$.isReady) {
  31589. Ember.run.schedule('actions', self, '_initialize');
  31590. } else {
  31591. this.$().ready(function runInitialize() {
  31592. Ember.run(self, '_initialize');
  31593. });
  31594. }
  31595. },
  31596. /**
  31597. Use this to defer readiness until some condition is true.
  31598. Example:
  31599. ```javascript
  31600. App = Ember.Application.create();
  31601. App.deferReadiness();
  31602. jQuery.getJSON("/auth-token", function(token) {
  31603. App.token = token;
  31604. App.advanceReadiness();
  31605. });
  31606. ```
  31607. This allows you to perform asynchronous setup logic and defer
  31608. booting your application until the setup has finished.
  31609. However, if the setup requires a loading UI, it might be better
  31610. to use the router for this purpose.
  31611. @method deferReadiness
  31612. */
  31613. deferReadiness: function() {
  31614. Ember.assert("You must call deferReadiness on an instance of Ember.Application", this instanceof Ember.Application);
  31615. Ember.assert("You cannot defer readiness since the `ready()` hook has already been called.", this._readinessDeferrals > 0);
  31616. this._readinessDeferrals++;
  31617. },
  31618. /**
  31619. Call `advanceReadiness` after any asynchronous setup logic has completed.
  31620. Each call to `deferReadiness` must be matched by a call to `advanceReadiness`
  31621. or the application will never become ready and routing will not begin.
  31622. @method advanceReadiness
  31623. @see {Ember.Application#deferReadiness}
  31624. */
  31625. advanceReadiness: function() {
  31626. Ember.assert("You must call advanceReadiness on an instance of Ember.Application", this instanceof Ember.Application);
  31627. this._readinessDeferrals--;
  31628. if (this._readinessDeferrals === 0) {
  31629. Ember.run.once(this, this.didBecomeReady);
  31630. }
  31631. },
  31632. /**
  31633. registers a factory for later injection
  31634. Example:
  31635. ```javascript
  31636. App = Ember.Application.create();
  31637. App.Person = Ember.Object.extend({});
  31638. App.Orange = Ember.Object.extend({});
  31639. App.Email = Ember.Object.extend({});
  31640. App.session = Ember.Object.create({});
  31641. App.register('model:user', App.Person, {singleton: false });
  31642. App.register('fruit:favorite', App.Orange);
  31643. App.register('communication:main', App.Email, {singleton: false});
  31644. App.register('session', App.session, {instantiate: false});
  31645. ```
  31646. @method register
  31647. @param fullName {String} type:name (e.g., 'model:user')
  31648. @param factory {Function} (e.g., App.Person)
  31649. @param options {String} (optional)
  31650. **/
  31651. register: function() {
  31652. var container = this.__container__;
  31653. container.register.apply(container, arguments);
  31654. },
  31655. /**
  31656. defines an injection or typeInjection
  31657. Example:
  31658. ```javascript
  31659. App.inject(<full_name or type>, <property name>, <full_name>)
  31660. App.inject('controller:application', 'email', 'model:email')
  31661. App.inject('controller', 'source', 'source:main')
  31662. ```
  31663. Please note that injections on models are currently disabled.
  31664. This was done because ember-data was not ready for fully a container aware ecosystem.
  31665. You can enable injections on models by setting `Ember.MODEL_FACTORY_INJECTIONS` flag to `true`
  31666. If model factory injections are enabled, models should not be
  31667. accessed globally (only through `container.lookupFactory('model:modelName'))`);
  31668. @method inject
  31669. @param factoryNameOrType {String}
  31670. @param property {String}
  31671. @param injectionName {String}
  31672. **/
  31673. inject: function() {
  31674. var container = this.__container__;
  31675. container.injection.apply(container, arguments);
  31676. },
  31677. /**
  31678. Calling initialize manually is not supported.
  31679. Please see Ember.Application#advanceReadiness and
  31680. Ember.Application#deferReadiness.
  31681. @private
  31682. @deprecated
  31683. @method initialize
  31684. **/
  31685. initialize: function() {
  31686. Ember.deprecate('Calling initialize manually is not supported. Please see Ember.Application#advanceReadiness and Ember.Application#deferReadiness');
  31687. },
  31688. /**
  31689. Initialize the application. This happens automatically.
  31690. Run any initializers and run the application load hook. These hooks may
  31691. choose to defer readiness. For example, an authentication hook might want
  31692. to defer readiness until the auth token has been retrieved.
  31693. @private
  31694. @method _initialize
  31695. */
  31696. _initialize: function() {
  31697. if (this.isDestroyed) { return; }
  31698. // At this point, the App.Router must already be assigned
  31699. if (this.Router) {
  31700. var container = this.__container__;
  31701. container.unregister('router:main');
  31702. container.register('router:main', this.Router);
  31703. }
  31704. this.runInitializers();
  31705. Ember.runLoadHooks('application', this);
  31706. // At this point, any initializers or load hooks that would have wanted
  31707. // to defer readiness have fired. In general, advancing readiness here
  31708. // will proceed to didBecomeReady.
  31709. this.advanceReadiness();
  31710. return this;
  31711. },
  31712. /**
  31713. Reset the application. This is typically used only in tests. It cleans up
  31714. the application in the following order:
  31715. 1. Deactivate existing routes
  31716. 2. Destroy all objects in the container
  31717. 3. Create a new application container
  31718. 4. Re-route to the existing url
  31719. Typical Example:
  31720. ```javascript
  31721. var App;
  31722. Ember.run(function() {
  31723. App = Ember.Application.create();
  31724. });
  31725. module("acceptance test", {
  31726. setup: function() {
  31727. App.reset();
  31728. }
  31729. });
  31730. test("first test", function() {
  31731. // App is freshly reset
  31732. });
  31733. test("first test", function() {
  31734. // App is again freshly reset
  31735. });
  31736. ```
  31737. Advanced Example:
  31738. Occasionally you may want to prevent the app from initializing during
  31739. setup. This could enable extra configuration, or enable asserting prior
  31740. to the app becoming ready.
  31741. ```javascript
  31742. var App;
  31743. Ember.run(function() {
  31744. App = Ember.Application.create();
  31745. });
  31746. module("acceptance test", {
  31747. setup: function() {
  31748. Ember.run(function() {
  31749. App.reset();
  31750. App.deferReadiness();
  31751. });
  31752. }
  31753. });
  31754. test("first test", function() {
  31755. ok(true, 'something before app is initialized');
  31756. Ember.run(function() {
  31757. App.advanceReadiness();
  31758. });
  31759. ok(true, 'something after app is initialized');
  31760. });
  31761. ```
  31762. @method reset
  31763. **/
  31764. reset: function() {
  31765. this._readinessDeferrals = 1;
  31766. function handleReset() {
  31767. var router = this.__container__.lookup('router:main');
  31768. router.reset();
  31769. Ember.run(this.__container__, 'destroy');
  31770. this.buildContainer();
  31771. Ember.run.schedule('actions', this, function() {
  31772. this._initialize();
  31773. });
  31774. }
  31775. Ember.run.join(this, handleReset);
  31776. },
  31777. /**
  31778. @private
  31779. @method runInitializers
  31780. */
  31781. runInitializers: function() {
  31782. var initializers = get(this.constructor, 'initializers'),
  31783. container = this.__container__,
  31784. graph = new Ember.DAG(),
  31785. namespace = this,
  31786. name, initializer;
  31787. for (name in initializers) {
  31788. initializer = initializers[name];
  31789. graph.addEdges(initializer.name, initializer.initialize, initializer.before, initializer.after);
  31790. }
  31791. graph.topsort(function (vertex) {
  31792. var initializer = vertex.value;
  31793. Ember.assert("No application initializer named '"+vertex.name+"'", initializer);
  31794. initializer(container, namespace);
  31795. });
  31796. },
  31797. /**
  31798. @private
  31799. @method didBecomeReady
  31800. */
  31801. didBecomeReady: function() {
  31802. this.setupEventDispatcher();
  31803. this.ready(); // user hook
  31804. this.startRouting();
  31805. if (!Ember.testing) {
  31806. // Eagerly name all classes that are already loaded
  31807. Ember.Namespace.processAll();
  31808. Ember.BOOTED = true;
  31809. }
  31810. this.resolve(this);
  31811. },
  31812. /**
  31813. Setup up the event dispatcher to receive events on the
  31814. application's `rootElement` with any registered
  31815. `customEvents`.
  31816. @private
  31817. @method setupEventDispatcher
  31818. */
  31819. setupEventDispatcher: function() {
  31820. var customEvents = get(this, 'customEvents'),
  31821. rootElement = get(this, 'rootElement'),
  31822. dispatcher = this.__container__.lookup('event_dispatcher:main');
  31823. set(this, 'eventDispatcher', dispatcher);
  31824. dispatcher.setup(customEvents, rootElement);
  31825. },
  31826. /**
  31827. trigger a new call to `route` whenever the URL changes.
  31828. If the application has a router, use it to route to the current URL, and
  31829. @private
  31830. @method startRouting
  31831. @property router {Ember.Router}
  31832. */
  31833. startRouting: function() {
  31834. var router = this.__container__.lookup('router:main');
  31835. if (!router) { return; }
  31836. router.startRouting();
  31837. },
  31838. handleURL: function(url) {
  31839. var router = this.__container__.lookup('router:main');
  31840. router.handleURL(url);
  31841. },
  31842. /**
  31843. Called when the Application has become ready.
  31844. The call will be delayed until the DOM has become ready.
  31845. @event ready
  31846. */
  31847. ready: Ember.K,
  31848. /**
  31849. @deprecated Use 'Resolver' instead
  31850. Set this to provide an alternate class to `Ember.DefaultResolver`
  31851. @property resolver
  31852. */
  31853. resolver: null,
  31854. /**
  31855. Set this to provide an alternate class to `Ember.DefaultResolver`
  31856. @property resolver
  31857. */
  31858. Resolver: null,
  31859. willDestroy: function() {
  31860. Ember.BOOTED = false;
  31861. // Ensure deactivation of routes before objects are destroyed
  31862. this.__container__.lookup('router:main').reset();
  31863. this.__container__.destroy();
  31864. },
  31865. initializer: function(options) {
  31866. this.constructor.initializer(options);
  31867. }
  31868. });
  31869. Ember.Application.reopenClass({
  31870. initializers: {},
  31871. initializer: function(initializer) {
  31872. // If this is the first initializer being added to a subclass, we are going to reopen the class
  31873. // to make sure we have a new `initializers` object, which extends from the parent class' using
  31874. // prototypal inheritance. Without this, attempting to add initializers to the subclass would
  31875. // pollute the parent class as well as other subclasses.
  31876. if (this.superclass.initializers !== undefined && this.superclass.initializers === this.initializers) {
  31877. this.reopenClass({
  31878. initializers: Ember.create(this.initializers)
  31879. });
  31880. }
  31881. Ember.assert("The initializer '" + initializer.name + "' has already been registered", !this.initializers[initializer.name]);
  31882. Ember.assert("An initializer cannot be registered with both a before and an after", !(initializer.before && initializer.after));
  31883. Ember.assert("An initializer cannot be registered without an initialize function", Ember.canInvoke(initializer, 'initialize'));
  31884. this.initializers[initializer.name] = initializer;
  31885. },
  31886. /**
  31887. This creates a container with the default Ember naming conventions.
  31888. It also configures the container:
  31889. * registered views are created every time they are looked up (they are
  31890. not singletons)
  31891. * registered templates are not factories; the registered value is
  31892. returned directly.
  31893. * the router receives the application as its `namespace` property
  31894. * all controllers receive the router as their `target` and `controllers`
  31895. properties
  31896. * all controllers receive the application as their `namespace` property
  31897. * the application view receives the application controller as its
  31898. `controller` property
  31899. * the application view receives the application template as its
  31900. `defaultTemplate` property
  31901. @private
  31902. @method buildContainer
  31903. @static
  31904. @param {Ember.Application} namespace the application to build the
  31905. container for.
  31906. @return {Ember.Container} the built container
  31907. */
  31908. buildContainer: function(namespace) {
  31909. var container = new Ember.Container();
  31910. Ember.Container.defaultContainer = new DeprecatedContainer(container);
  31911. container.set = Ember.set;
  31912. container.resolver = resolverFor(namespace);
  31913. container.normalize = container.resolver.normalize;
  31914. container.describe = container.resolver.describe;
  31915. container.makeToString = container.resolver.makeToString;
  31916. container.optionsForType('component', { singleton: false });
  31917. container.optionsForType('view', { singleton: false });
  31918. container.optionsForType('template', { instantiate: false });
  31919. container.optionsForType('helper', { instantiate: false });
  31920. container.register('application:main', namespace, { instantiate: false });
  31921. container.register('controller:basic', Ember.Controller, { instantiate: false });
  31922. container.register('controller:object', Ember.ObjectController, { instantiate: false });
  31923. container.register('controller:array', Ember.ArrayController, { instantiate: false });
  31924. container.register('route:basic', Ember.Route, { instantiate: false });
  31925. container.register('event_dispatcher:main', Ember.EventDispatcher);
  31926. container.register('router:main', Ember.Router);
  31927. container.injection('router:main', 'namespace', 'application:main');
  31928. container.register('location:hash', Ember.HashLocation);
  31929. container.register('location:history', Ember.HistoryLocation);
  31930. container.register('location:none', Ember.NoneLocation);
  31931. container.injection('controller', 'target', 'router:main');
  31932. container.injection('controller', 'namespace', 'application:main');
  31933. container.injection('route', 'router', 'router:main');
  31934. return container;
  31935. }
  31936. });
  31937. /**
  31938. This function defines the default lookup rules for container lookups:
  31939. * templates are looked up on `Ember.TEMPLATES`
  31940. * other names are looked up on the application after classifying the name.
  31941. For example, `controller:post` looks up `App.PostController` by default.
  31942. * if the default lookup fails, look for registered classes on the container
  31943. This allows the application to register default injections in the container
  31944. that could be overridden by the normal naming convention.
  31945. @private
  31946. @method resolverFor
  31947. @param {Ember.Namespace} namespace the namespace to look for classes
  31948. @return {*} the resolved value for a given lookup
  31949. */
  31950. function resolverFor(namespace) {
  31951. if (namespace.get('resolver')) {
  31952. Ember.deprecate('Application.resolver is deprecated in favor of Application.Resolver', false);
  31953. }
  31954. var ResolverClass = namespace.get('resolver') || namespace.get('Resolver') || Ember.DefaultResolver;
  31955. var resolver = ResolverClass.create({
  31956. namespace: namespace
  31957. });
  31958. function resolve(fullName) {
  31959. return resolver.resolve(fullName);
  31960. }
  31961. resolve.describe = function(fullName) {
  31962. return resolver.lookupDescription(fullName);
  31963. };
  31964. resolve.makeToString = function(factory, fullName) {
  31965. return resolver.makeToString(factory, fullName);
  31966. };
  31967. resolve.normalize = function(fullName) {
  31968. if (resolver.normalize) {
  31969. return resolver.normalize(fullName);
  31970. } else {
  31971. Ember.deprecate('The Resolver should now provide a \'normalize\' function', false);
  31972. return fullName;
  31973. }
  31974. };
  31975. return resolve;
  31976. }
  31977. Ember.runLoadHooks('Ember.Application', Ember.Application);
  31978. })();
  31979. (function() {
  31980. })();
  31981. (function() {
  31982. /**
  31983. @module ember
  31984. @submodule ember-application
  31985. */
  31986. var get = Ember.get, set = Ember.set;
  31987. function verifyNeedsDependencies(controller, container, needs) {
  31988. var dependency, i, l, missing = [];
  31989. for (i=0, l=needs.length; i<l; i++) {
  31990. dependency = needs[i];
  31991. Ember.assert(Ember.inspect(controller) + "#needs must not specify dependencies with periods in their names (" + dependency + ")", dependency.indexOf('.') === -1);
  31992. if (dependency.indexOf(':') === -1) {
  31993. dependency = "controller:" + dependency;
  31994. }
  31995. // Structure assert to still do verification but not string concat in production
  31996. if (!container.has(dependency)) {
  31997. missing.push(dependency);
  31998. }
  31999. }
  32000. if (missing.length) {
  32001. throw new Ember.Error(Ember.inspect(controller) + " needs [ " + missing.join(', ') + " ] but " + (missing.length > 1 ? 'they' : 'it') + " could not be found");
  32002. }
  32003. }
  32004. var defaultControllersComputedProperty = Ember.computed(function() {
  32005. var controller = this;
  32006. return {
  32007. needs: get(controller, 'needs'),
  32008. container: get(controller, 'container'),
  32009. unknownProperty: function(controllerName) {
  32010. var needs = this.needs,
  32011. dependency, i, l;
  32012. for (i=0, l=needs.length; i<l; i++) {
  32013. dependency = needs[i];
  32014. if (dependency === controllerName) {
  32015. return this.container.lookup('controller:' + controllerName);
  32016. }
  32017. }
  32018. var errorMessage = Ember.inspect(controller) + '#needs does not include `' + controllerName + '`. To access the ' + controllerName + ' controller from ' + Ember.inspect(controller) + ', ' + Ember.inspect(controller) + ' should have a `needs` property that is an array of the controllers it has access to.';
  32019. throw new ReferenceError(errorMessage);
  32020. },
  32021. setUnknownProperty: function (key, value) {
  32022. throw new Error("You cannot overwrite the value of `controllers." + key + "` of " + Ember.inspect(controller));
  32023. }
  32024. };
  32025. });
  32026. /**
  32027. @class ControllerMixin
  32028. @namespace Ember
  32029. */
  32030. Ember.ControllerMixin.reopen({
  32031. concatenatedProperties: ['needs'],
  32032. /**
  32033. An array of other controller objects available inside
  32034. instances of this controller via the `controllers`
  32035. property:
  32036. For example, when you define a controller:
  32037. ```javascript
  32038. App.CommentsController = Ember.ArrayController.extend({
  32039. needs: ['post']
  32040. });
  32041. ```
  32042. The application's single instance of these other
  32043. controllers are accessible by name through the
  32044. `controllers` property:
  32045. ```javascript
  32046. this.get('controllers.post'); // instance of App.PostController
  32047. ```
  32048. Given that you have a nested controller (nested resource):
  32049. ```javascript
  32050. App.CommentsNewController = Ember.ObjectController.extend({
  32051. });
  32052. ```
  32053. When you define a controller that requires access to a nested one:
  32054. ```javascript
  32055. App.IndexController = Ember.ObjectController.extend({
  32056. needs: ['commentsNew']
  32057. });
  32058. ```
  32059. You will be able to get access to it:
  32060. ```javascript
  32061. this.get('controllers.commentsNew'); // instance of App.CommentsNewController
  32062. ```
  32063. This is only available for singleton controllers.
  32064. @property {Array} needs
  32065. @default []
  32066. */
  32067. needs: [],
  32068. init: function() {
  32069. var needs = get(this, 'needs'),
  32070. length = get(needs, 'length');
  32071. if (length > 0) {
  32072. Ember.assert(' `' + Ember.inspect(this) + ' specifies `needs`, but does ' +
  32073. "not have a container. Please ensure this controller was " +
  32074. "instantiated with a container.",
  32075. this.container || Ember.meta(this, false).descs.controllers !== defaultControllersComputedProperty);
  32076. if (this.container) {
  32077. verifyNeedsDependencies(this, this.container, needs);
  32078. }
  32079. // if needs then initialize controllers proxy
  32080. get(this, 'controllers');
  32081. }
  32082. this._super.apply(this, arguments);
  32083. },
  32084. /**
  32085. @method controllerFor
  32086. @see {Ember.Route#controllerFor}
  32087. @deprecated Use `needs` instead
  32088. */
  32089. controllerFor: function(controllerName) {
  32090. Ember.deprecate("Controller#controllerFor is deprecated, please use Controller#needs instead");
  32091. return Ember.controllerFor(get(this, 'container'), controllerName);
  32092. },
  32093. /**
  32094. Stores the instances of other controllers available from within
  32095. this controller. Any controller listed by name in the `needs`
  32096. property will be accessible by name through this property.
  32097. ```javascript
  32098. App.CommentsController = Ember.ArrayController.extend({
  32099. needs: ['post'],
  32100. postTitle: function(){
  32101. var currentPost = this.get('controllers.post'); // instance of App.PostController
  32102. return currentPost.get('title');
  32103. }.property('controllers.post.title')
  32104. });
  32105. ```
  32106. @see {Ember.ControllerMixin#needs}
  32107. @property {Object} controllers
  32108. @default null
  32109. */
  32110. controllers: defaultControllersComputedProperty
  32111. });
  32112. })();
  32113. (function() {
  32114. })();
  32115. (function() {
  32116. /**
  32117. Ember Application
  32118. @module ember
  32119. @submodule ember-application
  32120. @requires ember-views, ember-routing
  32121. */
  32122. })();
  32123. (function() {
  32124. /**
  32125. @module ember
  32126. @submodule ember-extension-support
  32127. */
  32128. /**
  32129. The `DataAdapter` helps a data persistence library
  32130. interface with tools that debug Ember such
  32131. as the [Ember Extension](https://github.com/tildeio/ember-extension)
  32132. for Chrome and Firefox.
  32133. This class will be extended by a persistence library
  32134. which will override some of the methods with
  32135. library-specific code.
  32136. The methods likely to be overridden are:
  32137. * `getFilters`
  32138. * `detect`
  32139. * `columnsForType`
  32140. * `getRecords`
  32141. * `getRecordColumnValues`
  32142. * `getRecordKeywords`
  32143. * `getRecordFilterValues`
  32144. * `getRecordColor`
  32145. * `observeRecord`
  32146. The adapter will need to be registered
  32147. in the application's container as `dataAdapter:main`
  32148. Example:
  32149. ```javascript
  32150. Application.initializer({
  32151. name: "dataAdapter",
  32152. initialize: function(container, application) {
  32153. application.register('dataAdapter:main', DS.DataAdapter);
  32154. }
  32155. });
  32156. ```
  32157. @class DataAdapter
  32158. @namespace Ember
  32159. @extends Ember.Object
  32160. */
  32161. Ember.DataAdapter = Ember.Object.extend({
  32162. init: function() {
  32163. this._super();
  32164. this.releaseMethods = Ember.A();
  32165. },
  32166. /**
  32167. The container of the application being debugged.
  32168. This property will be injected
  32169. on creation.
  32170. @property container
  32171. @default null
  32172. */
  32173. container: null,
  32174. /**
  32175. Number of attributes to send
  32176. as columns. (Enough to make the record
  32177. identifiable).
  32178. @private
  32179. @property attributeLimit
  32180. @default 3
  32181. */
  32182. attributeLimit: 3,
  32183. /**
  32184. Stores all methods that clear observers.
  32185. These methods will be called on destruction.
  32186. @private
  32187. @property releaseMethods
  32188. */
  32189. releaseMethods: Ember.A(),
  32190. /**
  32191. Specifies how records can be filtered.
  32192. Records returned will need to have a `filterValues`
  32193. property with a key for every name in the returned array.
  32194. @public
  32195. @method getFilters
  32196. @return {Array} List of objects defining filters.
  32197. The object should have a `name` and `desc` property.
  32198. */
  32199. getFilters: function() {
  32200. return Ember.A();
  32201. },
  32202. /**
  32203. Fetch the model types and observe them for changes.
  32204. @public
  32205. @method watchModelTypes
  32206. @param {Function} typesAdded Callback to call to add types.
  32207. Takes an array of objects containing wrapped types (returned from `wrapModelType`).
  32208. @param {Function} typesUpdated Callback to call when a type has changed.
  32209. Takes an array of objects containing wrapped types.
  32210. @return {Function} Method to call to remove all observers
  32211. */
  32212. watchModelTypes: function(typesAdded, typesUpdated) {
  32213. var modelTypes = this.getModelTypes(),
  32214. self = this, typesToSend, releaseMethods = Ember.A();
  32215. typesToSend = modelTypes.map(function(type) {
  32216. var wrapped = self.wrapModelType(type);
  32217. releaseMethods.push(self.observeModelType(type, typesUpdated));
  32218. return wrapped;
  32219. });
  32220. typesAdded(typesToSend);
  32221. var release = function() {
  32222. releaseMethods.forEach(function(fn) { fn(); });
  32223. self.releaseMethods.removeObject(release);
  32224. };
  32225. this.releaseMethods.pushObject(release);
  32226. return release;
  32227. },
  32228. /**
  32229. Fetch the records of a given type and observe them for changes.
  32230. @public
  32231. @method watchRecords
  32232. @param {Function} recordsAdded Callback to call to add records.
  32233. Takes an array of objects containing wrapped records.
  32234. The object should have the following properties:
  32235. columnValues: {Object} key and value of a table cell
  32236. object: {Object} the actual record object
  32237. @param {Function} recordsUpdated Callback to call when a record has changed.
  32238. Takes an array of objects containing wrapped records.
  32239. @param {Function} recordsRemoved Callback to call when a record has removed.
  32240. Takes the following parameters:
  32241. index: the array index where the records were removed
  32242. count: the number of records removed
  32243. @return {Function} Method to call to remove all observers
  32244. */
  32245. watchRecords: function(type, recordsAdded, recordsUpdated, recordsRemoved) {
  32246. var self = this, releaseMethods = Ember.A(), records = this.getRecords(type), release;
  32247. var recordUpdated = function(updatedRecord) {
  32248. recordsUpdated([updatedRecord]);
  32249. };
  32250. var recordsToSend = records.map(function(record) {
  32251. releaseMethods.push(self.observeRecord(record, recordUpdated));
  32252. return self.wrapRecord(record);
  32253. });
  32254. var contentDidChange = function(array, idx, removedCount, addedCount) {
  32255. for (var i = idx; i < idx + addedCount; i++) {
  32256. var record = array.objectAt(i);
  32257. var wrapped = self.wrapRecord(record);
  32258. releaseMethods.push(self.observeRecord(record, recordUpdated));
  32259. recordsAdded([wrapped]);
  32260. }
  32261. if (removedCount) {
  32262. recordsRemoved(idx, removedCount);
  32263. }
  32264. };
  32265. var observer = { didChange: contentDidChange, willChange: Ember.K };
  32266. records.addArrayObserver(self, observer);
  32267. release = function() {
  32268. releaseMethods.forEach(function(fn) { fn(); });
  32269. records.removeArrayObserver(self, observer);
  32270. self.releaseMethods.removeObject(release);
  32271. };
  32272. recordsAdded(recordsToSend);
  32273. this.releaseMethods.pushObject(release);
  32274. return release;
  32275. },
  32276. /**
  32277. Clear all observers before destruction
  32278. @private
  32279. */
  32280. willDestroy: function() {
  32281. this._super();
  32282. this.releaseMethods.forEach(function(fn) {
  32283. fn();
  32284. });
  32285. },
  32286. /**
  32287. Detect whether a class is a model.
  32288. Test that against the model class
  32289. of your persistence library
  32290. @private
  32291. @method detect
  32292. @param {Class} klass The class to test
  32293. @return boolean Whether the class is a model class or not
  32294. */
  32295. detect: function(klass) {
  32296. return false;
  32297. },
  32298. /**
  32299. Get the columns for a given model type.
  32300. @private
  32301. @method columnsForType
  32302. @param {Class} type The model type
  32303. @return {Array} An array of columns of the following format:
  32304. name: {String} name of the column
  32305. desc: {String} Humanized description (what would show in a table column name)
  32306. */
  32307. columnsForType: function(type) {
  32308. return Ember.A();
  32309. },
  32310. /**
  32311. Adds observers to a model type class.
  32312. @private
  32313. @method observeModelType
  32314. @param {Class} type The model type class
  32315. @param {Function} typesUpdated Called when a type is modified.
  32316. @return {Function} The function to call to remove observers
  32317. */
  32318. observeModelType: function(type, typesUpdated) {
  32319. var self = this, records = this.getRecords(type);
  32320. var onChange = function() {
  32321. typesUpdated([self.wrapModelType(type)]);
  32322. };
  32323. var observer = {
  32324. didChange: function() {
  32325. Ember.run.scheduleOnce('actions', this, onChange);
  32326. },
  32327. willChange: Ember.K
  32328. };
  32329. records.addArrayObserver(this, observer);
  32330. var release = function() {
  32331. records.removeArrayObserver(self, observer);
  32332. };
  32333. return release;
  32334. },
  32335. /**
  32336. Wraps a given model type and observes changes to it.
  32337. @private
  32338. @method wrapModelType
  32339. @param {Class} type A model class
  32340. @param {Function} typesUpdated callback to call when the type changes
  32341. @return {Object} contains the wrapped type and the function to remove observers
  32342. Format:
  32343. type: {Object} the wrapped type
  32344. The wrapped type has the following format:
  32345. name: {String} name of the type
  32346. count: {Integer} number of records available
  32347. columns: {Columns} array of columns to describe the record
  32348. object: {Class} the actual Model type class
  32349. release: {Function} The function to remove observers
  32350. */
  32351. wrapModelType: function(type, typesUpdated) {
  32352. var release, records = this.getRecords(type),
  32353. typeToSend, self = this;
  32354. typeToSend = {
  32355. name: type.toString(),
  32356. count: Ember.get(records, 'length'),
  32357. columns: this.columnsForType(type),
  32358. object: type
  32359. };
  32360. return typeToSend;
  32361. },
  32362. /**
  32363. Fetches all models defined in the application.
  32364. @private
  32365. @method getModelTypes
  32366. @return {Array} Array of model types
  32367. */
  32368. // TODO: Use the resolver instead of looping over namespaces.
  32369. getModelTypes: function() {
  32370. var namespaces = Ember.A(Ember.Namespace.NAMESPACES), types = Ember.A(), self = this;
  32371. namespaces.forEach(function(namespace) {
  32372. for (var key in namespace) {
  32373. if (!namespace.hasOwnProperty(key)) { continue; }
  32374. var klass = namespace[key];
  32375. if (self.detect(klass)) {
  32376. types.push(klass);
  32377. }
  32378. }
  32379. });
  32380. return types;
  32381. },
  32382. /**
  32383. Fetches all loaded records for a given type.
  32384. @private
  32385. @method getRecords
  32386. @return {Array} An array of records.
  32387. This array will be observed for changes,
  32388. so it should update when new records are added/removed.
  32389. */
  32390. getRecords: function(type) {
  32391. return Ember.A();
  32392. },
  32393. /**
  32394. Wraps a record and observers changes to it.
  32395. @private
  32396. @method wrapRecord
  32397. @param {Object} record The record instance.
  32398. @return {Object} The wrapped record. Format:
  32399. columnValues: {Array}
  32400. searchKeywords: {Array}
  32401. */
  32402. wrapRecord: function(record) {
  32403. var recordToSend = { object: record }, columnValues = {}, self = this;
  32404. recordToSend.columnValues = this.getRecordColumnValues(record);
  32405. recordToSend.searchKeywords = this.getRecordKeywords(record);
  32406. recordToSend.filterValues = this.getRecordFilterValues(record);
  32407. recordToSend.color = this.getRecordColor(record);
  32408. return recordToSend;
  32409. },
  32410. /**
  32411. Gets the values for each column.
  32412. @private
  32413. @method getRecordColumnValues
  32414. @return {Object} Keys should match column names defined
  32415. by the model type.
  32416. */
  32417. getRecordColumnValues: function(record) {
  32418. return {};
  32419. },
  32420. /**
  32421. Returns keywords to match when searching records.
  32422. @private
  32423. @method getRecordKeywords
  32424. @return {Array} Relevant keywords for search.
  32425. */
  32426. getRecordKeywords: function(record) {
  32427. return Ember.A();
  32428. },
  32429. /**
  32430. Returns the values of filters defined by `getFilters`.
  32431. @private
  32432. @method getRecordFilterValues
  32433. @param {Object} record The record instance
  32434. @return {Object} The filter values
  32435. */
  32436. getRecordFilterValues: function(record) {
  32437. return {};
  32438. },
  32439. /**
  32440. Each record can have a color that represents its state.
  32441. @private
  32442. @method getRecordColor
  32443. @param {Object} record The record instance
  32444. @return {String} The record's color
  32445. Possible options: black, red, blue, green
  32446. */
  32447. getRecordColor: function(record) {
  32448. return null;
  32449. },
  32450. /**
  32451. Observes all relevant properties and re-sends the wrapped record
  32452. when a change occurs.
  32453. @private
  32454. @method observerRecord
  32455. @param {Object} record The record instance
  32456. @param {Function} recordUpdated The callback to call when a record is updated.
  32457. @return {Function} The function to call to remove all observers.
  32458. */
  32459. observeRecord: function(record, recordUpdated) {
  32460. return function(){};
  32461. }
  32462. });
  32463. })();
  32464. (function() {
  32465. /**
  32466. Ember Extension Support
  32467. @module ember
  32468. @submodule ember-extension-support
  32469. @requires ember-application
  32470. */
  32471. })();
  32472. (function() {
  32473. /**
  32474. @module ember
  32475. @submodule ember-testing
  32476. */
  32477. var slice = [].slice,
  32478. helpers = {},
  32479. injectHelpersCallbacks = [];
  32480. /**
  32481. This is a container for an assortment of testing related functionality:
  32482. * Choose your default test adapter (for your framework of choice).
  32483. * Register/Unregister additional test helpers.
  32484. * Setup callbacks to be fired when the test helpers are injected into
  32485. your application.
  32486. @class Test
  32487. @namespace Ember
  32488. */
  32489. Ember.Test = {
  32490. /**
  32491. `registerHelper` is used to register a test helper that will be injected
  32492. when `App.injectTestHelpers` is called.
  32493. The helper method will always be called with the current Application as
  32494. the first parameter.
  32495. For example:
  32496. ```javascript
  32497. Ember.Test.registerHelper('boot', function(app) {
  32498. Ember.run(app, app.advanceReadiness);
  32499. });
  32500. ```
  32501. This helper can later be called without arguments because it will be
  32502. called with `app` as the first parameter.
  32503. ```javascript
  32504. App = Ember.Application.create();
  32505. App.injectTestHelpers();
  32506. boot();
  32507. ```
  32508. @public
  32509. @method registerHelper
  32510. @param {String} name The name of the helper method to add.
  32511. @param {Function} helperMethod
  32512. @param options {Object}
  32513. */
  32514. registerHelper: function(name, helperMethod) {
  32515. helpers[name] = {
  32516. method: helperMethod,
  32517. meta: { wait: false }
  32518. };
  32519. },
  32520. /**
  32521. `registerAsyncHelper` is used to register an async test helper that will be injected
  32522. when `App.injectTestHelpers` is called.
  32523. The helper method will always be called with the current Application as
  32524. the first parameter.
  32525. For example:
  32526. ```javascript
  32527. Ember.Test.registerAsyncHelper('boot', function(app) {
  32528. Ember.run(app, app.advanceReadiness);
  32529. });
  32530. ```
  32531. The advantage of an async helper is that it will not run
  32532. until the last async helper has completed. All async helpers
  32533. after it will wait for it complete before running.
  32534. For example:
  32535. ```javascript
  32536. Ember.Test.registerAsyncHelper('deletePost', function(app, postId) {
  32537. click('.delete-' + postId);
  32538. });
  32539. // ... in your test
  32540. visit('/post/2');
  32541. deletePost(2);
  32542. visit('/post/3');
  32543. deletePost(3);
  32544. ```
  32545. @public
  32546. @method registerAsyncHelper
  32547. @param {String} name The name of the helper method to add.
  32548. @param {Function} helperMethod
  32549. */
  32550. registerAsyncHelper: function(name, helperMethod) {
  32551. helpers[name] = {
  32552. method: helperMethod,
  32553. meta: { wait: true }
  32554. };
  32555. },
  32556. /**
  32557. Remove a previously added helper method.
  32558. Example:
  32559. ```javascript
  32560. Ember.Test.unregisterHelper('wait');
  32561. ```
  32562. @public
  32563. @method unregisterHelper
  32564. @param {String} name The helper to remove.
  32565. */
  32566. unregisterHelper: function(name) {
  32567. delete helpers[name];
  32568. delete Ember.Test.Promise.prototype[name];
  32569. },
  32570. /**
  32571. Used to register callbacks to be fired whenever `App.injectTestHelpers`
  32572. is called.
  32573. The callback will receive the current application as an argument.
  32574. Example:
  32575. ```javascript
  32576. Ember.Test.onInjectHelpers(function() {
  32577. Ember.$(document).ajaxStart(function() {
  32578. Test.pendingAjaxRequests++;
  32579. });
  32580. Ember.$(document).ajaxStop(function() {
  32581. Test.pendingAjaxRequests--;
  32582. });
  32583. });
  32584. ```
  32585. @public
  32586. @method onInjectHelpers
  32587. @param {Function} callback The function to be called.
  32588. */
  32589. onInjectHelpers: function(callback) {
  32590. injectHelpersCallbacks.push(callback);
  32591. },
  32592. /**
  32593. This returns a thenable tailored for testing. It catches failed
  32594. `onSuccess` callbacks and invokes the `Ember.Test.adapter.exception`
  32595. callback in the last chained then.
  32596. This method should be returned by async helpers such as `wait`.
  32597. @public
  32598. @method promise
  32599. @param {Function} resolver The function used to resolve the promise.
  32600. */
  32601. promise: function(resolver) {
  32602. return new Ember.Test.Promise(resolver);
  32603. },
  32604. /**
  32605. Used to allow ember-testing to communicate with a specific testing
  32606. framework.
  32607. You can manually set it before calling `App.setupForTesting()`.
  32608. Example:
  32609. ```javascript
  32610. Ember.Test.adapter = MyCustomAdapter.create()
  32611. ```
  32612. If you do not set it, ember-testing will default to `Ember.Test.QUnitAdapter`.
  32613. @public
  32614. @property adapter
  32615. @type {Class} The adapter to be used.
  32616. @default Ember.Test.QUnitAdapter
  32617. */
  32618. adapter: null,
  32619. /**
  32620. Replacement for `Ember.RSVP.resolve`
  32621. The only difference is this uses
  32622. and instance of `Ember.Test.Promise`
  32623. @public
  32624. @method resolve
  32625. @param {Mixed} The value to resolve
  32626. */
  32627. resolve: function(val) {
  32628. return Ember.Test.promise(function(resolve) {
  32629. return resolve(val);
  32630. });
  32631. },
  32632. /**
  32633. This allows ember-testing to play nicely with other asynchronous
  32634. events, such as an application that is waiting for a CSS3
  32635. transition or an IndexDB transaction.
  32636. For example:
  32637. ```javascript
  32638. Ember.Test.registerWaiter(function() {
  32639. return myPendingTransactions() == 0;
  32640. });
  32641. ```
  32642. The `context` argument allows you to optionally specify the `this`
  32643. with which your callback will be invoked.
  32644. For example:
  32645. ```javascript
  32646. Ember.Test.registerWaiter(MyDB, MyDB.hasPendingTransactions);
  32647. ```
  32648. @public
  32649. @method registerWaiter
  32650. @param {Object} context (optional)
  32651. @param {Function} callback
  32652. */
  32653. registerWaiter: function(context, callback) {
  32654. if (arguments.length === 1) {
  32655. callback = context;
  32656. context = null;
  32657. }
  32658. if (!this.waiters) {
  32659. this.waiters = Ember.A();
  32660. }
  32661. this.waiters.push([context, callback]);
  32662. },
  32663. /**
  32664. `unregisterWaiter` is used to unregister a callback that was
  32665. registered with `registerWaiter`.
  32666. @public
  32667. @method unregisterWaiter
  32668. @param {Object} context (optional)
  32669. @param {Function} callback
  32670. */
  32671. unregisterWaiter: function(context, callback) {
  32672. var pair;
  32673. if (!this.waiters) { return; }
  32674. if (arguments.length === 1) {
  32675. callback = context;
  32676. context = null;
  32677. }
  32678. pair = [context, callback];
  32679. this.waiters = Ember.A(this.waiters.filter(function(elt) {
  32680. return Ember.compare(elt, pair)!==0;
  32681. }));
  32682. }
  32683. };
  32684. function helper(app, name) {
  32685. var fn = helpers[name].method,
  32686. meta = helpers[name].meta;
  32687. return function() {
  32688. var args = slice.call(arguments),
  32689. lastPromise = Ember.Test.lastPromise;
  32690. args.unshift(app);
  32691. // some helpers are not async and
  32692. // need to return a value immediately.
  32693. // example: `find`
  32694. if (!meta.wait) {
  32695. return fn.apply(app, args);
  32696. }
  32697. if (!lastPromise) {
  32698. // It's the first async helper in current context
  32699. lastPromise = fn.apply(app, args);
  32700. } else {
  32701. // wait for last helper's promise to resolve
  32702. // and then execute
  32703. run(function() {
  32704. lastPromise = Ember.Test.resolve(lastPromise).then(function() {
  32705. return fn.apply(app, args);
  32706. });
  32707. });
  32708. }
  32709. return lastPromise;
  32710. };
  32711. }
  32712. function run(fn) {
  32713. if (!Ember.run.currentRunLoop) {
  32714. Ember.run(fn);
  32715. } else {
  32716. fn();
  32717. }
  32718. }
  32719. Ember.Application.reopen({
  32720. /**
  32721. This property contains the testing helpers for the current application. These
  32722. are created once you call `injectTestHelpers` on your `Ember.Application`
  32723. instance. The included helpers are also available on the `window` object by
  32724. default, but can be used from this object on the individual application also.
  32725. @property testHelpers
  32726. @type {Object}
  32727. @default {}
  32728. */
  32729. testHelpers: {},
  32730. /**
  32731. This property will contain the original methods that were registered
  32732. on the `helperContainer` before `injectTestHelpers` is called.
  32733. When `removeTestHelpers` is called, these methods are restored to the
  32734. `helperContainer`.
  32735. @property originalMethods
  32736. @type {Object}
  32737. @default {}
  32738. @private
  32739. */
  32740. originalMethods: {},
  32741. /**
  32742. This property indicates whether or not this application is currently in
  32743. testing mode. This is set when `setupForTesting` is called on the current
  32744. application.
  32745. @property testing
  32746. @type {Boolean}
  32747. @default false
  32748. */
  32749. testing: false,
  32750. /**
  32751. This hook defers the readiness of the application, so that you can start
  32752. the app when your tests are ready to run. It also sets the router's
  32753. location to 'none', so that the window's location will not be modified
  32754. (preventing both accidental leaking of state between tests and interference
  32755. with your testing framework).
  32756. Example:
  32757. ```
  32758. App.setupForTesting();
  32759. ```
  32760. @method setupForTesting
  32761. */
  32762. setupForTesting: function() {
  32763. Ember.testing = true;
  32764. this.testing = true;
  32765. this.Router.reopen({
  32766. location: 'none'
  32767. });
  32768. // if adapter is not manually set default to QUnit
  32769. if (!Ember.Test.adapter) {
  32770. Ember.Test.adapter = Ember.Test.QUnitAdapter.create();
  32771. }
  32772. },
  32773. /**
  32774. This will be used as the container to inject the test helpers into. By
  32775. default the helpers are injected into `window`.
  32776. @property helperContainer
  32777. @type {Object} The object to be used for test helpers.
  32778. @default window
  32779. */
  32780. helperContainer: window,
  32781. /**
  32782. This injects the test helpers into the `helperContainer` object. If an object is provided
  32783. it will be used as the helperContainer. If `helperContainer` is not set it will default
  32784. to `window`. If a function of the same name has already been defined it will be cached
  32785. (so that it can be reset if the helper is removed with `unregisterHelper` or
  32786. `removeTestHelpers`).
  32787. Any callbacks registered with `onInjectHelpers` will be called once the
  32788. helpers have been injected.
  32789. Example:
  32790. ```
  32791. App.injectTestHelpers();
  32792. ```
  32793. @method injectTestHelpers
  32794. */
  32795. injectTestHelpers: function(helperContainer) {
  32796. if (helperContainer) { this.helperContainer = helperContainer; }
  32797. this.testHelpers = {};
  32798. for (var name in helpers) {
  32799. this.originalMethods[name] = this.helperContainer[name];
  32800. this.testHelpers[name] = this.helperContainer[name] = helper(this, name);
  32801. protoWrap(Ember.Test.Promise.prototype, name, helper(this, name), helpers[name].meta.wait);
  32802. }
  32803. for(var i = 0, l = injectHelpersCallbacks.length; i < l; i++) {
  32804. injectHelpersCallbacks[i](this);
  32805. }
  32806. },
  32807. /**
  32808. This removes all helpers that have been registered, and resets and functions
  32809. that were overridden by the helpers.
  32810. Example:
  32811. ```javascript
  32812. App.removeTestHelpers();
  32813. ```
  32814. @public
  32815. @method removeTestHelpers
  32816. */
  32817. removeTestHelpers: function() {
  32818. for (var name in helpers) {
  32819. this.helperContainer[name] = this.originalMethods[name];
  32820. delete this.testHelpers[name];
  32821. delete this.originalMethods[name];
  32822. }
  32823. }
  32824. });
  32825. // This method is no longer needed
  32826. // But still here for backwards compatibility
  32827. // of helper chaining
  32828. function protoWrap(proto, name, callback, isAsync) {
  32829. proto[name] = function() {
  32830. var args = arguments;
  32831. if (isAsync) {
  32832. return callback.apply(this, args);
  32833. } else {
  32834. return this.then(function() {
  32835. return callback.apply(this, args);
  32836. });
  32837. }
  32838. };
  32839. }
  32840. Ember.Test.Promise = function() {
  32841. Ember.RSVP.Promise.apply(this, arguments);
  32842. Ember.Test.lastPromise = this;
  32843. };
  32844. Ember.Test.Promise.prototype = Ember.create(Ember.RSVP.Promise.prototype);
  32845. Ember.Test.Promise.prototype.constructor = Ember.Test.Promise;
  32846. // Patch `then` to isolate async methods
  32847. // specifically `Ember.Test.lastPromise`
  32848. var originalThen = Ember.RSVP.Promise.prototype.then;
  32849. Ember.Test.Promise.prototype.then = function(onSuccess, onFailure) {
  32850. return originalThen.call(this, function(val) {
  32851. return isolate(onSuccess, val);
  32852. }, onFailure);
  32853. };
  32854. // This method isolates nested async methods
  32855. // so that they don't conflict with other last promises.
  32856. //
  32857. // 1. Set `Ember.Test.lastPromise` to null
  32858. // 2. Invoke method
  32859. // 3. Return the last promise created during method
  32860. // 4. Restore `Ember.Test.lastPromise` to original value
  32861. function isolate(fn, val) {
  32862. var value, lastPromise;
  32863. // Reset lastPromise for nested helpers
  32864. Ember.Test.lastPromise = null;
  32865. value = fn(val);
  32866. lastPromise = Ember.Test.lastPromise;
  32867. // If the method returned a promise
  32868. // return that promise. If not,
  32869. // return the last async helper's promise
  32870. if ((value && (value instanceof Ember.Test.Promise)) || !lastPromise) {
  32871. return value;
  32872. } else {
  32873. run(function() {
  32874. lastPromise = Ember.Test.resolve(lastPromise).then(function() {
  32875. return value;
  32876. });
  32877. });
  32878. return lastPromise;
  32879. }
  32880. }
  32881. })();
  32882. (function() {
  32883. Ember.onLoad('Ember.Application', function(Application) {
  32884. Application.initializer({
  32885. name: 'deferReadiness in `testing` mode',
  32886. initialize: function(container, application){
  32887. if (application.testing) {
  32888. application.deferReadiness();
  32889. }
  32890. }
  32891. });
  32892. });
  32893. })();
  32894. (function() {
  32895. /**
  32896. @module ember
  32897. @submodule ember-testing
  32898. */
  32899. var $ = Ember.$;
  32900. /**
  32901. This method creates a checkbox and triggers the click event to fire the
  32902. passed in handler. It is used to correct for a bug in older versions
  32903. of jQuery (e.g 1.8.3).
  32904. @private
  32905. @method testCheckboxClick
  32906. */
  32907. function testCheckboxClick(handler) {
  32908. $('<input type="checkbox">')
  32909. .css({ position: 'absolute', left: '-1000px', top: '-1000px' })
  32910. .appendTo('body')
  32911. .on('click', handler)
  32912. .trigger('click')
  32913. .remove();
  32914. }
  32915. $(function() {
  32916. /*
  32917. Determine whether a checkbox checked using jQuery's "click" method will have
  32918. the correct value for its checked property.
  32919. If we determine that the current jQuery version exhibits this behavior,
  32920. patch it to work correctly as in the commit for the actual fix:
  32921. https://github.com/jquery/jquery/commit/1fb2f92.
  32922. */
  32923. testCheckboxClick(function() {
  32924. if (!this.checked && !$.event.special.click) {
  32925. $.event.special.click = {
  32926. // For checkbox, fire native event so checked state will be right
  32927. trigger: function() {
  32928. if ($.nodeName( this, "input" ) && this.type === "checkbox" && this.click) {
  32929. this.click();
  32930. return false;
  32931. }
  32932. }
  32933. };
  32934. }
  32935. });
  32936. // Try again to verify that the patch took effect or blow up.
  32937. testCheckboxClick(function() {
  32938. Ember.warn("clicked checkboxes should be checked! the jQuery patch didn't work", this.checked);
  32939. });
  32940. });
  32941. })();
  32942. (function() {
  32943. /**
  32944. @module ember
  32945. @submodule ember-testing
  32946. */
  32947. var Test = Ember.Test;
  32948. /**
  32949. The primary purpose of this class is to create hooks that can be implemented
  32950. by an adapter for various test frameworks.
  32951. @class Adapter
  32952. @namespace Ember.Test
  32953. */
  32954. Test.Adapter = Ember.Object.extend({
  32955. /**
  32956. This callback will be called whenever an async operation is about to start.
  32957. Override this to call your framework's methods that handle async
  32958. operations.
  32959. @public
  32960. @method asyncStart
  32961. */
  32962. asyncStart: Ember.K,
  32963. /**
  32964. This callback will be called whenever an async operation has completed.
  32965. @public
  32966. @method asyncEnd
  32967. */
  32968. asyncEnd: Ember.K,
  32969. /**
  32970. Override this method with your testing framework's false assertion.
  32971. This function is called whenever an exception occurs causing the testing
  32972. promise to fail.
  32973. QUnit example:
  32974. ```javascript
  32975. exception: function(error) {
  32976. ok(false, error);
  32977. };
  32978. ```
  32979. @public
  32980. @method exception
  32981. @param {String} error The exception to be raised.
  32982. */
  32983. exception: function(error) {
  32984. throw error;
  32985. }
  32986. });
  32987. /**
  32988. This class implements the methods defined by Ember.Test.Adapter for the
  32989. QUnit testing framework.
  32990. @class QUnitAdapter
  32991. @namespace Ember.Test
  32992. @extends Ember.Test.Adapter
  32993. */
  32994. Test.QUnitAdapter = Test.Adapter.extend({
  32995. asyncStart: function() {
  32996. stop();
  32997. },
  32998. asyncEnd: function() {
  32999. start();
  33000. },
  33001. exception: function(error) {
  33002. ok(false, Ember.inspect(error));
  33003. }
  33004. });
  33005. })();
  33006. (function() {
  33007. /**
  33008. * @module ember
  33009. * @submodule ember-testing
  33010. */
  33011. var get = Ember.get,
  33012. Test = Ember.Test,
  33013. helper = Test.registerHelper,
  33014. asyncHelper = Test.registerAsyncHelper,
  33015. countAsync = 0;
  33016. Test.pendingAjaxRequests = 0;
  33017. Test.onInjectHelpers(function() {
  33018. Ember.$(document).ajaxStart(function() {
  33019. Test.pendingAjaxRequests++;
  33020. });
  33021. Ember.$(document).ajaxStop(function() {
  33022. Ember.assert("An ajaxStop event which would cause the number of pending AJAX " +
  33023. "requests to be negative has been triggered. This is most likely " +
  33024. "caused by AJAX events that were started before calling " +
  33025. "`injectTestHelpers()`.", Test.pendingAjaxRequests !== 0);
  33026. Test.pendingAjaxRequests--;
  33027. });
  33028. });
  33029. function currentRouteName(app){
  33030. var appController = app.__container__.lookup('controller:application');
  33031. return get(appController, 'currentRouteName');
  33032. }
  33033. function currentPath(app){
  33034. var appController = app.__container__.lookup('controller:application');
  33035. return get(appController, 'currentPath');
  33036. }
  33037. function currentURL(app){
  33038. var router = app.__container__.lookup('router:main');
  33039. return get(router, 'location').getURL();
  33040. }
  33041. function visit(app, url) {
  33042. var router = app.__container__.lookup('router:main');
  33043. router.location.setURL(url);
  33044. if (app._readinessDeferrals > 0) {
  33045. router['initialURL'] = url;
  33046. Ember.run(app, 'advanceReadiness');
  33047. delete router['initialURL'];
  33048. } else {
  33049. Ember.run(app, app.handleURL, url);
  33050. }
  33051. return wait(app);
  33052. }
  33053. function click(app, selector, context) {
  33054. var $el = findWithAssert(app, selector, context);
  33055. Ember.run($el, 'mousedown');
  33056. if ($el.is(':input')) {
  33057. var type = $el.prop('type');
  33058. if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') {
  33059. Ember.run($el, function(){
  33060. // Firefox does not trigger the `focusin` event if the window
  33061. // does not have focus. If the document doesn't have focus just
  33062. // use trigger('focusin') instead.
  33063. if (!document.hasFocus || document.hasFocus()) {
  33064. this.focus();
  33065. } else {
  33066. this.trigger('focusin');
  33067. }
  33068. });
  33069. }
  33070. }
  33071. Ember.run($el, 'mouseup');
  33072. Ember.run($el, 'click');
  33073. return wait(app);
  33074. }
  33075. function triggerEvent(app, selector, context, event){
  33076. if (typeof method === 'undefined') {
  33077. event = context;
  33078. context = null;
  33079. }
  33080. var $el = findWithAssert(app, selector, context);
  33081. Ember.run($el, 'trigger', event);
  33082. return wait(app);
  33083. }
  33084. function keyEvent(app, selector, context, type, keyCode) {
  33085. var $el;
  33086. if (typeof keyCode === 'undefined') {
  33087. keyCode = type;
  33088. type = context;
  33089. context = null;
  33090. }
  33091. $el = findWithAssert(app, selector, context);
  33092. var event = Ember.$.Event(type, { keyCode: keyCode });
  33093. Ember.run($el, 'trigger', event);
  33094. return wait(app);
  33095. }
  33096. function fillIn(app, selector, context, text) {
  33097. var $el;
  33098. if (typeof text === 'undefined') {
  33099. text = context;
  33100. context = null;
  33101. }
  33102. $el = findWithAssert(app, selector, context);
  33103. Ember.run(function() {
  33104. $el.val(text).change();
  33105. });
  33106. return wait(app);
  33107. }
  33108. function findWithAssert(app, selector, context) {
  33109. var $el = find(app, selector, context);
  33110. if ($el.length === 0) {
  33111. throw new Ember.Error("Element " + selector + " not found.");
  33112. }
  33113. return $el;
  33114. }
  33115. function find(app, selector, context) {
  33116. var $el;
  33117. context = context || get(app, 'rootElement');
  33118. $el = app.$(selector, context);
  33119. return $el;
  33120. }
  33121. function andThen(app, callback) {
  33122. return wait(app, callback(app));
  33123. }
  33124. function wait(app, value) {
  33125. return Test.promise(function(resolve) {
  33126. // If this is the first async promise, kick off the async test
  33127. if (++countAsync === 1) {
  33128. Test.adapter.asyncStart();
  33129. }
  33130. // Every 10ms, poll for the async thing to have finished
  33131. var watcher = setInterval(function() {
  33132. // 1. If the router is loading, keep polling
  33133. var routerIsLoading = !!app.__container__.lookup('router:main').router.activeTransition;
  33134. if (routerIsLoading) { return; }
  33135. // 2. If there are pending Ajax requests, keep polling
  33136. if (Test.pendingAjaxRequests) { return; }
  33137. // 3. If there are scheduled timers or we are inside of a run loop, keep polling
  33138. if (Ember.run.hasScheduledTimers() || Ember.run.currentRunLoop) { return; }
  33139. if (Test.waiters && Test.waiters.any(function(waiter) {
  33140. var context = waiter[0];
  33141. var callback = waiter[1];
  33142. return !callback.call(context);
  33143. })) { return; }
  33144. // Stop polling
  33145. clearInterval(watcher);
  33146. // If this is the last async promise, end the async test
  33147. if (--countAsync === 0) {
  33148. Test.adapter.asyncEnd();
  33149. }
  33150. // Synchronously resolve the promise
  33151. Ember.run(null, resolve, value);
  33152. }, 10);
  33153. });
  33154. }
  33155. /**
  33156. * Loads a route, sets up any controllers, and renders any templates associated
  33157. * with the route as though a real user had triggered the route change while
  33158. * using your app.
  33159. *
  33160. * Example:
  33161. *
  33162. * ```javascript
  33163. * visit('posts/index').then(function() {
  33164. * // assert something
  33165. * });
  33166. * ```
  33167. *
  33168. * @method visit
  33169. * @param {String} url the name of the route
  33170. * @return {RSVP.Promise}
  33171. */
  33172. asyncHelper('visit', visit);
  33173. /**
  33174. * Clicks an element and triggers any actions triggered by the element's `click`
  33175. * event.
  33176. *
  33177. * Example:
  33178. *
  33179. * ```javascript
  33180. * click('.some-jQuery-selector').then(function() {
  33181. * // assert something
  33182. * });
  33183. * ```
  33184. *
  33185. * @method click
  33186. * @param {String} selector jQuery selector for finding element on the DOM
  33187. * @return {RSVP.Promise}
  33188. */
  33189. asyncHelper('click', click);
  33190. /**
  33191. * Simulates a key event, e.g. `keypress`, `keydown`, `keyup` with the desired keyCode
  33192. *
  33193. * Example:
  33194. *
  33195. * ```javascript
  33196. * keyEvent('.some-jQuery-selector', 'keypress', 13).then(function() {
  33197. * // assert something
  33198. * });
  33199. * ```
  33200. *
  33201. * @method keyEvent
  33202. * @param {String} selector jQuery selector for finding element on the DOM
  33203. * @param {String} the type of key event, e.g. `keypress`, `keydown`, `keyup`
  33204. * @param {Number} the keyCode of the simulated key event
  33205. * @return {RSVP.Promise}
  33206. */
  33207. asyncHelper('keyEvent', keyEvent);
  33208. /**
  33209. * Fills in an input element with some text.
  33210. *
  33211. * Example:
  33212. *
  33213. * ```javascript
  33214. * fillIn('#email', 'you@example.com').then(function() {
  33215. * // assert something
  33216. * });
  33217. * ```
  33218. *
  33219. * @method fillIn
  33220. * @param {String} selector jQuery selector finding an input element on the DOM
  33221. * to fill text with
  33222. * @param {String} text text to place inside the input element
  33223. * @return {RSVP.Promise}
  33224. */
  33225. asyncHelper('fillIn', fillIn);
  33226. /**
  33227. * Finds an element in the context of the app's container element. A simple alias
  33228. * for `app.$(selector)`.
  33229. *
  33230. * Example:
  33231. *
  33232. * ```javascript
  33233. * var $el = find('.my-selector');
  33234. * ```
  33235. *
  33236. * @method find
  33237. * @param {String} selector jQuery string selector for element lookup
  33238. * @return {Object} jQuery object representing the results of the query
  33239. */
  33240. helper('find', find);
  33241. /**
  33242. * Like `find`, but throws an error if the element selector returns no results.
  33243. *
  33244. * Example:
  33245. *
  33246. * ```javascript
  33247. * var $el = findWithAssert('.doesnt-exist'); // throws error
  33248. * ```
  33249. *
  33250. * @method findWithAssert
  33251. * @param {String} selector jQuery selector string for finding an element within
  33252. * the DOM
  33253. * @return {Object} jQuery object representing the results of the query
  33254. * @throws {Error} throws error if jQuery object returned has a length of 0
  33255. */
  33256. helper('findWithAssert', findWithAssert);
  33257. /**
  33258. Causes the run loop to process any pending events. This is used to ensure that
  33259. any async operations from other helpers (or your assertions) have been processed.
  33260. This is most often used as the return value for the helper functions (see 'click',
  33261. 'fillIn','visit',etc).
  33262. Example:
  33263. ```javascript
  33264. Ember.Test.registerAsyncHelper('loginUser', function(app, username, password) {
  33265. visit('secured/path/here')
  33266. .fillIn('#username', username)
  33267. .fillIn('#password', username)
  33268. .click('.submit')
  33269. return wait();
  33270. });
  33271. @method wait
  33272. @param {Object} value The value to be returned.
  33273. @return {RSVP.Promise}
  33274. */
  33275. asyncHelper('wait', wait);
  33276. asyncHelper('andThen', andThen);
  33277. })();
  33278. (function() {
  33279. /**
  33280. Ember Testing
  33281. @module ember
  33282. @submodule ember-testing
  33283. @requires ember-application
  33284. */
  33285. })();
  33286. (function() {
  33287. /**
  33288. Ember
  33289. @module ember
  33290. */
  33291. function throwWithMessage(msg) {
  33292. return function() {
  33293. throw new Ember.Error(msg);
  33294. };
  33295. }
  33296. function generateRemovedClass(className) {
  33297. var msg = " has been moved into a plugin: https://github.com/emberjs/ember-states";
  33298. return {
  33299. extend: throwWithMessage(className + msg),
  33300. create: throwWithMessage(className + msg)
  33301. };
  33302. }
  33303. Ember.StateManager = generateRemovedClass("Ember.StateManager");
  33304. /**
  33305. This was exported to ember-states plugin for v 1.0.0 release. See: https://github.com/emberjs/ember-states
  33306. @class StateManager
  33307. @namespace Ember
  33308. */
  33309. Ember.State = generateRemovedClass("Ember.State");
  33310. /**
  33311. This was exported to ember-states plugin for v 1.0.0 release. See: https://github.com/emberjs/ember-states
  33312. @class State
  33313. @namespace Ember
  33314. */
  33315. })();
  33316. })();